compose-patterns-2025

Compare original and translation side by side

🇺🇸

Original

English
🇨🇳

Translation

Chinese

Docker Compose Patterns for Production (2025)

2025年Docker Compose生产环境模式

Overview

概述

This skill documents production-ready Docker Compose patterns and best practices for 2025, based on official Docker documentation and industry standards.
本文基于Docker官方文档及行业标准,记录了2025年适用于生产环境的Docker Compose模式与最佳实践。

File Format Changes (2025)

2025年文件格式变更

IMPORTANT: The
version
field is now obsolete in Docker Compose v2.42+.
Correct (2025):
yaml
services:
  app:
    image: myapp:latest
Incorrect (deprecated):
yaml
version: '3.8'  # DO NOT USE
services:
  app:
    image: myapp:latest
重要提示: 在Docker Compose v2.42+版本中,
version
字段已被弃用。
正确写法(2025年):
yaml
services:
  app:
    image: myapp:latest
错误写法(已废弃):
yaml
version: '3.8'  # 请勿使用
services:
  app:
    image: myapp:latest

Multiple Environment Strategy

多环境策略

Pattern: Base + Environment Overrides

模式:基础配置 + 环境覆盖

compose.yaml (base):
yaml
services:
  app:
    build:
      context: ./app
      dockerfile: Dockerfile
    environment:
      - NODE_ENV=production
    restart: unless-stopped
compose.override.yaml (development - auto-loaded):
yaml
services:
  app:
    build:
      target: development
    volumes:
      - ./app/src:/app/src:cached
    environment:
      - NODE_ENV=development
      - DEBUG=*
    ports:
      - "9229:9229"  # Debugger
compose.prod.yaml (production - explicit):
yaml
services:
  app:
    build:
      target: production
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: '1'
          memory: 512M
      restart_policy:
        condition: on-failure
        max_attempts: 3
Usage:
bash
undefined
compose.yaml(基础配置):
yaml
services:
  app:
    build:
      context: ./app
      dockerfile: Dockerfile
    environment:
      - NODE_ENV=production
    restart: unless-stopped
compose.override.yaml(开发环境 - 自动加载):
yaml
services:
  app:
    build:
      target: development
    volumes:
      - ./app/src:/app/src:cached
    environment:
      - NODE_ENV=development
      - DEBUG=*
    ports:
      - "9229:9229"  # 调试端口
compose.prod.yaml(生产环境 - 显式指定):
yaml
services:
  app:
    build:
      target: production
    deploy:
      replicas: 3
      resources:
        limits:
          cpus: '1'
          memory: 512M
      restart_policy:
        condition: on-failure
        max_attempts: 3
使用方式:
bash
undefined

Development (auto-loads compose.override.yaml)

开发环境(自动加载compose.override.yaml)

docker compose up
docker compose up

Production

生产环境

docker compose -f compose.yaml -f compose.prod.yaml up -d
docker compose -f compose.yaml -f compose.prod.yaml up -d

CI/CD

CI/CD环境

docker compose -f compose.yaml -f compose.ci.yaml up --abort-on-container-exit
undefined
docker compose -f compose.yaml -f compose.ci.yaml up --abort-on-container-exit
undefined

Environment Variable Management

环境变量管理

Pattern: .env Files per Environment

模式:按环境拆分.env文件

.env.template (committed to git):
bash
undefined
.env.template(提交至Git):
bash
undefined

Database

数据库

DB_HOST=sqlserver DB_PORT=1433 DB_NAME=myapp DB_USER=sa
DB_HOST=sqlserver DB_PORT=1433 DB_NAME=myapp DB_USER=sa

DB_PASSWORD= (set in actual .env)

DB_PASSWORD= (在实际.env文件中设置)

Redis

Redis

REDIS_HOST=redis REDIS_PORT=6379
REDIS_HOST=redis REDIS_PORT=6379

REDIS_PASSWORD= (set in actual .env)

REDIS_PASSWORD= (在实际.env文件中设置)

Application

应用程序

NODE_ENV=production LOG_LEVEL=info

