惯性聚合 高效追踪和阅读你感兴趣的博客、新闻、科技资讯
阅读原文 在惯性聚合中打开

推荐订阅源

aimingoo的专栏
aimingoo的专栏
Engineering at Meta
Engineering at Meta
有赞技术团队
有赞技术团队
博客园_首页
Apple Machine Learning Research
Apple Machine Learning Research
Vercel News
Vercel News
G
Google Developers Blog
Blog — PlanetScale
Blog — PlanetScale
IT之家
IT之家
MongoDB | Blog
MongoDB | Blog
Y
Y Combinator Blog
B
Blog
The GitHub Blog
The GitHub Blog
M
MIT News - Artificial intelligence
OSCHINA 社区最新新闻
OSCHINA 社区最新新闻
Stack Overflow Blog
Stack Overflow Blog
C
Check Point Blog
Microsoft Azure Blog
Microsoft Azure Blog
D
DataBreaches.Net
I
InfoQ
Recent Announcements
Recent Announcements
阮一峰的网络日志
阮一峰的网络日志
腾讯CDC
H
Help Net Security

DEV Community

Authentication Security Deep Dive: From Brute Force to Salted Hashing (With Java Examples) Why AI Systems Don’t Fail — They Drift Spilling beans for how i learn for exam😁"Reinforcement Learning Cheat Sheet" I Replaced Chrome with Safari for AI Browser Automation. Here's What Broke (and What Finally Worked) How Python Borrows Other People's Work The $40 Architecture: Processing 1 Billion API Requests with 99.99% Uptime Vibe Coding: A Workflow Guide (From Zero to SaaS) Most webhook security guides protect the wrong side. The scary part is delivery. Headless CMS for TanStack Start: Build a Blog with Cosmic EU Age Verification App "Hacked in 2 Minutes" — What Actually Happened Comfy Cloud’s delete function does not actually remove files Running AI Models on GPU Cloud Servers: A Beginner Guide Event-driven media intelligence with AWS Step Functions and Bedrock I scored 500 AI prompts across 8 quality dimensions — here's what broke How to Call Google Gemini API from Next.js (Free Tier, No Backend Needed) The Portal Protocol: Reclaiming Human Connection in the Age of AI How to Fix Your Team's Scattered Knowledge Problem With a Self-Hosted Forum Intro to tc Cloud Functors: A Graph-First Mental Model for the Modern Cloud Designing Multi-Tenant Backends With Both Ownership and Team Access I Built a Neumorphic CSS Library with 77+ Components — Here's What I Learned PostgreSQL Performance Optimization: Why Connection Pooling Is Critical at Scale Cómo construí un SaaS multi-rubro para gestionar expensas en Argentina con FastAPI + Vue 3 🚀 I Built an Ethical Hacking Scanner Tool – Open Source Project I Replaced /usage and /context in Claude Code With a Single Statusline A Pythonic Way to Handle Emails (IMAP/SMTP) with Auto-Discovery and AI-Ready Design I Collected 8.9 Million Polymarket Price Points — Here's What I Found About How Markets Really Move EcoTrack AI — Carbon Footprint Tracker & Dashboard Everyone's Using AI. No One Agrees How. 5 self-hosted ebook managers worth trying in 2026 Building Your First AI Agent with LangChain: From Chatbot to Autonomous Assistant
Running PostgreSQL Correctly with Docker Compose
bertrand HARTWIG · 2026-06-17 · via DEV Community

This guide explains how to run a PostgreSQL instance with Docker Compose using a configuration that provides a solid baseline for a properly configured PostgreSQL deployment. (excluding backup and monitoring).

The goal is not only to start PostgreSQL, but to start it with sane defaults, persistent storage, proper health checks, query observability, and memory settings aligned with the resources allocated to the container.

The example below is generated by pgAssistant, which provides this kind of PostgreSQL Docker configuration for free.

Why this configuration matters

A PostgreSQL container should not be treated as a simple throwaway service when it stores application data. Several Docker Compose options have a direct impact on reliability, performance, security, and observability.

The most important points are:

  • restart: always
  • shm_size
  • persistent volumes
  • container CPU and memory limits
  • POSTGRES_INITDB_ARGS
  • a proper health check
  • pg_stat_statements
  • autovacuum=on
  • PostgreSQL tuning parameters generated from pgTune

Example docker-compose.yml

services:
  northwind-db:
    restart: always
    image: postgres:17-alpine
    shm_size: 1GB

    # Optional: Use tmpfs for shared memory when running in Swarm mode
    # volumes:
    #   - type: tmpfs
    #     target: /dev/shm
    #     tmpfs:
    #       size: 1073741824

    volumes:
      - northwind_data:/var/lib/postgresql/data

    ports:
      - "5432:5432"

    deploy:
      resources:
        limits:
          cpus: "6.0"
          memory: 4GB

    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=xxxxx
      - POSTGRES_DB=northwind
      - POSTGRES_INITDB_ARGS=--auth-local=scram-sha-256 --auth-host=scram-sha-256

    healthcheck:
      test: ["CMD", "pg_isready", "-U", "postgres"]
      interval: 10s
      timeout: 5s
      retries: 5

    command: >
      postgres
        -c shared_preload_libraries='pg_stat_statements'
        -c autovacuum=on
        -c max_connections=200
        -c shared_buffers='1GB'
        -c effective_cache_size='3GB'
        -c maintenance_work_mem='256MB'
        -c checkpoint_completion_target=0.9
        -c wal_buffers='16MB'
        -c default_statistics_target=100
        -c random_page_cost=1.1
        -c effective_io_concurrency=200
        -c work_mem='5242kB'
        -c min_wal_size='1GB'
        -c max_wal_size='4GB'
        -c huge_pages='off'
        -c max_worker_processes=6
        -c max_parallel_workers=6
        -c max_parallel_maintenance_workers=3
        -c max_parallel_workers_per_gather=3

volumes:
  northwind_data:

restart: always

restart: always

This option tells Docker to automatically restart the PostgreSQL container if it stops unexpectedly.

For a database service, this is important because PostgreSQL is usually a critical dependency for the application. Without a restart policy, the database may remain stopped after a crash, host reboot, or Docker daemon restart.

restart: always does not replace monitoring, backups, replication, or high availability, but it provides a basic resilience layer that should almost always be enabled for a database container.

Shared memory and shm_size

shm_size: 1GB

PostgreSQL relies on shared memory for several internal operations. Docker containers have a default shared memory size that is often too small for a properly tuned PostgreSQL instance.

A good rule is to align shm_size with the PostgreSQL shared_buffers value.

For example:

shm_size: 512MB

should be consistent with:

-c shared_buffers='512MB'

In the example generated by pgAssistant, both values are set to 1GB:

shm_size: 1GB
-c shared_buffers='1GB'

This is important because shared_buffers defines how much memory PostgreSQL uses for its own shared buffer cache. If Docker shared memory is undersized compared to PostgreSQL configuration, PostgreSQL may fail to start or behave poorly under load.

Persistent volume

volumes:
  - northwind_data:/var/lib/postgresql/data

mount point is diffrent with postgresql 18 :

volumes:
  - northwind_data:/var/lib/postgresql

A PostgreSQL database must use persistent storage.

The directory /var/lib/postgresql/data or /var/lib/postgresql with v18 is where the official PostgreSQL Docker image stores the database cluster. If this directory is not backed by a Docker volume or another persistent storage mechanism, the data may be lost when the container is removed.

The named volume:

volumes:
  northwind_data:

ensures that database files survive container recreation.

This is one of the most important parts of the configuration.

Container resources

deploy:
  resources:
    limits:
      cpus: "6.0"
      memory: 4GB

The CPU and memory allocated to the container are not just Docker-level constraints. They are also the values that should be used to calculate PostgreSQL tuning parameters.

Tools such as pgTune need to know how many CPUs and how much memory are available to PostgreSQL. The values used in pgTune must match the resources allocated to the container.

For example, if the container is limited to:

cpus: "6.0"
memory: 4GB

then pgTune should be configured using:

  • 6 CPUs
  • 4 GB of RAM

Using host-level resources instead of container-level resources would produce an incorrect PostgreSQL configuration.

POSTGRES_INITDB_ARGS

POSTGRES_INITDB_ARGS=--auth-local=scram-sha-256 --auth-host=scram-sha-256

POSTGRES_INITDB_ARGS allows passing arguments to initdb when the PostgreSQL data directory is initialized for the first time.

