Skip to content

Postgresql guide#24068

Open
igor-alexandrov wants to merge 18 commits intodocker:mainfrom
igor-alexandrov:postgresql-guide
Open

Postgresql guide#24068
igor-alexandrov wants to merge 18 commits intodocker:mainfrom
igor-alexandrov:postgresql-guide

Conversation

@igor-alexandrov
Copy link
Contributor

@igor-alexandrov igor-alexandrov commented Feb 3, 2026

Description

  • Add comprehensive PostgreSQL containerization guide with 4 modules covering setup, configuration, networking, and ecosystem tools
  • Include practical Docker and Docker Compose examples for each topic
  • Cover data persistence strategies (named volumes, bind mounts), initialization scripts, performance tuning, and connection pooling

This PR introduces a new PostgreSQL-specific guide to help users containerize PostgreSQL databases using Docker. The guide is structured into four progressive modules:

  1. Immediate Setup & Data Persistence - Covers running PostgreSQL containers with proper data persistence using named volumes, bind mounts, and Docker Compose configurations.

  2. Advanced Configuration and Initialization - Explains initialization scripts (/docker-entrypoint-initdb.d/), performance tuning parameters (memory settings, connection limits, I/O
    configuration), and timezone/locale settings.

  3. Networking and Connectivity - Details how to configure networking for containerized PostgreSQL deployments.

  4. Companions for PostgreSQL - Introduces ecosystem tools including pgAdmin 4 for visual management, PgBouncer and Pgpool-II for connection pooling, and pgbench for performance testing.

Examples include tabs showing both Docker Hardened Images (DHI) and Docker Official Images (DOI) variants where applicable.

The guide is prepared by @igor-alexandrov, @edithturn, and @Expeto.

Reviews

  • Technical review
  • Editorial review
  • Product review

@netlify
Copy link

netlify bot commented Feb 3, 2026

Deploy Preview for docsdocker ready!

Name Link
🔨 Latest commit f705491
🔍 Latest deploy log https://app.netlify.com/projects/docsdocker/deploys/699efe63635afb0008749ca0
😎 Deploy Preview https://deploy-preview-24068--docsdocker.netlify.app
📱 Preview on mobile
Toggle QR Code...

QR Code

Use your smartphone camera to open QR code link.

To edit notification comments on pull requests, go to your Netlify project configuration.

@igor-alexandrov igor-alexandrov marked this pull request as draft February 3, 2026 22:50
@igor-alexandrov igor-alexandrov marked this pull request as ready for review February 13, 2026 19:59
Copy link
Contributor

@tippexs tippexs left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just a small remark. Other then that, Great Work LGTM

```yaml
services:
postgres:
image: postgres:17.7
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is there a reason why we do use 17.7 instead of 18 as in the rest of the guide?

Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We fixed! Thank you @tippexs

Copy link
Contributor

@craig-osterhout craig-osterhout left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks @igor-alexandrov and all.
It looks great!
I left mostly style nits, not any technical blockers.

title: PostgreSQL specific guide
linkTitle: PostgreSQL
description: Containerize PostgreSQL databases using Docker
keywords: Docker, getting started, postgresql, languag
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
keywords: Docker, getting started, postgresql, languag
keywords: Docker, getting started, postgresql, language

time: 20 minutes
---

- Immediate Setup & Data Persistence
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Not needed, as the template auto populates the child pages.

Suggested change
- Immediate Setup & Data Persistence

---

- Immediate Setup & Data Persistence
- Advanced Configuration and Initialization
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Advanced Configuration and Initialization


- Immediate Setup & Data Persistence
- Advanced Configuration and Initialization
- Networking and Connectivity
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Networking and Connectivity

- Immediate Setup & Data Persistence
- Advanced Configuration and Initialization
- Networking and Connectivity
- Companions for PostfgreSQL
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- Companions for PostfgreSQL


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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### What to Expect
### 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
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
### Key Observations
### Key observations


When comparing direct connections versus PgBouncer, you'll typically notice:

**1. Connection overhead differs significantly**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
**1. Connection overhead differs significantly**
#### 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**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
**2. Behavior under pressure reveals the real difference**
#### 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**
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
**3. Throughput varies by environment**
#### 3. Throughput varies by environment

POSTGRES_DB: benchmark
POSTGRES_HOST_AUTH_METHOD: trust
volumes:
- postgres_data:/var/lib/postgresql/data
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
- postgres_data:/var/lib/postgresql/data
- postgres_data:/var/lib/postgresql


### 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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

So, I noticed that there's a discrepancy in where exactly the data directory is stored between dhi.io/postgres and docker.io/library/postgres.

The official image stores it at /var/lib/postgresql//docker whereas the hardened image stores it at /var/lib/postgresql//data.

I don't think we need to get into the weeds about where exactly it is in this paragraph, so maybe we can rephrase to:

Suggested change
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.
When the container starts, it checks whether the PostgreSQL data directory 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.

| `.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.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
> **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.
> **Important:** Initialization scripts only run when the PostgreSQL data directory is empty. If you mount a volume containing existing data, initialization is skipped. This behavior prevents overwriting existing databases.


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`.
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

👍

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants