From 7318b3a4178d03146795a1f77bc68820ca7f997b Mon Sep 17 00:00:00 2001 From: Igor Alexandrov Date: Fri, 12 Dec 2025 17:37:01 -0500 Subject: [PATCH 01/17] Initial PostgreSQL guide structure --- content/guides/postgresql/_index.md | 19 +++++++++++++++++++ ...vanced-configuration-and-initialization.md | 5 +++++ .../postgresql/companions-for-postgresql.md | 5 +++++ .../immediate-setup-and-data-persistence.md | 5 +++++ .../postgresql/networking-and-connectivity.md | 5 +++++ 5 files changed, 39 insertions(+) create mode 100644 content/guides/postgresql/_index.md create mode 100644 content/guides/postgresql/advanced-configuration-and-initialization.md create mode 100644 content/guides/postgresql/companions-for-postgresql.md create mode 100644 content/guides/postgresql/immediate-setup-and-data-persistence.md create mode 100644 content/guides/postgresql/networking-and-connectivity.md diff --git a/content/guides/postgresql/_index.md b/content/guides/postgresql/_index.md new file mode 100644 index 000000000000..aad5ca67fa68 --- /dev/null +++ b/content/guides/postgresql/_index.md @@ -0,0 +1,19 @@ +--- +title: PostgreSQL specific guide +linkTitle: PostgreSQL +description: Containerize PostgreSQL databases using Docker +keywords: Docker, getting started, postgresql, languag +summary: | + This guide explains how to containerize PostgreSQL databases using + Docker. +toc_min: 1 +toc_max: 2 +tags: [databases] +params: + time: 20 minutes +--- + +- Immediate Setup & Data Persistence +- Advanced Configuration and Initialization +- Networking and Connectivity +- Companions for PostfgreSQL diff --git a/content/guides/postgresql/advanced-configuration-and-initialization.md b/content/guides/postgresql/advanced-configuration-and-initialization.md new file mode 100644 index 000000000000..90c6099df581 --- /dev/null +++ b/content/guides/postgresql/advanced-configuration-and-initialization.md @@ -0,0 +1,5 @@ +--- +title: Advanced Configuration and Initialization +linkTitle: Advanced Configuration and Initialization +weight: 20 +--- \ No newline at end of file diff --git a/content/guides/postgresql/companions-for-postgresql.md b/content/guides/postgresql/companions-for-postgresql.md new file mode 100644 index 000000000000..39a16814b317 --- /dev/null +++ b/content/guides/postgresql/companions-for-postgresql.md @@ -0,0 +1,5 @@ +--- +title: Companions for PostgreSQL +linkTitle: Companions for PostgreSQL +weight: 40 +--- \ No newline at end of file diff --git a/content/guides/postgresql/immediate-setup-and-data-persistence.md b/content/guides/postgresql/immediate-setup-and-data-persistence.md new file mode 100644 index 000000000000..3d4e5e4f9e97 --- /dev/null +++ b/content/guides/postgresql/immediate-setup-and-data-persistence.md @@ -0,0 +1,5 @@ +--- +title: Immediate Setup & Data Persistence +linkTitle: Immediate Setup & Data Persistence +weight: 10 +--- \ No newline at end of file diff --git a/content/guides/postgresql/networking-and-connectivity.md b/content/guides/postgresql/networking-and-connectivity.md new file mode 100644 index 000000000000..f3ef9a88224f --- /dev/null +++ b/content/guides/postgresql/networking-and-connectivity.md @@ -0,0 +1,5 @@ +--- +title: Networking and Connectivity +linkTitle: Networking and Connectivity +weight: 30 +--- \ No newline at end of file From 0a9ffb0193457f206630d3cd5a7ff718116394ca Mon Sep 17 00:00:00 2001 From: bs Date: Wed, 31 Dec 2025 11:47:51 +0300 Subject: [PATCH 02/17] dhi: postgresql, part 2 and 4 , final drafts --- ...vanced-configuration-and-initialization.md | 202 +++++++++++++++- .../postgresql/companions-for-postgresql.md | 219 +++++++++++++++++- 2 files changed, 419 insertions(+), 2 deletions(-) diff --git a/content/guides/postgresql/advanced-configuration-and-initialization.md b/content/guides/postgresql/advanced-configuration-and-initialization.md index 90c6099df581..4ff4c315b932 100644 --- a/content/guides/postgresql/advanced-configuration-and-initialization.md +++ b/content/guides/postgresql/advanced-configuration-and-initialization.md @@ -2,4 +2,204 @@ title: Advanced Configuration and Initialization linkTitle: Advanced Configuration and Initialization weight: 20 ---- \ No newline at end of file +--- + +# PostgreSQL: Advanced Configuration and Initialization + +This guide covers advanced configuration techniques for running PostgreSQL in Docker containers, including automated database initialization, performance tuning, and timezone configuration. + +## Overview + +While PostgreSQL containers can be started quickly with default settings, production environments require customized configurations. This guide explains how to: + +- Automate database, schema, and user creation during container startup +- Tune PostgreSQL performance parameters for containerized workloads +- Configure timezone and locale settings + +## Initialization scripts + +The official PostgreSQL Docker image supports running initialization scripts automatically when the container starts for the first time. Any files placed in the `/docker-entrypoint-initdb.d/` directory are executed in alphabetical order. + +### How initialization works + +When the container starts, it checks whether the data directory (`/var/lib/postgresql/data`) is empty. If the directory already contains data, PostgreSQL starts immediately without running any initialization. If the directory is empty, the container runs `initdb` to create a new database cluster, then executes all scripts in `/docker-entrypoint-initdb.d/` in alphabetical order before starting PostgreSQL. + +### Supported file formats + +| Format | Description | +|--------|-------------| +| `.sql` | SQL commands executed directly | +| `.sql.gz` | Gzip-compressed SQL files | +| `.sh` | Shell scripts executed with bash | + +> **Important:** Initialization scripts only run when the PostgreSQL data directory (`/var/lib/postgresql/data`) is empty. If you mount a volume containing existing data, initialization is skipped. This behavior prevents overwriting existing databases. + +## Mounting initialization scripts + +Use Docker Compose to mount initialization scripts into the container. First, create a project directory: + +```console +$ mkdir -p postgres-project/init-db +$ cd postgres-project +``` + +Create a `compose.yaml` file: + +```yaml +services: + db: + image: postgres:18 + volumes: + - ./init-db:/docker-entrypoint-initdb.d + - postgres_data:/var/lib/postgresql/data + environment: + POSTGRES_PASSWORD: mysecretpassword + +volumes: + postgres_data: +``` + +All scripts in the `./init-db` directory execute when the container starts for the first time. This is great for bootstrapping databases. + +## Initialization script example + +Create a file named `init.sql` in your `init-db` directory: + +```sql +CREATE TABLE users ( + id SERIAL PRIMARY KEY, + email VARCHAR(255) UNIQUE NOT NULL, + name VARCHAR(100) NOT NULL, + created_at TIMESTAMP DEFAULT CURRENT_TIMESTAMP +); +``` + +This script runs automatically when the container starts for the first time, creating your initial database schema. + +> **Note:** Ensure initialization scripts have proper read permissions. If you encounter "Permission denied" errors, run `chmod 644 init-db/*.sql` to make the files readable by the container. + +## Performance tuning + +Default PostgreSQL settings are conservative to work on systems with limited resources. For production workloads, you should tune these parameters based on your container's allocated resources. + +### Method 1: Custom configuration file + +For complete control, mount a custom `postgresql.conf` file. First, extract the default configuration: + +```console +$ docker run -i --rm postgres:18 cat /usr/share/postgresql/postgresql.conf.sample > my-postgres.conf +``` + +Edit `my-postgres.conf` with your desired settings, then mount it in your Compose file: + +```yaml +services: + db: + image: postgres:18 + volumes: + - ./my-postgres.conf:/etc/postgresql/postgresql.conf + - ./init-db:/docker-entrypoint-initdb.d + - postgres_data:/var/lib/postgresql/data + command: postgres -c config_file=/etc/postgresql/postgresql.conf + environment: + POSTGRES_PASSWORD: mysecretpassword + +volumes: + postgres_data: +``` + +## Key configuration parameters + +The following tables list important `postgresql.conf` parameters for containerized PostgreSQL deployments. + +### Connection settings + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `listen_addresses` | IP addresses to listen on | `localhost` | +| `port` | TCP port number | `5432` | +| `max_connections` | Maximum concurrent connections | `100` | + +### Memory settings + +| Parameter | Description | Recommended starting value | +|-----------|-------------|---------------------------| +| `shared_buffers` | Shared memory for caching | 25% of container memory | +| `work_mem` | Memory per query operation | 4MB - 64MB | +| `maintenance_work_mem` | Memory for VACUUM, CREATE INDEX | 64MB - 256MB | +| `effective_cache_size` | Planner's cache size estimate | 50-75% of container memory | + +### I/O settings + +| Parameter | Description | Recommended starting value | +|-----------|-------------|---------------------------| +| `effective_io_concurrency` | Concurrent disk I/O operations | `200` for SSDs, `2` for HDDs | + +### Timeout settings + +| Parameter | Description | Default | +|-----------|-------------|---------| +| `statement_timeout` | Max time for any statement | `0` (disabled) | +| `lock_timeout` | Max time to wait for a lock | `0` (disabled) | +| `deadlock_timeout` | Time before checking for deadlock | `1s` | +| `transaction_timeout` | Max time for a transaction | `0` (disabled) | + +> **Note:** Setting `shared_buffers` too high in a container can exceed kernel shared memory limits. We recommend using no more than 25-30% of the container's memory limit. + +## Timezone and locale configuration + +Proper localization ensures timestamps and sorting behave correctly for your application's users. + +```yaml +services: + db: + image: postgres:18 + volumes: + - /etc/localtime:/etc/localtime:ro + - /etc/timezone:/etc/timezone:ro + environment: + POSTGRES_PASSWORD: mysecretpassword + TZ: America/New_York +``` + +Alternatively, set the timezone using a PostgreSQL parameter: + +```yaml +command: + - postgres + - -c + - timezone=America/New_York +``` + +### Setting the locale + +Specify locale settings during database initialization using the `POSTGRES_INITDB_ARGS` environment variable: + +```yaml +services: + db: + image: postgres:18 + environment: + POSTGRES_PASSWORD: mysecretpassword + POSTGRES_INITDB_ARGS: --encoding=UTF8 --lc-collate=en_US.UTF-8 --lc-ctype=en_US.UTF-8 +``` + +This affects collation (sorting) and character processing behavior. Changing this variable after db creation will have no effect, this only has effect during the first run. + +## Connecting to the database + +You can interact with PostgreSQL running in a container even without psql installed on your host machine. + +### Interactive shell + +Open a psql session inside the container: + +```console +$ docker exec -it postgres-container psql -U postgres +``` + +Connect to a specific database: + +```console +$ docker exec -it postgres-container psql -U postgres -d mydb +``` \ No newline at end of file diff --git a/content/guides/postgresql/companions-for-postgresql.md b/content/guides/postgresql/companions-for-postgresql.md index 39a16814b317..2fd9b4779f8e 100644 --- a/content/guides/postgresql/companions-for-postgresql.md +++ b/content/guides/postgresql/companions-for-postgresql.md @@ -2,4 +2,221 @@ title: Companions for PostgreSQL linkTitle: Companions for PostgreSQL weight: 40 ---- \ No newline at end of file +--- + + +# PostgreSQL Ecosystem Companions: pgAdmin, PgBouncer, and Performance Testing + +Running a standalone PostgreSQL container is often just the beginning. What happens when thousands of connections arrive, or when you need a visual interface to manage your database? + +This is where **companion tools** come into play. These applications extend PostgreSQL with capabilities the core database engine doesn't provide natively: visual administration, connection pooling, and performance benchmarking. This guide covers how to deploy pgAdmin 4, PgBouncer, Pgpool-II, and pgbench in Docker, when to use each tool, and real-world benchmark results demonstrating their performance impact. + +## pgAdmin 4: Visual Management Platform + +pgAdmin 4 is the industry-standard open source management tool for PostgreSQL. When deployed in Docker, it typically runs in **Server Mode**, providing a multi-user web interface to manage one or more database instances. + +While you can accomplish everything from the command line using `psql`, a visual interface significantly simplifies writing complex queries, visualizing table structures, and exploring database objects. + +### Key Considerations + +When running pgAdmin in Docker, keep these points in mind: + +- **Image**: Use the official `dpage/pgadmin4` image +- **Networking**: In a Docker Compose environment, pgAdmin connects to the database using the internal service name (for example, `db:5432`) rather than `localhost` + +### Docker Compose Configuration + +To quickly deploy pgAdmin: + +```yaml +pgadmin: + image: dpage/pgadmin4:8.14 + environment: + PGADMIN_DEFAULT_EMAIL: admin@example.com + PGADMIN_DEFAULT_PASSWORD: secure_password + volumes: + - pgadmin_data:/var/lib/pgadmin + ports: + - "8080:80" +``` + +With this configuration, access the pgAdmin interface at `http://localhost:8080`. Use the email and password specified in the environment variables for initial login. + +> **Important**: In production environments, pass `PGADMIN_DEFAULT_PASSWORD` as an external environment variable or use Docker secrets. Storing passwords in plain text within `docker-compose.yml` poses a security risk. + +Now that you have visual database management in place, the next challenge in production environments is handling connection load. The following section explains how to manage high-volume database traffic. + +## PgBouncer: Lightweight Connection Pooling + +PostgreSQL creates a new process for every client connection, which consumes significant RAM. What happens when you have 1,000 concurrent users? PgBouncer solves exactly this problem. + +PgBouncer is a lightweight proxy that pools connections, allowing thousands of applications to share a small number of actual database backends. Think of it as a traffic controller: everyone wants to pass through simultaneously, but the controller regulates the flow to prevent congestion. + +### Pooling Modes + +PgBouncer offers three distinct pooling modes: + +| Mode | Description | Use Case | +|------|-------------|----------| +| **Session** | Connection assigned for entire session duration | Long-lived connections, session variables | +| **Transaction** | Connection returned after each transaction ends | Web applications, microservices (most common) | +| **Statement** | Connection returned after every SQL statement | Simple queries, no multi-statement transactions | + +### When to Use PgBouncer + +PgBouncer becomes essential when you encounter: + +- "too many connections" errors +- High memory consumption due to connection overhead +- Many short-lived connections (web applications, serverless functions) +- Need to serve thousands of clients with limited database connections + +### Complete Docker Compose Setup + +To run PostgreSQL and PgBouncer together, you need three files: `docker-compose.yml`, `pgbouncer.ini`, and `userlist.txt`. + +First, create the PgBouncer configuration file (`pgbouncer.ini`): + +```ini +[databases] +benchmark = host=postgres port=5432 dbname=benchmark user=postgres + +[pgbouncer] +listen_addr = 0.0.0.0 +listen_port = 6432 +auth_type = trust +auth_file = /etc/pgbouncer/userlist.txt +admin_users = postgres +pool_mode = transaction +max_client_conn = 1000 +default_pool_size = 50 +min_pool_size = 10 +reserve_pool_size = 10 +max_db_connections = 100 +``` + +Next, create the user authentication file (`userlist.txt`): + +``` +"postgres" "postgres" +``` + +Finally, create the Docker Compose file (`docker-compose.yml`): + +```yaml +services: + postgres: + image: postgres:17.7 + container_name: postgres + environment: + POSTGRES_USER: postgres + POSTGRES_PASSWORD: postgres + POSTGRES_DB: benchmark + POSTGRES_HOST_AUTH_METHOD: trust + volumes: + - postgres_data:/var/lib/postgresql/data + ports: + - "5432:5432" + networks: + - pgnet + healthcheck: + test: ["CMD-SHELL", "pg_isready -U postgres"] + interval: 5s + timeout: 5s + retries: 5 + + pgbouncer: + image: percona/percona-pgbouncer:1.25.0 + container_name: pgbouncer + volumes: + - ./pgbouncer.ini:/etc/pgbouncer/pgbouncer.ini + - ./userlist.txt:/etc/pgbouncer/userlist.txt + ports: + - "6432:6432" + networks: + - pgnet + depends_on: + postgres: + condition: service_healthy + +volumes: + postgres_data: + +networks: + pgnet: + driver: bridge +``` + +Key configuration notes: + +- PgBouncer listens on port **6432**, avoiding confusion with the direct PostgreSQL connection on port 5432 +- The `depends_on` directive with `service_healthy` condition ensures PgBouncer starts only after PostgreSQL is ready +- `pool_mode = transaction` is the optimal choice for most web applications +- The Percona PgBouncer image requires mounted configuration files (without the `:ro` flag, as the entrypoint script needs to modify them) +- This example uses `trust` authentication for simplicity. In production, configure proper SCRAM-SHA-256 authentication + +> **Note**: The Percona PgBouncer entrypoint script processes the configuration files on startup. Mount them without the read-only flag to avoid permission errors. + + + + +## pgbench: Performance Benchmarking + +pgbench is a benchmarking utility included with the official PostgreSQL image. It allows you to simulate heavy workloads and verify how your Docker configuration performs under pressure. + +### Initialize Benchmark Tables + +First, create the test tables. The `-s` (scale) parameter determines data size—scale factor 50 creates approximately 5 million rows: + +```bash +docker exec postgres pgbench -i -s 50 -U postgres benchmark +``` + +### Run Stress Tests + +Key parameters: + +- `-c`: Number of simulated clients +- `-j`: Number of threads +- `-T`: Duration in seconds + +Test with direct PostgreSQL connection: + +```bash +docker exec postgres pgbench -h localhost -U postgres -c 50 -j 4 -T 60 benchmark +``` + +Test through PgBouncer: + +```bash +docker exec postgres pgbench -h pgbouncer -p 6432 -U postgres -c 50 -j 4 -T 60 benchmark +``` + +## Understanding Benchmark Results + +Does PgBouncer actually make a difference? Run the benchmarks yourself to find out. Your results will vary based on your hardware, Docker configuration, network setup, and system load. + +### What to Expect + +When you run these benchmarks, you'll observe patterns rather than specific numbers. Think of it like comparing two different routes to work: the "faster" route depends on traffic conditions, time of day, and your vehicle. + +### Key Observations + +When comparing direct connections versus PgBouncer, you'll typically notice: + +**1. Connection overhead differs significantly** + +Direct connections require PostgreSQL to spawn a new process for each client. PgBouncer reuses existing connections. Watch the "initial connection time" metric in your results—PgBouncer often shows dramatically faster connection setup. + +**2. Behavior under pressure reveals the real difference** + +Try increasing the client count (`-c` parameter) gradually: 50, 100, 150, 200. At some point, direct connections will fail with "too many clients already" while PgBouncer continues handling requests. This is PgBouncer's primary value: **it prevents connection exhaustion**. + +**3. Throughput varies by environment** + +On some systems, direct connections show higher transactions per second (TPS) at low concurrency. On others, PgBouncer wins even with few clients. The difference depends on: +- CPU and memory available +- Docker networking overhead +- Disk I/O speed +- Whether connections are being rapidly opened and closed + From 9238c68fb7b99732e6a9fb62ff2cd62da76b4a0d Mon Sep 17 00:00:00 2001 From: Igor Alexandrov Date: Mon, 5 Jan 2026 11:16:16 -0500 Subject: [PATCH 03/17] Added two first sections to the first part of the PostgreSQL guide. --- .../immediate-setup-and-data-persistence.md | 87 ++++++++++++++++++- 1 file changed, 86 insertions(+), 1 deletion(-) diff --git a/content/guides/postgresql/immediate-setup-and-data-persistence.md b/content/guides/postgresql/immediate-setup-and-data-persistence.md index 3d4e5e4f9e97..6e28b74c1aef 100644 --- a/content/guides/postgresql/immediate-setup-and-data-persistence.md +++ b/content/guides/postgresql/immediate-setup-and-data-persistence.md @@ -1,5 +1,90 @@ --- title: Immediate Setup & Data Persistence linkTitle: Immediate Setup & Data Persistence +description: Get PostgreSQL running in Docker in under five minutes. Learn how to configure named volumes and bind mounts to persist your database across container restarts. +keywords: + - PostgreSQL Docker + - Docker Compose PostgreSQL + - container database weight: 10 ---- \ No newline at end of file +--- + +This guide gets you from zero to a running PostgreSQL container in under five minutes, then explains how to keep your data safe across container restarts and removals. + +## Overview + +Running PostgreSQL in Docker requires understanding one critical concept: containers are ephemeral, but your data shouldn't be. This guide covers: + +- Starting PostgreSQL with a single command +- Understanding why containers lose data by default +- Configuring volumes for persistent storage +- Translating your setup to Docker Compose + +## Quick Start (Minimal Viable Container) + +Run PostgreSQL immediately with this single command: + +```console +$ docker run --rm --name postgres-dev -e POSTGRES_PASSWORD=mysecretpassword -p 5432:5432 -d postgres:18 +``` + +### Understanding the flags + +| Flag | Purpose | +|------|---------| +| `--name postgres-dev` | Assigns a memorable name instead of a random string | +| `-e POSTGRES_PASSWORD=...` | Sets the superuser password (required) | +| `-p 5432:5432` | Maps host port 5432 to container port 5432 | +| `-d` | Runs the container in the background (detached mode) | + +Verify the container is running: + +```console +$ docker ps --filter name=postgres-dev +CONTAINER ID IMAGE COMMAND STATUS PORTS NAMES +a1b2c3d4e5f6 postgres:18 "docker-entrypoint.s…" Up 2 seconds 0.0.0.0:5432->5432/tcp postgres-dev +``` + +Connect using psql from inside the container: + +```console +$ docker exec -it postgres-dev psql -U postgres +psql (18.0) +Type "help" for help. + +postgres=# +``` + +You now have a working PostgreSQL instance. But there's a problem—stop this container and your data disappears. + +## The Data Persistence Problem + +Containers use an ephemeral filesystem. When a container is removed, everything inside it, including your database files, is deleted. + +Demonstrate this yourself: + +```console +$ docker exec postgres-dev psql -U postgres -c "CREATE DATABASE testdb;" +CREATE DATABASE + +$ docker exec postgres-dev psql -U postgres -c "\l" | grep testdb + testdb | postgres | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | + +$ docker stop postgres-dev +postgres-dev + +$ docker run --rm --name postgres-dev -e POSTGRES_PASSWORD=mysecretpassword -p 5432:5432 -d postgres:18 + +$ docker exec postgres-dev psql -U postgres -c "\l" | grep testdb +(no output - database is gone) +``` + +Your `testdb` database vanished because the new container started with a fresh filesystem. This is expected behavior—and exactly why volumes exist. + +## Named Volumes (Recommended Approach) + +## Bind Mounts (Alternative) + +## Verifying Persistence + +## Docker Compose Version \ No newline at end of file From 0942ec72fda15b622a217a0e9f4a02ac73b79d80 Mon Sep 17 00:00:00 2001 From: Igor Alexandrov Date: Mon, 5 Jan 2026 13:43:46 -0500 Subject: [PATCH 04/17] Added the Named Volumes section --- .../immediate-setup-and-data-persistence.md | 44 ++++++++++++++++++- 1 file changed, 42 insertions(+), 2 deletions(-) diff --git a/content/guides/postgresql/immediate-setup-and-data-persistence.md b/content/guides/postgresql/immediate-setup-and-data-persistence.md index 6e28b74c1aef..b7a56367ce8e 100644 --- a/content/guides/postgresql/immediate-setup-and-data-persistence.md +++ b/content/guides/postgresql/immediate-setup-and-data-persistence.md @@ -25,7 +25,10 @@ Running PostgreSQL in Docker requires understanding one critical concept: contai Run PostgreSQL immediately with this single command: ```console -$ docker run --rm --name postgres-dev -e POSTGRES_PASSWORD=mysecretpassword -p 5432:5432 -d postgres:18 +$ docker run --rm --name postgres-dev \ + -e POSTGRES_PASSWORD=mysecretpassword \ + -p 5432:5432 \ + -d postgres:18 ``` ### Understanding the flags @@ -81,7 +84,44 @@ $ docker exec postgres-dev psql -U postgres -c "\l" | grep testdb Your `testdb` database vanished because the new container started with a fresh filesystem. This is expected behavior—and exactly why volumes exist. -## Named Volumes (Recommended Approach) +## Named Volumes + +Named volumes are Docker-managed storage locations that persist independently of containers. Docker handles the filesystem location, permissions, and lifecycle. + +Create a container with a named volume: + +```console +$ docker run --rm --name postgres-dev \ + -e POSTGRES_PASSWORD=mysecretpassword \ + -p 5432:5432 \ + -v postgres_data:/var/lib/postgresql \ + -d postgres:18 +``` + +The `-v postgres_data:/var/lib/postgresql` flag mounts a named volume called `postgres_data` to PostgreSQL's data directory. If the volume doesn't exist, Docker creates it automatically. + +> **Note:** PostgreSQL 18+ stores data in a version-specific subdirectory under `/var/lib/postgresql`. Mounting at this level (rather than `/var/lib/postgresql/data`) allows for easier upgrades using `pg_upgrade --link`. + +### Verify persistence works + +```console +$ docker exec postgres-dev psql -U postgres -c "CREATE DATABASE testdb;" +CREATE DATABASE + +$ docker stop postgres-dev +postgres-dev + +$ docker run --rm --name postgres-dev \ + -e POSTGRES_PASSWORD=mysecretpassword \ + -p 5432:5432 \ + -v postgres_data:/var/lib/postgresql \ + -d postgres:18 + +$ docker exec postgres-dev psql -U postgres -c "\l" | grep testdb + testdb | postgres | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | +``` + +The database survived because the volume preserved it. ## Bind Mounts (Alternative) From c92e89e87c6f9d8db6e896d81392ed7f7d62bf91 Mon Sep 17 00:00:00 2001 From: Igor Alexandrov Date: Mon, 5 Jan 2026 14:20:34 -0500 Subject: [PATCH 05/17] Added the "Bind Mounts" section --- .../immediate-setup-and-data-persistence.md | 59 ++++++++++++++++++- 1 file changed, 58 insertions(+), 1 deletion(-) diff --git a/content/guides/postgresql/immediate-setup-and-data-persistence.md b/content/guides/postgresql/immediate-setup-and-data-persistence.md index b7a56367ce8e..033110906191 100644 --- a/content/guides/postgresql/immediate-setup-and-data-persistence.md +++ b/content/guides/postgresql/immediate-setup-and-data-persistence.md @@ -123,8 +123,65 @@ $ docker exec postgres-dev psql -U postgres -c "\l" | grep testdb The database survived because the volume preserved it. +### Managing volumes + +List all volumes: + +```console +$ docker volume ls --filter name=postgres_data +DRIVER VOLUME NAME +local postgres_data +``` + +Inspect a volume to see its details: + +```console +$ docker volume inspect postgres_data +[ + { + "CreatedAt": "2025-01-05T10:30:00Z", + "Driver": "local", + "Labels": null, + "Mountpoint": "/var/lib/docker/volumes/postgres_data/_data", + "Name": "postgres_data", + "Options": null, + "Scope": "local" + } +] +``` + +Remove an unused volume (warning: this deletes all data): + +```console +$ docker volume rm postgres_data +``` + ## Bind Mounts (Alternative) -## Verifying Persistence +Bind mounts map a specific host directory to a container path. Unlike named volumes, you control exactly where data lives on the host filesystem. + +```console +$ mkdir -p ~/postgres-data + +$ docker run --rm --name postgres-dev \ + -e POSTGRES_PASSWORD=mysecretpassword \ + -p 5432:5432 \ + -v ~/postgres-data:/var/lib/postgresql \ + -d postgres:18 +``` + +### When to use bind mounts + +Bind mounts are useful when you need direct filesystem access to the data directory for backup scripts that read files directly, when integrating with host-level monitoring tools, or when specific permission requirements exist. For most development and production scenarios, named volumes are simpler and less error-prone. + +### Common bind mount issues + +Permission errors are the most frequent problem with bind mounts. PostgreSQL runs as user `postgres` (UID 999) inside the container. If your host directory has restrictive permissions, the container fails to start. + +Check logs if the container exits immediately: + +```console +$ docker logs postgres-dev +``` ## Docker Compose Version \ No newline at end of file From 46d38795448076fe4844a16263332788f54cb1c4 Mon Sep 17 00:00:00 2001 From: Igor Alexandrov Date: Mon, 5 Jan 2026 16:55:43 -0500 Subject: [PATCH 06/17] Added the Compose section --- .../immediate-setup-and-data-persistence.md | 60 ++++++++++++++++++- 1 file changed, 59 insertions(+), 1 deletion(-) diff --git a/content/guides/postgresql/immediate-setup-and-data-persistence.md b/content/guides/postgresql/immediate-setup-and-data-persistence.md index 033110906191..833d1c987a1c 100644 --- a/content/guides/postgresql/immediate-setup-and-data-persistence.md +++ b/content/guides/postgresql/immediate-setup-and-data-persistence.md @@ -184,4 +184,62 @@ Check logs if the container exits immediately: $ docker logs postgres-dev ``` -## Docker Compose Version \ No newline at end of file +## Docker Compose configuration + +Docker Compose captures your entire configuration in a file, making setups reproducible and easier to manage as complexity grows. + +Create a `compose.yaml` file: + +```yaml +services: + db: + image: postgres:18 + container_name: postgres-dev + environment: + POSTGRES_PASSWORD: mysecretpassword + ports: + - "5432:5432" + volumes: + - postgres_data:/var/lib/postgresql + +volumes: + postgres_data: +``` + +Start the database: + +```console +$ docker compose up -d +``` + +Stop and remove containers (volume persists): + +```console +$ docker compose down +``` + +Alternatively, you can stop, remove containers, and delete the volume: + +```console +$ docker compose down -v +``` + +This compose file becomes the foundation for adding initialization scripts, performance tuning, and companion services covered in subsequent guides. + +### Environment variables reference + +The official PostgreSQL image supports these environment variables: + +| Variable | Required | Description | +|----------|----------|-------------| +| `POSTGRES_PASSWORD` | Yes | Superuser password | +| `POSTGRES_USER` | No | Superuser name (default: `postgres`) | +| `POSTGRES_DB` | No | Default database name (default: value of `POSTGRES_USER`) | + +## Next steps + +With persistent storage configured, you're ready to customize PostgreSQL further. The next chapter of the guide covers: + +- Automated schema creation with initialization scripts +- Performance tuning for containerized workloads +- Timezone and locale configuration \ No newline at end of file From 7df793de06277be3d2954a930cf85b76f8b4f269 Mon Sep 17 00:00:00 2001 From: Igor Alexandrov Date: Wed, 14 Jan 2026 17:58:08 -0500 Subject: [PATCH 07/17] Updated the first section based on comments from Edith Puclla --- .../immediate-setup-and-data-persistence.md | 16 ++++++++++++++-- 1 file changed, 14 insertions(+), 2 deletions(-) diff --git a/content/guides/postgresql/immediate-setup-and-data-persistence.md b/content/guides/postgresql/immediate-setup-and-data-persistence.md index 833d1c987a1c..1b0251433fa2 100644 --- a/content/guides/postgresql/immediate-setup-and-data-persistence.md +++ b/content/guides/postgresql/immediate-setup-and-data-persistence.md @@ -35,6 +35,7 @@ $ docker run --rm --name postgres-dev \ | Flag | Purpose | |------|---------| +| `--rm` | Automatically removes the container when it stops | | `--name postgres-dev` | Assigns a memorable name instead of a random string | | `-e POSTGRES_PASSWORD=...` | Sets the superuser password (required) | | `-p 5432:5432` | Maps host port 5432 to container port 5432 | @@ -76,7 +77,10 @@ $ docker exec postgres-dev psql -U postgres -c "\l" | grep testdb $ docker stop postgres-dev postgres-dev -$ docker run --rm --name postgres-dev -e POSTGRES_PASSWORD=mysecretpassword -p 5432:5432 -d postgres:18 +$ docker run --rm --name postgres-dev \ + -e POSTGRES_PASSWORD=mysecretpassword \ + -p 5432:5432 \ + -d postgres:18 $ docker exec postgres-dev psql -U postgres -c "\l" | grep testdb (no output - database is gone) @@ -104,6 +108,8 @@ The `-v postgres_data:/var/lib/postgresql` flag mounts a named volume called `po ### Verify persistence works +To verify data persistence, repeat the previous test, but this time with the named volume attached in place. + ```console $ docker exec postgres-dev psql -U postgres -c "CREATE DATABASE testdb;" CREATE DATABASE @@ -121,7 +127,7 @@ $ docker exec postgres-dev psql -U postgres -c "\l" | grep testdb testdb | postgres | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | ``` -The database survived because the volume preserved it. +If you see "testdb" in the output, persistence works: The database survived because the volume preserved the data directory. ### Managing volumes @@ -160,9 +166,15 @@ $ docker volume rm postgres_data Bind mounts map a specific host directory to a container path. Unlike named volumes, you control exactly where data lives on the host filesystem. +Create a directory on your host machine to store Postgres data. + ```console $ mkdir -p ~/postgres-data +``` +Run Postgres using a bind mount. + +```console $ docker run --rm --name postgres-dev \ -e POSTGRES_PASSWORD=mysecretpassword \ -p 5432:5432 \ From 7ca271699024aea49cb26b2ee45c6164a6223df6 Mon Sep 17 00:00:00 2001 From: bs Date: Thu, 22 Jan 2026 12:33:33 +0300 Subject: [PATCH 08/17] Update PostgreSQL Modules 2 and 4 with feedback fixes --- ...vanced-configuration-and-initialization.md | 41 +++++++++++++------ 1 file changed, 29 insertions(+), 12 deletions(-) diff --git a/content/guides/postgresql/advanced-configuration-and-initialization.md b/content/guides/postgresql/advanced-configuration-and-initialization.md index 4ff4c315b932..ae9cdd8d01ab 100644 --- a/content/guides/postgresql/advanced-configuration-and-initialization.md +++ b/content/guides/postgresql/advanced-configuration-and-initialization.md @@ -2,11 +2,15 @@ title: Advanced Configuration and Initialization linkTitle: Advanced Configuration and Initialization weight: 20 +description: Configure PostgreSQL initialization scripts, tune performance parameters, and set timezone and locale settings for containerized deployments. +keywords: + - PostgreSQL Docker + - Docker Compose PostgreSQL + - container database + - PostgreSQL performance tuning --- -# PostgreSQL: Advanced Configuration and Initialization - -This guide covers advanced configuration techniques for running PostgreSQL in Docker containers, including automated database initialization, performance tuning, and timezone configuration. +With persistent storage configured in the previous section, you're ready to customize PostgreSQL for real-world use. This guide covers advanced configuration techniques for running PostgreSQL in Docker containers, including automated database initialization, performance tuning, and timezone configuration. ## Overview @@ -51,7 +55,7 @@ services: image: postgres:18 volumes: - ./init-db:/docker-entrypoint-initdb.d - - postgres_data:/var/lib/postgresql/data + - postgres_data:/var/lib/postgresql environment: POSTGRES_PASSWORD: mysecretpassword @@ -99,7 +103,7 @@ services: volumes: - ./my-postgres.conf:/etc/postgresql/postgresql.conf - ./init-db:/docker-entrypoint-initdb.d - - postgres_data:/var/lib/postgresql/data + - postgres_data:/var/lib/postgresql command: postgres -c config_file=/etc/postgresql/postgresql.conf environment: POSTGRES_PASSWORD: mysecretpassword @@ -129,6 +133,8 @@ The following tables list important `postgresql.conf` parameters for containeriz | `maintenance_work_mem` | Memory for VACUUM, CREATE INDEX | 64MB - 256MB | | `effective_cache_size` | Planner's cache size estimate | 50-75% of container memory | +> **Docker memory limits:** When tuning memory parameters, set explicit memory limits on your container using `deploy.resources.limits.memory` in Compose or `--memory` with `docker run`. Without limits, PostgreSQL sees the host's total RAM and may allocate more than intended. For example, if your container should use 4GB maximum, set `shared_buffers` to approximately 1GB (25%). + ### I/O settings | Parameter | Description | Recommended starting value | @@ -155,20 +161,26 @@ services: db: image: postgres:18 volumes: + - postgres_data:/var/lib/postgresql - /etc/localtime:/etc/localtime:ro - /etc/timezone:/etc/timezone:ro environment: POSTGRES_PASSWORD: mysecretpassword TZ: America/New_York + +volumes: + postgres_data: ``` -Alternatively, set the timezone using a PostgreSQL parameter: +Alternatively, set the timezone using a PostgreSQL command-line parameter: ```yaml -command: - - postgres - - -c - - timezone=America/New_York +services: + db: + image: postgres:18 + command: ["postgres", "-c", "timezone=America/New_York"] + environment: + POSTGRES_PASSWORD: mysecretpassword ``` ### Setting the locale @@ -179,12 +191,17 @@ Specify locale settings during database initialization using the `POSTGRES_INITD services: db: image: postgres:18 + volumes: + - postgres_data:/var/lib/postgresql environment: POSTGRES_PASSWORD: mysecretpassword - POSTGRES_INITDB_ARGS: --encoding=UTF8 --lc-collate=en_US.UTF-8 --lc-ctype=en_US.UTF-8 + POSTGRES_INITDB_ARGS: "--encoding=UTF8 --lc-collate=en_US.UTF-8 --lc-ctype=en_US.UTF-8" + +volumes: + postgres_data: ``` -This affects collation (sorting) and character processing behavior. Changing this variable after db creation will have no effect, this only has effect during the first run. +This affects collation (sorting) and character processing behavior. Changing this variable after database creation has no effect—it only applies during the first run when the data directory is initialized. ## Connecting to the database From dcd11dcc8f86270b8e38854ead5bdda55b2867f0 Mon Sep 17 00:00:00 2001 From: Igor Alexandrov Date: Mon, 2 Feb 2026 22:52:32 -0500 Subject: [PATCH 09/17] Added DHI examples --- .../immediate-setup-and-data-persistence.md | 54 +++++++++++++++++++ 1 file changed, 54 insertions(+) diff --git a/content/guides/postgresql/immediate-setup-and-data-persistence.md b/content/guides/postgresql/immediate-setup-and-data-persistence.md index 1b0251433fa2..3fd4e8dea05e 100644 --- a/content/guides/postgresql/immediate-setup-and-data-persistence.md +++ b/content/guides/postgresql/immediate-setup-and-data-persistence.md @@ -22,8 +22,28 @@ Running PostgreSQL in Docker requires understanding one critical concept: contai ## Quick Start (Minimal Viable Container) +> [!NOTE] +> +> [Docker Hardened Images (DHIs)](https://docs.docker.com/dhi/) are minimal, secure, and production-ready container base and application images maintained by Docker. DHIs are recommended whenever it is possible for better security. They are designed to reduce vulnerabilities and simplify compliance, freely available to everyone with no subscription required, no usage restrictions, and no vendor lock-in. + Run PostgreSQL immediately with this single command: +{{< tabs >}} +{{< tab name="Using DHIs" >}} + +You must authenticate to dhi.io before you can pull Docker Hardened Images. Run docker login dhi.io to authenticate. + +```console +docker run --rm --name postgres-dev \ + -e POSTGRES_PASSWORD=mysecretpassword \ + -p 5432:5432 \ + -d dhi.io/postgres:18 +``` + +{{< /tab >}} + +{{< tab name="Using DOIs" >}} + ```console $ docker run --rm --name postgres-dev \ -e POSTGRES_PASSWORD=mysecretpassword \ @@ -31,6 +51,9 @@ $ docker run --rm --name postgres-dev \ -d postgres:18 ``` +{{< /tab >}} +{{< /tabs >}} + ### Understanding the flags | Flag | Purpose | @@ -94,6 +117,33 @@ Named volumes are Docker-managed storage locations that persist independently of Create a container with a named volume: +{{< tabs >}} +{{< tab name="Using DHIs" >}} + +You must authenticate to dhi.io before you can pull Docker Hardened Images. Run docker login dhi.io to authenticate. + +> [!NOTE] +> +> Hardened image runs as a non-root user, and the volume gets created with root ownership. To avoid permission issues, pre-create the volume and set ownership to UID 999 (the `postgres` user inside the container). + +```console +$ docker volume create postgres_data + +$ docker run --rm \ + -v postgres_data:/var/lib/postgresqlbusybox \ + chown -R 999:999 /var/lib/postgresql + +$ docker run --rm --name postgres-dev \ + -e POSTGRES_PASSWORD=mysecretpassword \ + -p 5432:5432 \ + -v postgres_data:/var/lib/postgresql \ + -d dhi.io/postgres:18 +``` + +{{< /tab >}} + +{{< tab name="Using DOIs" >}} + ```console $ docker run --rm --name postgres-dev \ -e POSTGRES_PASSWORD=mysecretpassword \ @@ -102,6 +152,10 @@ $ docker run --rm --name postgres-dev \ -d postgres:18 ``` +{{< /tab >}} +{{< /tabs >}} + + The `-v postgres_data:/var/lib/postgresql` flag mounts a named volume called `postgres_data` to PostgreSQL's data directory. If the volume doesn't exist, Docker creates it automatically. > **Note:** PostgreSQL 18+ stores data in a version-specific subdirectory under `/var/lib/postgresql`. Mounting at this level (rather than `/var/lib/postgresql/data`) allows for easier upgrades using `pg_upgrade --link`. From bc3e9c8ed83dc24463b71351bf04753de24885a1 Mon Sep 17 00:00:00 2001 From: Igor Alexandrov Date: Tue, 3 Feb 2026 14:40:33 -0500 Subject: [PATCH 10/17] Added more DHI examples --- .../immediate-setup-and-data-persistence.md | 94 ++++++++++++++++--- 1 file changed, 82 insertions(+), 12 deletions(-) diff --git a/content/guides/postgresql/immediate-setup-and-data-persistence.md b/content/guides/postgresql/immediate-setup-and-data-persistence.md index 3fd4e8dea05e..6799ccf745f6 100644 --- a/content/guides/postgresql/immediate-setup-and-data-persistence.md +++ b/content/guides/postgresql/immediate-setup-and-data-persistence.md @@ -31,7 +31,7 @@ Run PostgreSQL immediately with this single command: {{< tabs >}} {{< tab name="Using DHIs" >}} -You must authenticate to dhi.io before you can pull Docker Hardened Images. Run docker login dhi.io to authenticate. +You must authenticate to dhi.io before you can pull Docker Hardened Images. Run `docker login dhi.io` to authenticate. ```console docker run --rm --name postgres-dev \ @@ -90,6 +90,32 @@ Containers use an ephemeral filesystem. When a container is removed, everything Demonstrate this yourself: +{{< tabs >}} +{{< tab name="Using DHIs" >}} + +```console +$ docker exec postgres-dev psql -U postgres -c "CREATE DATABASE testdb;" +CREATE DATABASE + +$ docker exec postgres-dev psql -U postgres -c "\l" | grep testdb + testdb | postgres | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | + +$ docker stop postgres-dev +postgres-dev + +$ docker run --rm --name postgres-dev \ + -e POSTGRES_PASSWORD=mysecretpassword \ + -p 5432:5432 \ + -d dhi.io/postgres:18 + +$ docker exec postgres-dev psql -U postgres -c "\l" | grep testdb +(no output - database is gone) +``` + +{{< /tab >}} + +{{< tab name="Using DOIs" >}} + ```console $ docker exec postgres-dev psql -U postgres -c "CREATE DATABASE testdb;" CREATE DATABASE @@ -109,6 +135,9 @@ $ docker exec postgres-dev psql -U postgres -c "\l" | grep testdb (no output - database is gone) ``` +{{< /tab >}} +{{< /tabs >}} + Your `testdb` database vanished because the new container started with a fresh filesystem. This is expected behavior—and exactly why volumes exist. ## Named Volumes @@ -122,17 +151,7 @@ Create a container with a named volume: You must authenticate to dhi.io before you can pull Docker Hardened Images. Run docker login dhi.io to authenticate. -> [!NOTE] -> -> Hardened image runs as a non-root user, and the volume gets created with root ownership. To avoid permission issues, pre-create the volume and set ownership to UID 999 (the `postgres` user inside the container). - ```console -$ docker volume create postgres_data - -$ docker run --rm \ - -v postgres_data:/var/lib/postgresqlbusybox \ - chown -R 999:999 /var/lib/postgresql - $ docker run --rm --name postgres-dev \ -e POSTGRES_PASSWORD=mysecretpassword \ -p 5432:5432 \ @@ -164,6 +183,9 @@ The `-v postgres_data:/var/lib/postgresql` flag mounts a named volume called `po To verify data persistence, repeat the previous test, but this time with the named volume attached in place. +{{< tabs >}} +{{< tab name="Using DHIs" >}} + ```console $ docker exec postgres-dev psql -U postgres -c "CREATE DATABASE testdb;" CREATE DATABASE @@ -175,12 +197,36 @@ $ docker run --rm --name postgres-dev \ -e POSTGRES_PASSWORD=mysecretpassword \ -p 5432:5432 \ -v postgres_data:/var/lib/postgresql \ - -d postgres:18 + -d dhi.io/postgres:18 $ docker exec postgres-dev psql -U postgres -c "\l" | grep testdb testdb | postgres | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | ``` +{{< /tab >}} + +{{< tab name="Using DOIs" >}} + +```console +$ docker exec postgres-dev psql -U postgres -c "CREATE DATABASE testdb;" +CREATE DATABASE + +$ docker stop postgres-dev +postgres-dev + +$ docker run --rm --name postgres-dev \ + -e POSTGRES_PASSWORD=mysecretpassword \ + -p 5432:5432 \ + -v postgres_data:/var/lib/postgresql \ + -d postgres:18 + +$ docker exec postgres-dev psql -U postgres -c "\l" | grep testdb + testdb | postgres | UTF8 | libc | en_US.utf8 | en_US.utf8 | | | + +{{< /tab >}} + +{{< /tabs >}} + If you see "testdb" in the output, persistence works: The database survived because the volume preserved the data directory. ### Managing volumes @@ -222,6 +268,27 @@ Bind mounts map a specific host directory to a container path. Unlike named volu Create a directory on your host machine to store Postgres data. +{{< tabs >}} +{{< tab name="Using DHIs" >}} + +```console +mkdir -p ~/postgres-data && sudo chown -R 999:999 ~/postgres-data +``` + +Run Postgres using a bind mount. + +```console +docker run --rm --name postgres-dev \ + -e POSTGRES_PASSWORD=mysecretpassword \ + -p 5432:5432 \ + -v ~/postgres-data:/var/lib/postgresql \ + -d dhi.io/postgres:18 +``` + +{{< /tab >}} + +{{< tab name="Using DOIs" >}} + ```console $ mkdir -p ~/postgres-data ``` @@ -236,6 +303,9 @@ $ docker run --rm --name postgres-dev \ -d postgres:18 ``` +{{< /tab >}} +{{< /tabs >}} + ### When to use bind mounts Bind mounts are useful when you need direct filesystem access to the data directory for backup scripts that read files directly, when integrating with host-level monitoring tools, or when specific permission requirements exist. For most development and production scenarios, named volumes are simpler and less error-prone. From 3468d44005f1135cbe4973258571e5cae0702762 Mon Sep 17 00:00:00 2001 From: Edith Puclla Date: Tue, 3 Feb 2026 21:41:19 +0000 Subject: [PATCH 11/17] Adding Networking and Connectivity part --- .../postgresql/networking-and-connectivity.md | 328 +++++++++++++++++- 1 file changed, 327 insertions(+), 1 deletion(-) diff --git a/content/guides/postgresql/networking-and-connectivity.md b/content/guides/postgresql/networking-and-connectivity.md index f3ef9a88224f..54835c06224d 100644 --- a/content/guides/postgresql/networking-and-connectivity.md +++ b/content/guides/postgresql/networking-and-connectivity.md @@ -1,5 +1,331 @@ --- title: Networking and Connectivity linkTitle: Networking and Connectivity +description: This module shows how to connect to PostgreSQL in Docker in two common ways; from another container (internal network) and from your host machine (external access). +keywords: + - Networking PostgreSQL Docker weight: 30 ---- \ No newline at end of file +--- + +This guide covers two common ways to connect to PostgreSQL running in Docker: + +- **Container-to-container**: Connect from your application container to PostgreSQL over a private Docker network. No ports need to be exposed to the host. +- **Host-to-container**: Connect from your laptop or development machine using `localhost` and a published port. + +**Prerequisite**: This guide assumes you have PostgreSQL running with persistent storage. If you don't, follow the [Immediate Setup & Data Persistence]({{< relref "immediate-setup-and-data-persistence" >}}) guide first. + +## Internal Network Access (container-to-container) + +When your application runs in another container, connecting to PostgreSQL through a user-defined bridge network is the recommended approach. This setup provides automatic DNS resolution, so your application can connect to PostgreSQL using the container name as the hostname, without needing to track IP addresses. + +> **Why not use the default bridge network?** While containers on the default bridge network can communicate, they can only do so by IP address. Since container IP addresses change when containers restart, this would require updating your PostgreSQL connection strings each time. User-defined bridge networks solve this by providing automatic DNS resolution, ensuring your PostgreSQL connection strings remain stable even if containers restart and receive new IP addresses. + +**Here's a quick comparison:** + +> **Note**: The examples below show the difference in approach. To actually test this, follow the steps in this guide to set up containers on the appropriate networks first. + +With the default bridge network, you'd need to find the IP address first: +```bash +# Get the container's IP address (changes on restart) +docker inspect -f '{{range.NetworkSettings.Networks}}{{.IPAddress}}{{end}}' postgres-dev +# Output: 172.17.0.2 + +# Then connect using that IP address from another container +# (No --network flag needed - containers default to bridge network) +docker run --rm -it \ + -e PGPASSWORD=mysecretpassword \ + postgres:18 \ + psql -h 172.17.0.2 -U postgres +``` + +With a **user-defined network**, you simply use the container name: +```bash +# Container name works directly - no IP lookup needed +docker run --rm -it \ + --network my-app-net \ + -e PGPASSWORD=mysecretpassword \ + postgres:18 \ + psql -h postgres-dev -U postgres +``` + +### Step 1: Create a user-defined network + +```bash +docker network create my-app-net + +# Example Output +ab7f984be43a0ca15534a9ee568716ddbe869a5875077fad3ef3192e3af7d288 + +docker network ls +# Output +ab7f984be43a my-app-net bridge local + + +``` + +### Step 2: Run PostgreSQL on that network (no port publishing) + +Notice there is no `-p 5432:5432` here. This keeps PostgreSQL internal to Docker and not accessible from the host machine, which is more secure for production environments. + +```bash +docker run -d --name postgres-dev \ + --network my-app-net \ + -e POSTGRES_PASSWORD=mysecretpassword \ + -v postgres_data:/var/lib/postgresql \ + postgres:18 + + # Outout +CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES +6d351ed89efc postgres:18 "docker-entrypoint.s…" 9 seconds ago Up 8 seconds 5432/tcp postgres-dev + +``` + +### Step 3: Connect from another container using the Postgres container name + +You can test connectivity with a temporary psql client container: + +```bash +docker run --rm -it \ + --network my-app-net \ + -e PGPASSWORD=mysecretpassword \ + postgres:18 \ + psql -h postgres-dev -U postgres +``` + +**Key point**: `-h postgres-dev` works because Docker DNS resolves the container name on a user-defined network. The container name acts as the hostname. + +### Connection string examples + +When connecting from your application container, use these PostgreSQL connection strings: + +- **PostgreSQL URI format**: + This is the standard PostgreSQL connection URI format that combines all connection parameters into a single string, widely supported by PostgreSQL clients and libraries. + + ```bash + postgresql://postgres:mysecretpassword@postgres-dev:5432/postgres + ``` + + This command demonstrates passing a PostgreSQL URI connection string as an environment variable to a container, which your application can then read to connect to the database. + + Example usage in a Docker run command: + ```bash + docker run --rm -it \ + --network my-app-net \ + -e DATABASE_URL="postgresql://postgres:mysecretpassword@postgres-dev:5432/postgres" \ + alpine:latest \ + sh -c 'echo "DATABASE_URL is set to: $DATABASE_URL"' + ``` + + +- **PostgreSQL connection parameters**: + This format uses key-value pairs separated by spaces, which many PostgreSQL client libraries accept as an alternative to URI format. + ```bash + host=postgres-dev + port=5432 + user=postgres + password=mysecretpassword + dbname=postgres + ``` + + Example usage in application code (Python with psycopg2): + ```python + conn = psycopg2.connect( + host="postgres-dev", + port=5432, + user="postgres", + password="mysecretpassword", + dbname="postgres" + ) + ``` + +- **Connecting to a specific database**: + Replace the database name in the connection string to connect to a specific database instead of the default `postgres` database. + If you created a custom database (e.g., `testdb`), use: + ```bash + postgresql://postgres:mysecretpassword@postgres-dev:5432/testdb + ``` + + Example with SSL disabled (common in Docker networks): + Add `?sslmode=disable` to the connection string when connecting within a private Docker network where SSL encryption isn't required. + ```bash + postgresql://postgres:mysecretpassword@postgres-dev:5432/testdb?sslmode=disable + ``` + +> **PostgreSQL connection note**: The default port `5432` is used in these examples. If you're connecting to a different PostgreSQL instance or have changed the port, update the connection string accordingly. The container name (`postgres-dev`) is resolved by Docker DNS to the container's IP address on the network. + + +## Connecting from the Host (external access) + +To connect to PostgreSQL from your host machine using tools like `psql`, pgAdmin, DBeaver, or database management scripts, you need to publish PostgreSQL's port (`5432`) to the host. This allows external tools to reach the PostgreSQL container. + +### Expose Postgres to localhost only (recommended for development) + +This binds to `127.0.0.1` so it's only reachable from your local machine, not from other devices on your network. This is the most secure option for development. + +```bash +docker run -d --name postgres-dev \ + -e POSTGRES_PASSWORD=mysecretpassword \ + -p 127.0.0.1:5432:5432 \ + -v postgres_data:/var/lib/postgresql \ + postgres:18 +``` + +Now connect from your host: + +- **Host**: `localhost` or `127.0.0.1` +- **Port**: `5432` + +If you have `psql` installed on your host: +```bash +psql -h localhost -p 5432 -U postgres +``` + +You'll be prompted for the password. Alternatively, you can use the `PGPASSWORD` environment variable: +```bash +PGPASSWORD=mysecretpassword psql -h localhost -p 5432 -U postgres +``` + +### Connecting with PostgreSQL GUI tools + +Popular PostgreSQL GUI tools can connect using these common connection details: Host: `localhost`, Port: `5432`, User: `postgres`, Database: `postgres` (or your database name). + +- **pgAdmin**: A web-based PostgreSQL administration and development platform +- **DBeaver**: A universal database tool that supports PostgreSQL and many other databases. Select PostgreSQL as the connection type +- **TablePlus**: A modern, native database management tool for macOS and Windows with a clean interface + +All tools will prompt for the password you set with `POSTGRES_PASSWORD`. + +### Expose Postgres to all network interfaces (use with caution) + +To allow connections from other devices on your network, use `-p 5432:5432` instead of `-p 127.0.0.1:5432:5432`. This binds PostgreSQL to all network interfaces on your host, making it accessible from any device that can reach your host, not just localhost. + +```bash +docker run -d --name postgres-dev \ + -e POSTGRES_PASSWORD=mysecretpassword \ + -p 5432:5432 \ + -v postgres_data:/var/lib/postgresql \ + postgres:18 +``` + +> **Warning**: Exposing PostgreSQL to all network interfaces (`0.0.0.0:5432`) makes it accessible from any device that can reach your host. Only use this in trusted network environments or behind a firewall. For production, consider using a reverse proxy or VPN instead. + +### PostgreSQL security considerations for external access + +When exposing PostgreSQL to external access, follow these PostgreSQL-specific security practices: + +- **Avoid using the `postgres` superuser**: The default `postgres` user has full database privileges. Create dedicated users with only the permissions your application needs. +- **Use strong passwords**: PostgreSQL passwords should be complex. Consider using environment variables or secrets management instead of hardcoding passwords. +- **Limit network exposure**: Binding to `127.0.0.1` (localhost only) is safer than exposing to all interfaces (`0.0.0.0`). +- **Consider SSL/TLS**: For production, configure PostgreSQL to require SSL connections. The [Advanced Configuration and Initialization]({{< relref "advanced-configuration-and-initialization" >}}) guide shows how to configure PostgreSQL settings. +- **Create application-specific users**: Use initialization scripts to create users with limited privileges. For example, a read-only user for reporting or a user that can only access specific databases. + +The [Advanced Configuration and Initialization]({{< relref "advanced-configuration-and-initialization" >}}) guide shows how to use initialization scripts to create users and roles automatically. + +## Using Docker Compose for networking + +Docker Compose automatically creates a network for your services, making networking configuration simpler. Here's an example that combines both internal and external access: + +```yaml +services: + db: + image: postgres:18 + container_name: postgres-dev + environment: + POSTGRES_PASSWORD: mysecretpassword + volumes: + - postgres_data:/var/lib/postgresql + ports: + - "127.0.0.1:5432:5432" # Expose to localhost only + networks: + - app-network + + app: + build: ./my-app + environment: + DATABASE_URL: postgresql://postgres:mysecretpassword@db:5432/mydb + networks: + - app-network + depends_on: + - db + +volumes: + postgres_data: + +networks: + app-network: + driver: bridge +``` + +In this PostgreSQL-focused setup: +- The `app` service connects to PostgreSQL using the service name (`db`) as the hostname in the connection string +- PostgreSQL is accessible from your host at `localhost:5432` for external tools +- Both services are isolated on a custom network, providing network-level security +- The `depends_on` directive ensures PostgreSQL starts before your application + +**PostgreSQL connection details for the app service**: +- Hostname: `db` (resolved by Docker DNS) +- Port: `5432` (PostgreSQL default port) +- Database: `mydb` (as specified in the connection string) +- User: `postgres` (or a custom user you've created) + +> **Note**: Docker Compose automatically creates a network for your project. Services can reach each other by service name without explicit network configuration, but defining a custom network gives you more control. For PostgreSQL, this means your application can always connect using the service name, regardless of container restarts or IP changes. + +## Troubleshooting + +This section covers common PostgreSQL connection issues and their solutions when working with Docker networking. + +### "Could not translate host name postgres-dev" + +- Both containers must be on the same Docker network (`my-app-net`). +- Verify the network exists: `docker network ls` +- Check which network a container is on: `docker inspect postgres-dev | grep NetworkMode` +- Ensure you're using a user-defined network, not the default bridge network + +### "Connection refused" or "could not connect to server" + +- **PostgreSQL may still be initializing**: PostgreSQL takes a few seconds to start and initialize the database cluster. Wait 5-10 seconds after container start and retry. +- **Check if the PostgreSQL container is running**: + +```bash +docker ps --filter name=postgres-dev +``` + +- **Check PostgreSQL logs for initialization or connection errors**: + +```bash +docker logs postgres-dev +``` + +Look for messages like "database system is ready to accept connections" to confirm PostgreSQL is fully started. + +- **Verify the port mapping is correct**: + +```bash +docker port postgres-dev +``` + +This should show `5432/tcp -> 127.0.0.1:5432` (or `0.0.0.0:5432` if bound to all interfaces). + +- **Test PostgreSQL connectivity from inside the container**: + +```bash +docker exec -it postgres-dev psql -U postgres -c "SELECT version();" +``` + +If this works but external connections fail, the issue is with port publishing, not PostgreSQL itself. + +### "Password authentication failed" or "FATAL: password authentication failed for user" + +- **Confirm the password**: Verify you're using the same password set in `POSTGRES_PASSWORD` when you started the container. +- **Existing volume with old credentials**: If you reused an existing volume, the password from the original initialization is still in effect. The `POSTGRES_PASSWORD` environment variable only sets the password during the first database initialization. To reset: + - Remove the volume: `docker volume rm postgres_data` + - Or connect with the old password + - Or change the password after connecting: `ALTER USER postgres WITH PASSWORD 'newpassword';` +- **Try connecting with password prompt**: `psql -h localhost -U postgres -W` (the `-W` flag forces a password prompt) +- **Use PGPASSWORD environment variable**: `PGPASSWORD=mysecretpassword psql -h localhost -U postgres` +- **Check PostgreSQL authentication configuration**: If you've customized `pg_hba.conf`, verify the authentication method allows password authentication + +### "Network not found" + +- Ensure the network exists before starting containers: `docker network create my-app-net` +- If using Docker Compose, the network is created automatically when you run `docker compose up` \ No newline at end of file From b8a638541486199ffc6372e47063e29b979440de Mon Sep 17 00:00:00 2001 From: Edith Puclla Date: Wed, 4 Feb 2026 14:50:33 +0000 Subject: [PATCH 12/17] Fix the reference links --- content/guides/postgresql/networking-and-connectivity.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/guides/postgresql/networking-and-connectivity.md b/content/guides/postgresql/networking-and-connectivity.md index 54835c06224d..e9d8a01f0406 100644 --- a/content/guides/postgresql/networking-and-connectivity.md +++ b/content/guides/postgresql/networking-and-connectivity.md @@ -12,7 +12,7 @@ This guide covers two common ways to connect to PostgreSQL running in Docker: - **Container-to-container**: Connect from your application container to PostgreSQL over a private Docker network. No ports need to be exposed to the host. - **Host-to-container**: Connect from your laptop or development machine using `localhost` and a published port. -**Prerequisite**: This guide assumes you have PostgreSQL running with persistent storage. If you don't, follow the [Immediate Setup & Data Persistence]({{< relref "immediate-setup-and-data-persistence" >}}) guide first. +**Prerequisite**: This guide assumes you have PostgreSQL running with persistent storage. If you don't, follow the [Immediate Setup & Data Persistence](/content/guides/postgresql/immediate-setup-and-data-persistence/) guide first. ## Internal Network Access (container-to-container) @@ -216,10 +216,10 @@ When exposing PostgreSQL to external access, follow these PostgreSQL-specific se - **Avoid using the `postgres` superuser**: The default `postgres` user has full database privileges. Create dedicated users with only the permissions your application needs. - **Use strong passwords**: PostgreSQL passwords should be complex. Consider using environment variables or secrets management instead of hardcoding passwords. - **Limit network exposure**: Binding to `127.0.0.1` (localhost only) is safer than exposing to all interfaces (`0.0.0.0`). -- **Consider SSL/TLS**: For production, configure PostgreSQL to require SSL connections. The [Advanced Configuration and Initialization]({{< relref "advanced-configuration-and-initialization" >}}) guide shows how to configure PostgreSQL settings. +- **Consider SSL/TLS**: For production, configure PostgreSQL to require SSL connections. The [Advanced Configuration and Initialization](/content/guides/postgresql/advanced-configuration-and-initialization/) guide shows how to configure PostgreSQL settings. - **Create application-specific users**: Use initialization scripts to create users with limited privileges. For example, a read-only user for reporting or a user that can only access specific databases. -The [Advanced Configuration and Initialization]({{< relref "advanced-configuration-and-initialization" >}}) guide shows how to use initialization scripts to create users and roles automatically. +The [Advanced Configuration and Initialization](/content/guides/postgresql/advanced-configuration-and-initialization/) guide shows how to use initialization scripts to create users and roles automatically. ## Using Docker Compose for networking From 85114f55ef45defee18f6959069e54ef0ce77b41 Mon Sep 17 00:00:00 2001 From: Edith Puclla Date: Wed, 4 Feb 2026 16:38:34 +0000 Subject: [PATCH 13/17] Adding description and fixing level of doc tittle --- content/guides/postgresql/companions-for-postgresql.md | 7 ++++++- 1 file changed, 6 insertions(+), 1 deletion(-) diff --git a/content/guides/postgresql/companions-for-postgresql.md b/content/guides/postgresql/companions-for-postgresql.md index 2fd9b4779f8e..a9cd6b465a76 100644 --- a/content/guides/postgresql/companions-for-postgresql.md +++ b/content/guides/postgresql/companions-for-postgresql.md @@ -1,11 +1,16 @@ --- title: Companions for PostgreSQL linkTitle: Companions for PostgreSQL +description: This module explains how to customize PostgreSQL for real-world use in Docker, covering automated database initialization, performance tuning, and timezone configuration once persistent storage is in place. +keywords: + - PostgreSQL Docker + - Docker Compose PostgreSQL + - container database weight: 40 --- -# PostgreSQL Ecosystem Companions: pgAdmin, PgBouncer, and Performance Testing +## PostgreSQL Ecosystem Companions: pgAdmin, PgBouncer, and Performance Testing Running a standalone PostgreSQL container is often just the beginning. What happens when thousands of connections arrive, or when you need a visual interface to manage your database? From 8fe99529cfede7036e9f4c14c76dd6de2a049827 Mon Sep 17 00:00:00 2001 From: Edith Puclla Date: Wed, 4 Feb 2026 16:47:48 +0000 Subject: [PATCH 14/17] Fixing bash format for code snippeds --- content/guides/postgresql/companions-for-postgresql.md | 4 ++-- 1 file changed, 2 insertions(+), 2 deletions(-) diff --git a/content/guides/postgresql/companions-for-postgresql.md b/content/guides/postgresql/companions-for-postgresql.md index a9cd6b465a76..898f9b417d68 100644 --- a/content/guides/postgresql/companions-for-postgresql.md +++ b/content/guides/postgresql/companions-for-postgresql.md @@ -82,7 +82,7 @@ To run PostgreSQL and PgBouncer together, you need three files: `docker-compose. First, create the PgBouncer configuration file (`pgbouncer.ini`): -```ini +```bash [databases] benchmark = host=postgres port=5432 dbname=benchmark user=postgres @@ -102,7 +102,7 @@ max_db_connections = 100 Next, create the user authentication file (`userlist.txt`): -``` +```bash "postgres" "postgres" ``` From d68095612d406e98d1991257c16271488c4c697b Mon Sep 17 00:00:00 2001 From: Edith Puclla Date: Thu, 5 Feb 2026 00:30:15 +0000 Subject: [PATCH 15/17] Remove content form the static resource --- content/guides/postgresql/networking-and-connectivity.md | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/content/guides/postgresql/networking-and-connectivity.md b/content/guides/postgresql/networking-and-connectivity.md index e9d8a01f0406..a94c147618c9 100644 --- a/content/guides/postgresql/networking-and-connectivity.md +++ b/content/guides/postgresql/networking-and-connectivity.md @@ -12,7 +12,7 @@ This guide covers two common ways to connect to PostgreSQL running in Docker: - **Container-to-container**: Connect from your application container to PostgreSQL over a private Docker network. No ports need to be exposed to the host. - **Host-to-container**: Connect from your laptop or development machine using `localhost` and a published port. -**Prerequisite**: This guide assumes you have PostgreSQL running with persistent storage. If you don't, follow the [Immediate Setup & Data Persistence](/content/guides/postgresql/immediate-setup-and-data-persistence/) guide first. +**Prerequisite**: This guide assumes you have PostgreSQL running with persistent storage. If you don't, follow the [Immediate Setup & Data Persistence](/guides/postgresql/immediate-setup-and-data-persistence/) guide first. ## Internal Network Access (container-to-container) @@ -216,10 +216,10 @@ When exposing PostgreSQL to external access, follow these PostgreSQL-specific se - **Avoid using the `postgres` superuser**: The default `postgres` user has full database privileges. Create dedicated users with only the permissions your application needs. - **Use strong passwords**: PostgreSQL passwords should be complex. Consider using environment variables or secrets management instead of hardcoding passwords. - **Limit network exposure**: Binding to `127.0.0.1` (localhost only) is safer than exposing to all interfaces (`0.0.0.0`). -- **Consider SSL/TLS**: For production, configure PostgreSQL to require SSL connections. The [Advanced Configuration and Initialization](/content/guides/postgresql/advanced-configuration-and-initialization/) guide shows how to configure PostgreSQL settings. +- **Consider SSL/TLS**: For production, configure PostgreSQL to require SSL connections. The [Advanced Configuration and Initialization](/guides/postgresql/advanced-configuration-and-initialization/) guide shows how to configure PostgreSQL settings. - **Create application-specific users**: Use initialization scripts to create users with limited privileges. For example, a read-only user for reporting or a user that can only access specific databases. -The [Advanced Configuration and Initialization](/content/guides/postgresql/advanced-configuration-and-initialization/) guide shows how to use initialization scripts to create users and roles automatically. +The [Advanced Configuration and Initialization](/guides/postgresql/advanced-configuration-and-initialization/) guide shows how to use initialization scripts to create users and roles automatically. ## Using Docker Compose for networking From e42a58b4ab23f3d4df4940f6995a9e18a48a4c18 Mon Sep 17 00:00:00 2001 From: Edith Puclla Date: Thu, 5 Feb 2026 00:45:28 +0000 Subject: [PATCH 16/17] Fixing minor error in the doc spellings --- .../advanced-configuration-and-initialization.md | 6 +++--- .../guides/postgresql/companions-for-postgresql.md | 12 ++++++------ .../immediate-setup-and-data-persistence.md | 2 +- .../guides/postgresql/networking-and-connectivity.md | 4 ++-- 4 files changed, 12 insertions(+), 12 deletions(-) diff --git a/content/guides/postgresql/advanced-configuration-and-initialization.md b/content/guides/postgresql/advanced-configuration-and-initialization.md index ae9cdd8d01ab..630d1bd7696e 100644 --- a/content/guides/postgresql/advanced-configuration-and-initialization.md +++ b/content/guides/postgresql/advanced-configuration-and-initialization.md @@ -150,7 +150,7 @@ The following tables list important `postgresql.conf` parameters for containeriz | `deadlock_timeout` | Time before checking for deadlock | `1s` | | `transaction_timeout` | Max time for a transaction | `0` (disabled) | -> **Note:** Setting `shared_buffers` too high in a container can exceed kernel shared memory limits. We recommend using no more than 25-30% of the container's memory limit. +> **Note:** Setting `shared_buffers` too high in a container can exceed kernel shared memory limits. Use no more than 25-30% of the container's memory limit. ## Timezone and locale configuration @@ -205,11 +205,11 @@ This affects collation (sorting) and character processing behavior. Changing thi ## Connecting to the database -You can interact with PostgreSQL running in a container even without psql installed on your host machine. +You can interact with PostgreSQL running in a container even without `psql` installed on your host machine. ### Interactive shell -Open a psql session inside the container: +Open a `psql` session inside the container: ```console $ docker exec -it postgres-container psql -U postgres diff --git a/content/guides/postgresql/companions-for-postgresql.md b/content/guides/postgresql/companions-for-postgresql.md index 898f9b417d68..c555d5677545 100644 --- a/content/guides/postgresql/companions-for-postgresql.md +++ b/content/guides/postgresql/companions-for-postgresql.md @@ -14,7 +14,7 @@ weight: 40 Running a standalone PostgreSQL container is often just the beginning. What happens when thousands of connections arrive, or when you need a visual interface to manage your database? -This is where **companion tools** come into play. These applications extend PostgreSQL with capabilities the core database engine doesn't provide natively: visual administration, connection pooling, and performance benchmarking. This guide covers how to deploy pgAdmin 4, PgBouncer, Pgpool-II, and pgbench in Docker, when to use each tool, and real-world benchmark results demonstrating their performance impact. +This is where **companion tools** come into play. These applications extend PostgreSQL with capabilities the core database engine doesn't provide natively: visual administration, connection pooling, and performance benchmarking. This guide covers how to deploy pgAdmin 4, PgBouncer, Pgpool-II, and `pgbench` in Docker, when to use each tool, and real-world benchmark results demonstrating their performance impact. ## pgAdmin 4: Visual Management Platform @@ -154,20 +154,20 @@ networks: Key configuration notes: -- PgBouncer listens on port **6432**, avoiding confusion with the direct PostgreSQL connection on port 5432 +- `PgBouncer` listens on port **6432**, avoiding confusion with the direct PostgreSQL connection on port 5432 - The `depends_on` directive with `service_healthy` condition ensures PgBouncer starts only after PostgreSQL is ready - `pool_mode = transaction` is the optimal choice for most web applications -- The Percona PgBouncer image requires mounted configuration files (without the `:ro` flag, as the entrypoint script needs to modify them) +- The [Percona PgBouncer image](https://hub.docker.com/r/percona/percona-pgbouncer) requires mounted configuration files (without the `:ro` flag, as the entrypoint script needs to modify them) - This example uses `trust` authentication for simplicity. In production, configure proper SCRAM-SHA-256 authentication -> **Note**: The Percona PgBouncer entrypoint script processes the configuration files on startup. Mount them without the read-only flag to avoid permission errors. +> **Note**: The `Percona PgBouncer` entrypoint script processes the configuration files on startup. Mount them without the read-only flag to avoid permission errors. -## pgbench: Performance Benchmarking +## `pgbench`: Performance Benchmarking -pgbench is a benchmarking utility included with the official PostgreSQL image. It allows you to simulate heavy workloads and verify how your Docker configuration performs under pressure. +`pgbench` is a benchmarking utility included with the official PostgreSQL image. It allows you to simulate heavy workloads and verify how your Docker configuration performs under pressure. ### Initialize Benchmark Tables diff --git a/content/guides/postgresql/immediate-setup-and-data-persistence.md b/content/guides/postgresql/immediate-setup-and-data-persistence.md index 6799ccf745f6..1d5d192a60ef 100644 --- a/content/guides/postgresql/immediate-setup-and-data-persistence.md +++ b/content/guides/postgresql/immediate-setup-and-data-persistence.md @@ -72,7 +72,7 @@ CONTAINER ID IMAGE COMMAND STATUS PORTS a1b2c3d4e5f6 postgres:18 "docker-entrypoint.s…" Up 2 seconds 0.0.0.0:5432->5432/tcp postgres-dev ``` -Connect using psql from inside the container: +Connect using `psql` from inside the container: ```console $ docker exec -it postgres-dev psql -U postgres diff --git a/content/guides/postgresql/networking-and-connectivity.md b/content/guides/postgresql/networking-and-connectivity.md index a94c147618c9..43ac5247f847 100644 --- a/content/guides/postgresql/networking-and-connectivity.md +++ b/content/guides/postgresql/networking-and-connectivity.md @@ -156,7 +156,7 @@ When connecting from your application container, use these PostgreSQL connection ## Connecting from the Host (external access) -To connect to PostgreSQL from your host machine using tools like `psql`, pgAdmin, DBeaver, or database management scripts, you need to publish PostgreSQL's port (`5432`) to the host. This allows external tools to reach the PostgreSQL container. +To connect to PostgreSQL from your host machine using tools like `psql`, `pgAdmin`, `DBeaver`, or database management scripts, you need to publish PostgreSQL's port (`5432`) to the host. This allows external tools to reach the PostgreSQL container. ### Expose Postgres to localhost only (recommended for development) @@ -214,7 +214,7 @@ docker run -d --name postgres-dev \ When exposing PostgreSQL to external access, follow these PostgreSQL-specific security practices: - **Avoid using the `postgres` superuser**: The default `postgres` user has full database privileges. Create dedicated users with only the permissions your application needs. -- **Use strong passwords**: PostgreSQL passwords should be complex. Consider using environment variables or secrets management instead of hardcoding passwords. +- **Use strong passwords**: PostgreSQL passwords should be complex. Consider using environment variables or secrets management instead of `hardcoding` passwords. - **Limit network exposure**: Binding to `127.0.0.1` (localhost only) is safer than exposing to all interfaces (`0.0.0.0`). - **Consider SSL/TLS**: For production, configure PostgreSQL to require SSL connections. The [Advanced Configuration and Initialization](/guides/postgresql/advanced-configuration-and-initialization/) guide shows how to configure PostgreSQL settings. - **Create application-specific users**: Use initialization scripts to create users with limited privileges. For example, a read-only user for reporting or a user that can only access specific databases. From 2a3ae04e1839e8506dd60e0ddc6153a244fd584c Mon Sep 17 00:00:00 2001 From: Edith Puclla Date: Thu, 5 Feb 2026 00:54:28 +0000 Subject: [PATCH 17/17] Fixing validate check for grammar --- content/guides/postgresql/companions-for-postgresql.md | 2 +- .../guides/postgresql/immediate-setup-and-data-persistence.md | 2 +- content/guides/postgresql/networking-and-connectivity.md | 4 ++-- 3 files changed, 4 insertions(+), 4 deletions(-) diff --git a/content/guides/postgresql/companions-for-postgresql.md b/content/guides/postgresql/companions-for-postgresql.md index c555d5677545..1440d56ec34c 100644 --- a/content/guides/postgresql/companions-for-postgresql.md +++ b/content/guides/postgresql/companions-for-postgresql.md @@ -45,7 +45,7 @@ pgadmin: - "8080:80" ``` -With this configuration, access the pgAdmin interface at `http://localhost:8080`. Use the email and password specified in the environment variables for initial login. +With this configuration, access the pgAdmin interface at `http://localhost:8080`. Use the email and password specified in the environment variables for initial sign in. > **Important**: In production environments, pass `PGADMIN_DEFAULT_PASSWORD` as an external environment variable or use Docker secrets. Storing passwords in plain text within `docker-compose.yml` poses a security risk. diff --git a/content/guides/postgresql/immediate-setup-and-data-persistence.md b/content/guides/postgresql/immediate-setup-and-data-persistence.md index 1d5d192a60ef..9db064e08fe6 100644 --- a/content/guides/postgresql/immediate-setup-and-data-persistence.md +++ b/content/guides/postgresql/immediate-setup-and-data-persistence.md @@ -149,7 +149,7 @@ Create a container with a named volume: {{< tabs >}} {{< tab name="Using DHIs" >}} -You must authenticate to dhi.io before you can pull Docker Hardened Images. Run docker login dhi.io to authenticate. +You must authenticate to dhi.io before you can pull Docker Hardened Images. Run `docker login dhi.io` to authenticate. ```console $ docker run --rm --name postgres-dev \ diff --git a/content/guides/postgresql/networking-and-connectivity.md b/content/guides/postgresql/networking-and-connectivity.md index 43ac5247f847..9e08ff7909ef 100644 --- a/content/guides/postgresql/networking-and-connectivity.md +++ b/content/guides/postgresql/networking-and-connectivity.md @@ -22,7 +22,7 @@ When your application runs in another container, connecting to PostgreSQL throug **Here's a quick comparison:** -> **Note**: The examples below show the difference in approach. To actually test this, follow the steps in this guide to set up containers on the appropriate networks first. +> **Note**: The following examples show the difference in approach. To actually test this, follow the steps in this guide to set up containers on the appropriate networks first. With the default bridge network, you'd need to find the IP address first: ```bash @@ -82,7 +82,7 @@ CONTAINER ID IMAGE COMMAND CREATED STATUS ### Step 3: Connect from another container using the Postgres container name -You can test connectivity with a temporary psql client container: +You can test connectivity with a temporary `psql` client container: ```bash docker run --rm -it \