In this example, it enables SCRAM-SHA-256 authentication for both local and host connections:

--auth-local=scram-sha-256
--auth-host=scram-sha-256

This is important because authentication settings are part of the initial database cluster setup.

Note that these options only apply when the PostgreSQL data directory is empty. If the persistent volume already contains an initialized database, changing POSTGRES_INITDB_ARGS will not reinitialize the database.

Health check

healthcheck:
  test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER -d $$POSTGRES_DB"]
  interval: 10s
  timeout: 5s
  retries: 5

A health check allows Docker to determine whether PostgreSQL is actually ready to accept connections.

This is different from simply checking whether the container process is running. PostgreSQL may be running but not ready yet, especially during startup, crash recovery, or initialization.

The command:

pg_isready -U postgres

checks the readiness of the PostgreSQL server.

A proper health check is important when other services depend on the database. It allows orchestration tools, deployment scripts, and dependent containers to wait until PostgreSQL is ready before connecting.

pg_stat_statements

-c shared_preload_libraries='pg_stat_statements'

pg_stat_statements is essential for PostgreSQL query optimization.

It tracks SQL execution statistics, including how often queries run, how long they take, and how much load they generate. This makes it possible to identify expensive queries that need indexes, rewriting, caching, or schema improvements.

Enabling it requires two steps.

First, it must be loaded at server startup:

-c shared_preload_libraries='pg_stat_statements'

Second, the extension must be created inside the target database:

CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

A common way to do this with Docker is to add an initialization SQL script under /docker-entrypoint-initdb.d/, for example:

CREATE EXTENSION IF NOT EXISTS pg_stat_statements;

Without pg_stat_statements, database optimization is mostly guesswork. With it, you can focus on the queries that actually consume time and resources.

Useful example query:

SELECT
  query,
  calls,
  total_exec_time,
  mean_exec_time,
  rows
FROM pg_stat_statements
ORDER BY total_exec_time DESC
LIMIT 20;

autovacuum=on

-c autovacuum=on

Autovacuum should remain enabled.

PostgreSQL uses MVCC, which means updates and deletes leave behind dead tuples. Autovacuum cleans up these dead tuples and helps prevent table and index bloat.

Disabling autovacuum is dangerous for most applications. It can lead to degraded performance, excessive storage growth, transaction ID wraparound risks, and poor query plans due to outdated statistics.

In most cases, the right approach is not to disable autovacuum, but to tune it if the workload requires it.

pgTune-generated PostgreSQL parameters

The remaining PostgreSQL parameters passed to the postgres command are generated from pgTune:

-c max_connections=200
-c shared_buffers='1GB'
-c effective_cache_size='3GB'
-c maintenance_work_mem='256MB'
-c checkpoint_completion_target=0.9
-c wal_buffers='16MB'
-c default_statistics_target=100
-c random_page_cost=1.1
-c effective_io_concurrency=200
-c work_mem='5242kB'
-c min_wal_size='1GB'
-c max_wal_size='4GB'
-c huge_pages='off'
-c max_worker_processes=6
-c max_parallel_workers=6
-c max_parallel_maintenance_workers=3
-c max_parallel_workers_per_gather=3

These values should not be copied blindly from another machine.

They depend on:

  • allocated memory
  • available CPUs
  • storage type
  • expected workload
  • maximum number of connections
  • PostgreSQL version

pgTune provides a strong baseline configuration based on the resources allocated to the PostgreSQL container. It does not replace workload-specific tuning, but it gives a much better starting point than PostgreSQL defaults for many real-world deployments.

Important relationship between Docker resources and pgTune

The values used in pgTune must match the resources actually available to PostgreSQL.

For example, this Docker resource limit:

cpus: "6.0"
memory: 4GB

must be reflected in the pgTune input.

That is why pgAssistant generates both:

  1. the Docker resource limits, and
  2. the PostgreSQL runtime parameters derived from those limits.

This avoids a common mistake: tuning PostgreSQL for the host machine while the container is limited to fewer resources.

About pgAssistant

pgAssistant generates this kind of PostgreSQL Docker Compose configuration for free.

It helps create a more reliable and better-tuned PostgreSQL setup

This provides a solid minimum configuration for running PostgreSQL properly with Docker.