**.env.dev:**
```bash
DB_PASSWORD=Dev!Pass123
REDIS_PASSWORD=redis-dev-123
NODE_ENV=development
LOG_LEVEL=debug
.env.prod:
bash
DB_PASSWORD=${PROD_DB_PASSWORD}  # From CI/CD
REDIS_PASSWORD=${PROD_REDIS_PASSWORD}
NODE_ENV=production
LOG_LEVEL=info
Load specific environment:
bash
docker compose --env-file .env.dev up
NODE_ENV=production LOG_LEVEL=info

**.env.dev:**
```bash
DB_PASSWORD=Dev!Pass123
REDIS_PASSWORD=redis-dev-123
NODE_ENV=development
LOG_LEVEL=debug
.env.prod:
bash
DB_PASSWORD=${PROD_DB_PASSWORD}  # 来自CI/CD环境
REDIS_PASSWORD=${PROD_REDIS_PASSWORD}
NODE_ENV=production
LOG_LEVEL=info
加载指定环境:
bash
docker compose --env-file .env.dev up

Security Patterns

安全模式

Pattern: Run as Non-Root User

模式:以非根用户运行

yaml
services:
  app:
    image: node:20-alpine
    user: "1000:1000"  # UID:GID
    read_only: true
    tmpfs:
      - /tmp
      - /app/.cache
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE  # Only if binding to ports < 1024
    security_opt:
      - no-new-privileges:true
Create user in Dockerfile:
dockerfile
FROM node:20-alpine
yaml
services:
  app:
    image: node:20-alpine
    user: "1000:1000"  # UID:GID
    read_only: true
    tmpfs:
      - /tmp
      - /app/.cache
    cap_drop:
      - ALL
    cap_add:
      - NET_BIND_SERVICE  # 仅当需要绑定1024以下端口时添加
    security_opt:
      - no-new-privileges:true
在Dockerfile中创建用户:
dockerfile
FROM node:20-alpine

Create app user

创建应用用户

RUN addgroup -g 1000 appuser &&
adduser -D -u 1000 -G appuser appuser
RUN addgroup -g 1000 appuser &&
adduser -D -u 1000 -G appuser appuser

Set ownership

设置目录权限

WORKDIR /app COPY --chown=appuser:appuser . .
USER appuser
undefined
WORKDIR /app COPY --chown=appuser:appuser . .
USER appuser
undefined

Pattern: Secrets Management

模式:密钥管理

Docker Swarm secrets (production):
yaml
services:
  app:
    secrets:
      - db_password
      - api_key

secrets:
  db_password:
    file: ./secrets/db_password.txt
  api_key:
    external: true  # Managed by Swarm
Access secrets in application:
javascript
// Read from /run/secrets/
const fs = require('fs');
const dbPassword = fs.readFileSync('/run/secrets/db_password', 'utf8').trim();
Development alternative (environment):
yaml
services:
  app:
    environment:
      - DB_PASSWORD_FILE=/run/secrets/db_password
Docker Swarm密钥(生产环境):
yaml
services:
  app:
    secrets:
      - db_password
      - api_key

secrets:
  db_password:
    file: ./secrets/db_password.txt
  api_key:
    external: true  # 由Swarm管理
在应用中访问密钥:
javascript
// 从/run/secrets/读取
const fs = require('fs');
const dbPassword = fs.readFileSync('/run/secrets/db_password', 'utf8').trim();
开发环境替代方案(环境变量):
yaml
services:
  app:
    environment:
      - DB_PASSWORD_FILE=/run/secrets/db_password

Health Check Patterns

健康检查模式

Pattern: Comprehensive Health Checks

模式:全面健康检查

HTTP endpoint:
yaml
services:
  web:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 40s
Database ping:
yaml
services:
  postgres:
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER"]
      interval: 10s
      timeout: 3s
      retries: 3
Custom script:
yaml
services:
  app:
    healthcheck:
      test: ["CMD", "node", "/app/scripts/healthcheck.js"]
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 40s
healthcheck.js:
javascript
const http = require('http');

const options = {
  hostname: 'localhost',
  port: 8080,
  path: '/health',
  timeout: 2000
};

const req = http.request(options, (res) => {
  process.exit(res.statusCode === 200 ? 0 : 1);
});

req.on('error', () => process.exit(1));
req.on('timeout', () => {
  req.destroy();
  process.exit(1);
});
req.end();
HTTP端点检查:
yaml
services:
  web:
    healthcheck:
      test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 40s
数据库连通性检查:
yaml
services:
  postgres:
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER"]
      interval: 10s
      timeout: 3s
      retries: 3
自定义脚本检查:
yaml
services:
  app:
    healthcheck:
      test: ["CMD", "node", "/app/scripts/healthcheck.js"]
      interval: 30s
      timeout: 3s
      retries: 3
      start_period: 40s
healthcheck.js:
javascript
const http = require('http');

const options = {
  hostname: 'localhost',
  port: 8080,
  path: '/health',
  timeout: 2000
};

const req = http.request(options, (res) => {
  process.exit(res.statusCode === 200 ? 0 : 1);
});

req.on('error', () => process.exit(1));
req.on('timeout', () => {
  req.destroy();
  process.exit(1);
});
req.end();

Dependency Management

依赖管理

Pattern: Ordered Startup with Conditions

模式:带条件的有序启动

yaml
services:
  web:
    depends_on:
      database:
        condition: service_healthy
      redis:
        condition: service_started
      migration:
        condition: service_completed_successfully

  database:
    healthcheck:
      test: ["CMD-SHELL", "pg_isready"]
      interval: 10s

  redis:
    # No health check needed, just wait for start

  migration:
    image: myapp:latest
    command: npm run migrate
    restart: "no"  # Run once
    depends_on:
      database:
        condition: service_healthy
yaml
services:
  web:
    depends_on:
      database:
        condition: service_healthy
      redis:
        condition: service_started
      migration:
        condition: service_completed_successfully

  database:
    healthcheck:
      test: ["CMD-SHELL", "pg_isready"]
      interval: 10s

  redis:
    # 无需健康检查,只需等待启动完成

  migration:
    image: myapp:latest
    command: npm run migrate
    restart: "no"  # 仅运行一次
    depends_on:
      database:
        condition: service_healthy

Network Isolation Patterns

网络隔离模式

Pattern: Three-Tier Network Architecture

模式:三层网络架构

yaml
services:
  nginx:
    image: nginx:alpine
    networks:
      - frontend
    ports:
      - "80:80"

  api:
    build: ./api
    networks:
      - frontend
      - backend

  database:
    image: postgres:16-alpine
    networks:
      - backend  # No frontend access

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true  # No external access
yaml
services:
  nginx:
    image: nginx:alpine
    networks:
      - frontend
    ports:
      - "80:80"

  api:
    build: ./api
    networks:
      - frontend
      - backend

  database:
    image: postgres:16-alpine
    networks:
      - backend  # 禁止前端访问

networks:
  frontend:
    driver: bridge
  backend:
    driver: bridge
    internal: true  # 禁止外部访问

Pattern: Service-Specific Networks

模式:服务专属网络

yaml
services:
  web-app:
    networks:
      - public
      - app-network

  api:
    networks:
      - app-network
      - data-network

  postgres:
    networks:
      - data-network

  redis:
    networks:
      - data-network

networks:
  public:
    driver: bridge
  app-network:
    driver: bridge
    internal: true
  data-network:
    driver: bridge
    internal: true
yaml
services:
  web-app:
    networks:
      - public
      - app-network

  api:
    networks:
      - app-network
      - data-network

  postgres:
    networks:
      - data-network

  redis:
    networks:
      - data-network

networks:
  public:
    driver: bridge
  app-network:
    driver: bridge
    internal: true
  data-network:
    driver: bridge
    internal: true

Volume Patterns

卷管理模式

Pattern: Named Volumes for Persistence

模式:命名卷持久化

yaml
services:
  database:
    volumes:
      - db-data:/var/lib/postgresql/data  # Persistent data
      - ./init:/docker-entrypoint-initdb.d:ro  # Init scripts (read-only)
      - db-logs:/var/log/postgresql  # Logs

