Docker Compose makes deploying complex multi-container apps a breeze. With just a configuration file, you can launch an entire environment with orchestrated containers, volumes and networks.

In this comprehensive 2600+ word guide, we will explore the ins and outs of running PostgreSQL in Docker Compose, tailored for production environments.

Topics covered:

  • Compose Overview
  • Compose for PostgreSQL
  • Storage Considerations
  • Backup & Recovery
  • Monitoring & Logs
  • Compose in Production
  • Alternative Orchestrators
  • Troubleshooting
  • Conclusion

Let‘s get started!

Docker Compose Overview

Docker Compose is a tool that defines and runs multi-container Docker apps in an easy-to-use YAML format. Here is an example:

version: "3.7"

services:

  webapp:
    image: nginx:alpine    
    ports:
      - "80:80"

  db:
    image: postgres:12
    volumes:
      - dbdata:/var/lib/postgresql/data

volumes:
  dbdata:

With a single docker-compose up, it will spin up an Nginx container and PostgreSQL container linked together.

Much more concise than having to run individual docker commands!

Some key advantages of using Compose:

  • Simpler app management – No need to manually spin up containers and link together. Declarative setup in YAML.

  • Multi-container networking – Containers share networks for easy access between services.

  • Environment consistency – Runs the same from dev, test, staging to prod environments.

  • Orchestration – Scales up containers across multiple hosts.

And importantly for databases like PostgreSQL, Compose makes volume management easy for persistent storage.

So how does Compose help when running PostgreSQL in particular?

Docker Compose for PostgreSQL

Relational databases have challenging infrastructure needs like:

  • Persistent storage
  • High availibility
  • Backups
  • Resource allocation

Docker Compose alleviates these complexities for running PostgreSQL:

  • Declarative volume binding ensures data persists across container restarts

  • Scaling replicas and load balancing improves availability

  • Managing backups reduces risk of data loss

  • Dedicating resources (CPU/RAM) prevents noisy neighbor issues

By incorporating all these needs natively into a Compose file, you can setup production-grade PostgreSQL with ease!

Let‘s go through a sample setup.

Sample PostgreSQL Compose File

Here is an example Docker Compose file for PostgreSQL.

version: ‘3.7‘

services:

  postgres:
    image: postgres:12
    ports:
      - 5432:5432
    env_file:
      - postgres.env
    volumes:
      - db-data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD", "pg_isready", "-U", "postgres"]
      timeout: 45s
      interval: 10s
      retries: 10
    deploy:  
      resources:
        limits:
          cpus: 2
          memory: 2G
      restart_policy:
        condition: on-failure

  pgadmin:
    image: dpage/pgadmin4
    env_file: 
      - pgadmin.env 
    ports:
      - 8080:80
    depends_on:
      - postgres

volumes:
  db-data:

Breaking this down:

  • Base PostgreSQL 12 image
  • Persistent volume for /var/lib/postgresql/data
  • Environment variables for creds
  • Healthchecks to ensure its running
  • Resources limits for 2 CPU cores and 2GB RAM
  • pgAdmin 4 container for GUI management

This sets up a production-ready PostgreSQL instance with just a few lines!

But deployment needs advance beyond a single container. How do manage more complex environments?

Storage Drivers & IOPS Provisioning

Persistent volumes used in Compose can leverage a variety of storage drivers under the hood.

Based on the infrastructure PostgreSQL runs on, different drivers offer different performance profiles:

| Storage Driver | Infrastructure | Performance Profile |
| --------------------------- | -------------------------------------|-------------------------------------|
| local | Server disks | Lower latency storage |
| nfs | Network attached storage | Nerwork filesystem arxchitecture|   
| efs | AWS Elastic Filesystem | Multi-AZ network filesystem |

And beyond just picking the storage driver, attention needs to be paid to:

  • IOPS Provisioning – Picking SSD-backed storage for fast random IOPS performance. A PostgreSQL 10k RPM volume handles 20x more IOPS than 5.4k RPM.

  • Throughput – Having enough bandwidth to read data without bottlenecks. This varies across network storage vs local or directly attached disks.

So while Compose makes volume mounting simple, additional consideration to storage performance is vital in production.

Now that we have performant volumes, we next need to make sure data integrity is not compromised…

Backup & Recovery Tools

A well-designed backup & recovery strategy is crucial for data protection and disaster recovery.

The wal-g tool specialized for PostgreSQL can carry out different types of backups depending on your RPO/RTO objectives:

Backup type Description RPO + RTO
Full Base Backup Initial complete snapshot 24h
Continuous Archiving Ongoing WAL segments archiving < 5 min RPO, 1h RTO
Differential Backup Regular incremental deltas 1h RPO, 1h RTO

And these PostgreSQL backups can be orchestrated right within Compose:

services:

  postgres:
    //...

  walg:
    image: store/repo/wal-g:latest  
    env_file:  
      - walg.env
    volumes:
      - archive_location:/backups
    depends_on:
      - postgres
    entrypoint: "./backup.sh" 

Where backup.sh executes the wal-g backup commands monthly full + nightly differential backups.

Integrating these Compose configured backups improves PostgreSQL resiliency!

Monitoring & Logs

In container setups, visibility is key but can be lacking. Compose allows aggregating monitoring and logs across all services.

For metrics, this sample uses Prometheus to poll PostgreSQL metrics:

services:

  postgres_exporter:
    image: postgres_exporter
    depends_on:
      - postgres
    // exports PG metrics  

  prometheus:  
    image: prom/prometheus:v2.0.0
    volumes:
      - ./prometheus.yml:/etc/prometheus/prometheus.yml
    // scrapes metrics

And for logging, Filebeat ships PostgreSQL logs:

  filebeat:
    image: elastic/filebeat:6.3.0 
    volumes:
     - /var/lib/docker/containers:/var/lib/docker/containers
     - /var/log/postgresql:/var/log/postgresql
    // ships logs to Elasticsearch    

Centralized monitoring and logging avoids blindspots and offers cross-service visibility.

Now with backups, monitoring, and logging squared away – could this setup work at scale in true production environments?

Running PostgreSQL Compose in Production

For production-grade workloads, exclusively relying on Compose has some limitations:

  • Limited cluster/swarm management capabilities
  • No autoscaling based on load
  • Dropping containers leads to downtime
  • Single container failures impact service availability

So while Compose gets you 85% there for running production PostgreSQL, the last 15% requires robust orchestration capabilities.

This is where Kubernetes shines…

Compose vs Kubernetes vs Swarm

For advanced container orchestration needs, Kubernetes is the go-to choice while Swarm has receiving waning support.

Here is a high-level comparison between the three:

Docker Compose Docker Swarm Kubernetes
Orchestration Features Basic Minimal Fully-featured
Persistent Volumes Yes Yes Yes
Multi-host Networking No Yes Yes
Scaling Manual Auto Auto
Health Checks Yes Yes Yes
Dashboard No Yes Yes

The verdict?

  • Use Compose for dev, test, CI environments
  • Use Kubernetes for staging, production
  • Avoid Swarm

PostgreSQL can utilize Kubernetes‘ auto-scaling, load balancing, self-healing and advanced features to run large production workloads.

But operating Kubernetes is an order of magnitude more complex than using Compose. So start simple, then evolve!

Troubleshooting Tips

Here are some common issues faced in production Compose environments and how to troubleshoot them:

Containers crashing randomly

This typically happens when containers exceeds their CPU and memory limits, and the OOM killer terminates them.

Solutions:

  • Check if CPU or RAM is spiking via monitoring
  • Increase limits allocated in Compose file
  • Tune PostgreSQL settings to reduce memory usage

Host filesytem ran out of inodes

Persistent volumes hosted on the server can index all available inodes.

Solutions:

  • Use EFS/EBS volumes instead for unlimited inodes
  • Periodically cleanup old logs from host volumes

Orderly Failover Did Not Occur Between Primaries

Healthchecks might be incorrectly promoting new primary servers.

Solutions:

  • Check promotion settings in Patroni‘s configuration
  • Verify health check thresholds not too aggressive

So while everything should run smoothly in Compose, being prepared to track down errors is key!

Conclusion

In closing, Docker Compose provides an excellent platform for running PostgreSQL in both dev and simple production environments.

Compose makes configuring persistence, networking, orchestration and monitoring intuitive and integrated for PostgreSQL. This simplicity abstracts away many complexities traditionally associated with running databases at scale.

For advanced production use cases, graduation to Kubernetes is recommended over time to enable auto-scaling, high availability and effortless maintenance.

Overall, Docker Compose + PostgreSQL is a combination that pairs a robust relational database with simple yet powerful orchestration. Together they enable appliations backed by Postgres to be run anywhere from a developer‘s laptop to scalable multi-cloud production environments!

Similar Posts