关于 compose-patterns-2025
一份面向生产环境的 Docker Compose 配置参考技能,帮助开发者规划多环境部署,并涵盖安全、健康检查、网络、资源和运维实践。
主要功能
- 01基础配置与环境覆盖模式
- 02按环境区分变量文件
- 03非 root 用户与密钥管理模式
- 04健康检查与依赖条件
- 05网络、卷和资源配置
- 06日志、验证与故障排查
适用场景
- 01区分开发、CI 和生产环境配置
- 02降低容器访问与密钥处理风险
- 03设置服务就绪检查和启动顺序
- 04为部署准备 Compose 文件
安装
复制下面的命令,在终端中运行。
$
npx skills add https:/ / github.com/ josiahsiegel/ claude-plugin-marketplace --skill compose-patterns-2025安装后在 Claude Code 中输入/compose-patterns-2025确认已加载。
详细介绍
2025 年生产环境 Docker Compose 模式
概述
本文档介绍了适用于 2025 年的生产就绪 Docker Compose 模式和最佳实践,内容基于 Docker 官方文档和行业标准。
文件格式变更(2025 年)
重要: 在 Docker Compose v2.42+ 中,version 字段现已弃用。
正确写法(2025 年):
services:
app:
image: myapp:latest
错误写法(已弃用):
version: '3.8' # DO NOT USE
services:
app:
image: myapp:latest
多环境策略
模式:基础配置 + 环境覆盖
compose.yaml(基础配置):
services:
app:
build:
context: ./app
dockerfile: Dockerfile
environment:
- NODE_ENV=production
restart: unless-stopped
compose.override.yaml(开发环境 - 自动加载):
services:
app:
build:
target: development
volumes:
- ./app/src:/app/src:cached
environment:
- NODE_ENV=development
- DEBUG=*
ports:
- "9229:9229" # Debugger
compose.prod.yaml(生产环境 - 显式指定):
services:
app:
build:
target: production
deploy:
replicas: 3
resources:
limits:
cpus: '1'
memory: 512M
restart_policy:
condition: on-failure
max_attempts: 3
用法:
# Development (auto-loads compose.override.yaml)
docker compose up
# Production
docker compose -f compose.yaml -f compose.prod.yaml up -d
# CI/CD
docker compose -f compose.yaml -f compose.ci.yaml up --abort-on-container-exit
环境变量管理
模式:每个环境使用单独的 .env 文件
.env.template(提交到 git):
# Database
DB_HOST=sqlserver
DB_PORT=1433
DB_NAME=myapp
DB_USER=sa
# DB_PASSWORD= (set in actual .env)
# Redis
REDIS_HOST=redis
REDIS_PORT=6379
# REDIS_PASSWORD= (set in actual .env)
# Application
NODE_ENV=production
LOG_LEVEL=info
.env.dev:
DB_PASSWORD=Dev!Pass123
REDIS_PASSWORD=redis-dev-123
NODE_ENV=development
LOG_LEVEL=debug
.env.prod:
DB_PASSWORD=${PROD_DB_PASSWORD} # From CI/CD
REDIS_PASSWORD=${PROD_REDIS_PASSWORD}
NODE_ENV=production
LOG_LEVEL=info
加载指定环境:
docker compose --env-file .env.dev up
安全模式
模式:以非 root 用户身份运行
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
在 Dockerfile 中创建用户:
FROM node:20-alpine
# Create app user
RUN addgroup -g 1000 appuser && \
adduser -D -u 1000 -G appuser appuser
# Set ownership
WORKDIR /app
COPY --chown=appuser:appuser . .
USER appuser
模式:密钥管理
Docker Swarm 密钥(生产环境):
services:
app:
secrets:
- db_password
- api_key
secrets:
db_password:
file: ./secrets/db_password.txt
api_key:
external: true # Managed by Swarm
在应用程序中访问密钥:
// Read from /run/secrets/
const fs = require('fs');
const dbPassword = fs.readFileSync('/run/secrets/db_password', 'utf8').trim();
开发环境替代方案(环境变量):
services:
app:
environment:
- DB_PASSWORD_FILE=/run/secrets/db_password
健康检查模式
模式:全面的健康检查
HTTP 端点:
services:
web:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/health"]
interval: 30s
timeout: 3s
retries: 3
start_period: 40s
数据库 ping:
services:
postgres:
healthcheck:
test: ["CMD-SHELL", "pg_isready -U $$POSTGRES_USER"]
interval: 10s
timeout: 3s
retries: 3
自定义脚本:
services:
app:
healthcheck:
test: ["CMD", "node", "/app/scripts/healthcheck.js"]
interval: 30s
timeout: 3s
retries: 3
start_period: 40s
healthcheck.js:
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();
依赖管理
模式:按条件控制启动顺序
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
网络隔离模式
模式:三层网络架构
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
模式:服务专用网络
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
卷模式
模式:使用命名卷实现持久化
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
模式:开发环境绑定挂载
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
卷挂载选项:
:ro- 只读:rw- 读写(默认):cached- macOS 性能优化(以主机为准):delegated- macOS 性能优化(以容器为准):z- SELinux 单容器:Z- SELinux 多容器
资源管理模式
模式:CPU 和内存限制
services:
app:
deploy:
resources:
limits:
cpus: '1.0'
memory: 512M
reservations:
cpus: '0.5'
memory: 256M
计算资源总量:
# 3 app replicas + database + 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
# Total: 4 CPUs, 6GB RAM minimum
日志模式
模式:集中式日志记录
services:
app:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
compress: "true"
labels: "app,environment"
替代方案:将日志输出到 stdout/stderr(12 因子):
services:
app:
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
查看日志:
docker compose logs -f app
docker compose logs --since 30m app
docker compose logs --tail 100 app
初始化容器模式
模式:数据库迁移
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 锚点和别名
模式:可复用配置
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"
模式:特定环境的覆盖配置
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
端口绑定模式
模式:安全优先的端口绑定
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"
环境控制:
# Development (.env.dev)
DOCKER_WEB_PORT_FORWARD=127.0.0.1:8000 # Localhost only
# Production (.env.prod)
DOCKER_WEB_PORT_FORWARD=8000 # All interfaces
重启策略模式
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
验证和测试
模式:部署前验证
#!/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"
完整的生产环境示例
# Modern Compose format (no version field for v2.40+)
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
应避免的常见错误
- 使用
version字段 - 2025 年已弃用 - 没有健康检查 - 会导致竞态条件
- 以 root 身份运行 - 存在安全风险
- 没有资源限制 - 可能耗尽主机资源
- 硬编码密钥 - 使用密钥或环境变量
- 没有日志限制 - 可能导致磁盘空间问题
- 在生产环境中使用绑定挂载 - 改用命名卷
- 缺少重启策略 - 服务无法恢复
- 没有网络隔离 - 所有服务都可以相互通信
- 未使用 .dockerignore - 构建上下文更大
故障排除命令
# Validate syntax
docker compose config
# View merged configuration
docker compose config --services
# Check which file is being used
docker compose config --files
# View environment interpolation
docker compose config --no-interpolate
# Check service dependencies
docker compose config | yq '.services.*.depends_on'
# View resource usage
docker stats $(docker compose ps -q)
# Debug startup issues
docker compose up --no-deps service-name
# Force recreate
docker compose up --force-recreate service-name
参考资料
评论
支持 Markdown