volumes:
  db-data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /mnt/data/postgres  # Host path
  db-logs:
    driver: local
yaml
services:
  database:
    volumes:
      - db-data:/var/lib/postgresql/data  # 持久化数据
      - ./init:/docker-entrypoint-initdb.d:ro  # 初始化脚本(只读)
      - db-logs:/var/log/postgresql  # 日志存储

volumes:
  db-data:
    driver: local
    driver_opts:
      type: none
      o: bind
      device: /mnt/data/postgres  # 宿主机路径
  db-logs:
    driver: local

Pattern: Development Bind Mounts

模式:开发环境绑定挂载

yaml
services:
  app:
    volumes:
      - ./src:/app/src:cached  # macOS optimization
      - /app/node_modules  # Don't overwrite installed modules
      - app-cache:/app/.cache  # Named volume for cache
Volume mount options:
  • :ro
    - Read-only
  • :rw
    - Read-write (default)
  • :cached
    - macOS performance optimization (host authoritative)
  • :delegated
    - macOS performance optimization (container authoritative)
  • :z
    - SELinux single container
  • :Z
    - SELinux multi-container
yaml
services:
  app:
    volumes:
      - ./src:/app/src:cached  # macOS性能优化
      - /app/node_modules  # 不覆盖已安装的依赖
      - app-cache:/app/.cache  # 缓存使用命名卷
卷挂载选项:
  • :ro
    - 只读
  • :rw
    - 读写(默认)
  • :cached
    - macOS性能优化(宿主机优先)
  • :delegated
    - macOS性能优化(容器优先)
  • :z
    - SELinux单容器模式
  • :Z
    - SELinux多容器模式

Resource Management Patterns

资源管理模式

Pattern: CPU and Memory Limits

模式:CPU与内存限制

yaml
services:
  app:
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M
Calculate total resources:
yaml
undefined
yaml
services:
  app:
    deploy:
      resources:
        limits:
          cpus: '1.0'
          memory: 512M
        reservations:
          cpus: '0.5'
          memory: 256M
计算总资源需求:
yaml
undefined

3 app replicas + database + redis

3个app副本 + 数据库 + Redis

services: app: deploy: replicas: 3 resources: limits: cpus: '0.5' # 3 x 0.5 = 1.5 CPUs memory: 512M # 3 x 512M = 1.5GB
database: deploy: resources: limits: cpus: '2' # 2 CPUs memory: 4G # 4GB
redis: deploy: resources: limits: cpus: '0.5' # 0.5 CPUs memory: 512M # 512MB
services: app: deploy: replicas: 3 resources: limits: cpus: '0.5' # 3 × 0.5 = 1.5核CPU memory: 512M # 3 × 512M = 1.5GB内存
database: deploy: resources: limits: cpus: '2' # 2核CPU memory: 4G # 4GB内存
redis: deploy: resources: limits: cpus: '0.5' # 0.5核CPU memory: 512M # 512MB内存

Total: 4 CPUs, 6GB RAM minimum

总计:至少需要4核CPU,6GB内存

undefined
undefined

Logging Patterns

日志模式

Pattern: Centralized Logging

模式:集中式日志

yaml
services:
  app:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
        compress: "true"
        labels: "app,environment"
Alternative: Log to stdout/stderr (12-factor):
yaml
services:
  app:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
View logs:
bash
docker compose logs -f app
docker compose logs --since 30m app
docker compose logs --tail 100 app
yaml
services:
  app:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
        compress: "true"
        labels: "app,environment"
替代方案:输出至stdout/stderr(12要素原则):
yaml
services:
  app:
    logging:
      driver: "json-file"
      options:
        max-size: "10m"
        max-file: "3"
查看日志:
bash
docker compose logs -f app
docker compose logs --since 30m app
docker compose logs --tail 100 app

Init Container Pattern

初始化容器模式

Pattern: Database Migration

模式:数据库迁移

