Docker Compose Operations: Secrets, Limits, Logs, and Updates
This walkthrough builds a small, runnable PostgreSQL lab so you can practice common Docker Compose operations. It demonstrates a persistent volume, health check, resource limits, bounded logs, and file-backed secrets.
This is a local learning stack, not a production-ready deployment. For production, use a platform-appropriate secret manager, tested off-host backups, reviewed image versions, monitoring, and a documented recovery plan. The database port below is bound to localhost only. The example uses a moving major-version tag for convenience; production deployments should pin and review the exact approved image digest.
Step 1: Define the Compose Service
Create a PostgreSQL Compose Service
Compose FileMake a project directory such as compose-lab and save this file there as compose.yaml. The stack will be ready to start after Step 2 creates the secret files. The resource limits and log rotation are set on this Compose service.
services: db: image: postgres:16-alpine restart: unless-stopped environment: POSTGRES_DB: compose_lab POSTGRES_USER_FILE: /run/secrets/db_user POSTGRES_PASSWORD_FILE: /run/secrets/db_password secrets: - db_user - db_password volumes: - db_data:/var/lib/postgresql/data ports: - "127.0.0.1:5432:5432" healthcheck: test: ["CMD", "pg_isready", "-U", "compose_lab_user", "-d", "compose_lab"] interval: 10s timeout: 5s retries: 5 start_period: 15s mem_limit: 1g cpus: 1.0 logging: driver: json-file options: max-size: "10m" max-file: "3"
volumes: db_data:
secrets: db_user: file: ./secrets/db_user.txt db_password: file: ./secrets/db_password.txtStep 2: Create and Protect File-Backed Secrets
Create Local Secret Source Files
CredentialsRun these commands from the project directory containing compose.yaml. Compose grants the files to the database service at /run/secrets/. With a file: source, the files remain on the host; this is not the encrypted, in-memory secret store used by Docker Swarm. Keep the source files out of version control and restrict host access.
mkdir -p secretsumask 077printf '%s' 'compose_lab_user' > secrets/db_user.txtopenssl rand -base64 32 > secrets/db_password.txtchmod 0600 secrets/db_user.txt secrets/db_password.txt
# Add this line to the project's .gitignore.printf '%s\n' '/secrets/' >> .gitignoreβ― View Expected Console Output
$ ls -l secrets-rw------- 1 user user 16 Oct 5 10:00 db_user.txt-rw------- 1 user user 45 Oct 5 10:00 db_password.txtStep 3: Validate and Start the Stack
Start the Database and Check Its Health
DeploymentValidate the resolved Compose configuration before starting the service. Then wait for its health check and confirm the published port is limited to the local machine. βwait is available in recent Docker Compose v2 releases; if your version does not support it, check docker compose ps until the health status is healthy.
docker compose configdocker compose up -d --waitdocker compose psdocker compose exec db pg_isready \ -U "$(cat secrets/db_user.txt)" -d compose_labβ― View Expected Console Output
NAME IMAGE STATUS PORTScompose-lab-db-1 postgres:16-alpine Up 20 seconds (healthy) 127.0.0.1:5432->5432/tcp/var/run/postgresql:5432 - accepting connectionsStep 4: Inspect Logs and Resource Use
Check Bounded Logs and Container Resources
OperationsThe Compose service sets a maximum log file size and retention count. Inspect recent output and actual runtime resource use; limits constrain the container but do not prove that the database has enough capacity for its workload.
docker compose logs --tail=50 dbdocker stats --no-streamβ― View Expected Console Output
CONTAINER ID NAME CPU % MEM USAGE / LIMIT... compose-lab-db-1 0.20% 82MiB / 1GiBStep 5: Apply Image Updates Deliberately
Review and Roll Out an Approved Image Update
MaintenanceDo not automatically replace database images without checking the version and recovery plan. Before an approved update, take and verify a database backup, review the target image, and schedule any expected restart. A database major-version change may require a documented migration; changing the image tag alone is not that migration. This example does not promise a zero-downtime update. The Watchtower project is archived; use a maintained and reviewed update process instead.
# Review the current service and image reference.docker compose psdocker compose images
# After updating the approved image reference in compose.yaml:docker compose pull dbdocker compose up -d --wait dbdocker compose psdocker compose logs --tail=100 dbβ― View Expected Console Output
The database service is healthy after the planned restart.