yaml
services:
  migration:
    image: myapp:latest
    command: npm run migrate
    depends_on:
      database:
        condition: service_healthy
    restart: "no"  # Run once
    networks:
      - backend

  app:
    image: myapp:latest
    depends_on:
      migration:
        condition: service_completed_successfully
    networks:
      - backend
yaml
services:
  migration:
    image: myapp:latest
    command: npm run migrate
    depends_on:
      database:
        condition: service_healthy
    restart: "no"  # 仅运行一次
    networks:
      - backend

  app:
    image: myapp:latest
    depends_on:
      migration:
        condition: service_completed_successfully
    networks:
      - backend

YAML Anchors and Aliases

YAML锚点与别名

Pattern: Reusable Configuration

模式:可复用配置

yaml
x-common-app-config: &common-app
  restart: unless-stopped
  logging:
    driver: "json-file"
    options:
      max-size: "10m"
      max-file: "3"
  security_opt:
    - no-new-privileges:true
  cap_drop:
    - ALL
  cap_add:
    - NET_BIND_SERVICE

services:
  app1:
    <<: *common-app
    build: ./app1
    ports:
      - "8001:8080"

  app2:
    <<: *common-app
    build: ./app2
    ports:
      - "8002:8080"

  app3:
    <<: *common-app
    build: ./app3
    ports:
      - "8003:8080"
yaml
x-common-app-config: &common-app
  restart: unless-stopped
  logging:
    driver: "json-file"
    options:
      max-size: "10m"
      max-file: "3"
  security_opt:
    - no-new-privileges:true
  cap_drop:
    - ALL
  cap_add:
    - NET_BIND_SERVICE

services:
  app1:
    <<: *common-app
    build: ./app1
    ports:
      - "8001:8080"

  app2:
    <<: *common-app
    build: ./app2
    ports:
      - "8002:8080"

  app3:
    <<: *common-app
    build: ./app3
    ports:
      - "8003:8080"

Pattern: Environment-Specific Overrides

模式:按环境覆盖配置

yaml
x-logging: &default-logging
  driver: "json-file"
  options:
    max-size: "10m"
    max-file: "3"

x-resources: &default-resources
  limits:
    cpus: '1'
    memory: 512M
  reservations:
    cpus: '0.5'
    memory: 256M

services:
  app:
    logging: *default-logging
    deploy:
      resources: *default-resources
yaml
x-logging: &default-logging
  driver: "json-file"
  options:
    max-size: "10m"
    max-file: "3"

x-resources: &default-resources
  limits:
    cpus: '1'
    memory: 512M
  reservations:
    cpus: '0.5'
    memory: 256M

services:
  app:
    logging: *default-logging
    deploy:
      resources: *default-resources

Port Binding Patterns

端口绑定模式

Pattern: Security-First Port Binding

模式:安全优先的端口绑定

yaml
services:
  # Public services
  web:
    ports:
      - "80:8080"
      - "443:8443"

  # Development only (localhost binding)
  debug:
    ports:
      - "127.0.0.1:9229:9229"  # Debugger only accessible from host

  # Environment-based binding
  app:
    ports:
      - "${DOCKER_WEB_PORT_FORWARD:-127.0.0.1:8000}:8000"
Environment control:
bash
undefined
yaml
services:
  # 公开服务
  web:
    ports:
      - "80:8080"
      - "443:8443"

  # 仅开发环境使用(绑定localhost)
  debug:
    ports:
      - "127.0.0.1:9229:9229"  # 调试端口仅允许宿主机访问

  # 基于环境的动态绑定
  app:
    ports:
      - "${DOCKER_WEB_PORT_FORWARD:-127.0.0.1:8000}:8000"
环境变量控制:
bash
undefined

Development (.env.dev)

开发环境(.env.dev)

DOCKER_WEB_PORT_FORWARD=127.0.0.1:8000 # Localhost only
DOCKER_WEB_PORT_FORWARD=127.0.0.1:8000 # 仅允许本地访问

Production (.env.prod)

生产环境(.env.prod)

DOCKER_WEB_PORT_FORWARD=8000 # All interfaces
undefined
DOCKER_WEB_PORT_FORWARD=8000 # 允许所有接口访问
undefined

Restart Policy Patterns

重启策略模式

yaml
services:
  # Always restart (production services)
  app:
    restart: always

  # Restart unless manually stopped (most common)
  database:
    restart: unless-stopped

  # Never restart (one-time tasks)
  migration:
    restart: "no"

  # Restart on failure only (with Swarm)
  worker:
    deploy:
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
        window: 120s
yaml
services:
  # 始终重启(生产环境服务)
  app:
    restart: always

  # 除非手动停止,否则重启(最常用)
  database:
    restart: unless-stopped

  # 从不重启(一次性任务)
  migration:
    restart: "no"

  # 仅在失败时重启(Swarm环境)
  worker:
    deploy:
      restart_policy:
        condition: on-failure
        delay: 5s
        max_attempts: 3
        window: 120s

Validation and Testing

验证与测试

Pattern: Pre-Deployment Validation

模式:部署前验证

bash
#!/bin/bash
set -euo pipefail

echo "Validating Compose syntax..."
docker compose config > /dev/null

echo "Building images..."
docker compose build

echo "Running security scan..."
for service in $(docker compose config --services); do
  image=$(docker compose config | yq ".services.$service.image")
  if [ -n "$image" ]; then
    docker scout cves "$image" || true
  fi
done

echo "Starting services..."
docker compose up -d

echo "Checking health..."
sleep 10
docker compose ps

echo "Running smoke tests..."
curl -f http://localhost:8080/health || exit 1

echo "✓ All checks passed"
bash
#!/bin/bash
set -euo pipefail

echo "验证Compose语法..."
docker compose config > /dev/null

echo "构建镜像..."
docker compose build

echo "运行安全扫描..."
for service in $(docker compose config --services); do
  image=$(docker compose config | yq ".services.$service.image")
  if [ -n "$image" ]; then
    docker scout cves "$image" || true
  fi
done

echo "启动服务..."
docker compose up -d

echo "检查健康状态..."
sleep 10
docker compose ps

echo "运行冒烟测试..."
curl -f http://localhost:8080/health || exit 1

echo "✓ 所有检查通过"

Complete Production Example

完整生产环境示例

yaml
undefined
yaml
undefined

Modern Compose format (no version field for v2.40+)

新版Compose格式(v2.40+无需version字段)

x-common-service: &common-service restart: unless-stopped logging: driver: "json-file" options: max-size: "10m" max-file: "3" security_opt: - no-new-privileges:true
services: nginx: <<: *common-service image: nginxinc/nginx-unprivileged:alpine ports: - "80:8080" volumes: - ./nginx/conf.d:/etc/nginx/conf.d:ro networks: - frontend depends_on: api: condition: service_healthy healthcheck: test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/health"] interval: 30s
api: <<: *common-service build: context: ./api dockerfile: Dockerfile target: production user: "1000:1000" read_only: true tmpfs: - /tmp cap_drop: - ALL cap_add: - NET_BIND_SERVICE networks: - frontend - backend depends_on: migration: condition: service_completed_successfully redis: condition: service_started env_file: - .env healthcheck: test: ["CMD", "node", "healthcheck.js"] interval: 30s start_period: 40s deploy: resources: limits: cpus: '1' memory: 512M
migration: image: myapp:latest command: npm run migrate restart: "no" networks: - backend depends_on: postgres: condition: service_healthy
postgres: <<: *common-service image: postgres:16-alpine environment: - POSTGRES_PASSWORD_FILE=/run/secrets/postgres_password secrets: - postgres_password volumes: - postgres-data:/var/lib/postgresql/data networks: - backend healthcheck: test: ["CMD-SHELL", "pg_isready"] interval: 10s deploy: resources: limits: cpus: '1' memory: 2G
redis: <<: *common-service image: redis:7.4-alpine command: redis-server --requirepass ${REDIS_PASSWORD} volumes: - redis-data:/data networks: - backend healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s
networks: frontend: driver: bridge backend: driver: bridge internal: true
volumes: postgres-data: driver: local redis-data: driver: local
secrets: postgres_password: file: ./secrets/postgres_password.txt
undefined
x-common-service: &common-service restart: unless-stopped logging: driver: "json-file" options: max-size: "10m" max-file: "3" security_opt: - no-new-privileges:true
services: nginx: <<: *common-service image: nginxinc/nginx-unprivileged:alpine ports: - "80:8080" volumes: - ./nginx/conf.d:/etc/nginx/conf.d:ro networks: - frontend depends_on: api: condition: service_healthy healthcheck: test: ["CMD", "wget", "--quiet", "--tries=1", "--spider", "http://localhost:8080/health"] interval: 30s
api: <<: *common-service build: context: ./api dockerfile: Dockerfile target: production user: "1000:1000" read_only: true tmpfs: - /tmp cap_drop: - ALL cap_add: - NET_BIND_SERVICE networks: - frontend - backend depends_on: migration: condition: service_completed_successfully redis: condition: service_started env_file: - .env healthcheck: test: ["CMD", "node", "healthcheck.js"] interval: 30s start_period: 40s deploy: resources: limits: cpus: '1' memory: 512M
migration: image: myapp:latest command: npm run migrate restart: "no" networks: - backend depends_on: postgres: condition: service_healthy
postgres: <<: *common-service image: postgres:16-alpine environment: - POSTGRES_PASSWORD_FILE=/run/secrets/postgres_password secrets: - postgres_password volumes: - postgres-data:/var/lib/postgresql/data networks: - backend healthcheck: test: ["CMD-SHELL", "pg_isready"] interval: 10s deploy: resources: limits: cpus: '1' memory: 2G
redis: <<: *common-service image: redis:7.4-alpine command: redis-server --requirepass ${REDIS_PASSWORD} volumes: - redis-data:/data networks: - backend healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 10s
networks: frontend: driver: bridge backend: driver: bridge internal: true
volumes: postgres-data: driver: local redis-data: driver: local
secrets: postgres_password: file: ./secrets/postgres_password.txt
undefined

Common Mistakes to Avoid

常见错误规避

  1. Using
    version
    field
    - Obsolete in 2025
  2. No health checks - Leads to race conditions
  3. Running as root - Security risk
  4. No resource limits - Can exhaust host resources
  5. Hardcoded secrets - Use secrets or environment variables
  6. No logging limits - Disk space issues
  7. Bind mounts in production - Use named volumes
  8. Missing restart policies - Services don't recover
  9. No network isolation - All services can talk to each other
  10. Not using .dockerignore - Larger build contexts
  1. 使用
    version
    字段
    - 2025年已废弃
  2. 未配置健康检查 - 会导致启动竞争问题
  3. 以根用户运行 - 存在安全风险
  4. 未设置资源限制 - 可能耗尽宿主机资源
  5. 硬编码密钥 - 应使用密钥管理或环境变量
  6. 未设置日志限制 - 可能导致磁盘空间不足
  7. 生产环境使用绑定挂载 - 应使用命名卷
  8. 缺失重启策略 - 服务故障后无法自动恢复
  9. 未做网络隔离 - 所有服务可互相访问
  10. 未使用.dockerignore - 构建上下文过大

Troubleshooting Commands

故障排查命令

bash
undefined
bash
undefined

Validate syntax

验证语法

docker compose config
docker compose config

View merged configuration

查看合并后的配置

docker compose config --services
docker compose config --services

Check which file is being used

检查正在使用的配置文件

docker compose config --files
docker compose config --files

View environment interpolation

查看未插值的环境变量

docker compose config --no-interpolate
docker compose config --no-interpolate

Check service dependencies

检查服务依赖关系

docker compose config | yq '.services.*.depends_on'
docker compose config | yq '.services.*.depends_on'

View resource usage

查看资源使用情况

docker stats $(docker compose ps -q)
docker stats $(docker compose ps -q)

Debug startup issues

调试启动问题

docker compose up --no-deps service-name
docker compose up --no-deps service-name

Force recreate

强制重新创建容器

docker compose up --force-recreate service-name
undefined
docker compose up --force-recreate service-name
undefined

References

参考资料