Docker Compose 服务配置详解
概述
在 Docker Compose 中,services 是配置文件的核心部分,定义了应用程序中的各个服务。本文将深入探讨服务配置的各个方面,包括镜像配置、端口映射、卷挂载、环境变量等。
服务定义基础
基本服务结构
version: '3.8'
services:
service_name:
# 服务配置选项
image: image_name:tag
container_name: custom_container_name
restart: always
镜像配置
1. 使用现有镜像
services:
web:
image: nginx:1.21-alpine
database:
image: postgres:13
cache:
image: redis:6-alpine
2. 构建自定义镜像
简单构建
services:
app:
build: . # 使用当前目录的 Dockerfile
详细构建配置
services:
app:
build:
context: ./app # 构建上下文目录
dockerfile: Dockerfile.prod # 指定 Dockerfile
args: # 构建参数
- NODE_ENV=production
- API_URL=https://api.example.com
target: production # 多阶段构建目标
cache_from: # 缓存来源
- myapp:latest
labels: # 镜像标签
- "com.example.version=1.0"
- "com.example.environment=production"
构建参数示例
# Dockerfile
FROM node:14-alpine
ARG NODE_ENV=development
ARG API_URL=http://localhost:3000
ENV NODE_ENV=$NODE_ENV
ENV REACT_APP_API_URL=$API_URL
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
EXPOSE 3000
CMD ["npm", "start"]
端口映射
1. 基本端口映射
services:
web:
image: nginx
ports:
- "80:80" # 主机端口:容器端口
- "443:443"
- "8080:80" # 映射到不同端口
2. 高级端口配置
services:
web:
image: nginx
ports:
- "80:80" # 绑定到所有接口
- "127.0.0.1:8080:80" # 绑定到特定 IP
- "8000-8010:8000-8010" # 端口范围映射
- target: 80 # 长格式配置
published: 8080
protocol: tcp
mode: host
3. 暴露端口(不映射到主机)
services:
api:
image: myapi
expose:
- "3000" # 只在容器间可访问
- "3001"
卷挂载配置
1. 绑定挂载
services:
web:
image: nginx
volumes:
- ./html:/usr/share/nginx/html:ro # 只读挂载
- ./config:/etc/nginx/conf.d:rw # 读写挂载(默认)
- /var/log/nginx:/var/log/nginx # 绝对路径挂载
2. 命名卷
version: '3.8'
services:
database:
image: postgres:13
volumes:
- postgres_data:/var/lib/postgresql/data
- postgres_backup:/backup
volumes:
postgres_data:
driver: local
postgres_backup:
driver: local
driver_opts:
type: none
o: bind
device: /host/backup/path
3. 临时文件系统
services:
app:
image: myapp
tmpfs:
- /tmp
- /var/cache
# 或使用长格式
tmpfs:
- type: tmpfs
target: /tmp
tmpfs:
size: 100M
4. 高级卷配置
services:
app:
image: myapp
volumes:
- type: bind
source: ./app
target: /usr/src/app
read_only: true
- type: volume
source: data_volume
target: /data
volume:
nocopy: true
- type: tmpfs
target: /tmp
tmpfs:
size: 100M
mode: 1777
volumes:
data_volume:
环境变量配置
1. 直接定义环境变量
services:
app:
image: myapp
environment:
- NODE_ENV=production
- DATABASE_URL=postgresql://user:pass@db:5432/mydb
- DEBUG=false
# 或使用映射格式
environment:
NODE_ENV: production
DATABASE_URL: postgresql://user:pass@db:5432/mydb
DEBUG: "false" # 注意:所有值都是字符串
2. 从文件加载环境变量
services:
app:
image: myapp
env_file:
- .env
- .env.local
- ./config/.env.production
.env 文件示例
# .env
NODE_ENV=production
DATABASE_URL=postgresql://user:password@db:5432/mydb
REDIS_URL=redis://redis:6379
SECRET_KEY=your-secret-key
DEBUG=false
3. 环境变量优先级
- Compose 文件中的
environment - Shell 环境变量
env_file中的变量- Dockerfile 中的
ENV
网络配置
1. 默认网络
services:
web:
image: nginx
api:
image: myapi
# 默认情况下,所有服务都在同一个网络中
2. 自定义网络
version: '3.8'
services:
web:
image: nginx
networks:
- frontend
api:
image: myapi
networks:
- frontend
- backend
database:
image: postgres
networks:
- backend
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 内部网络,不能访问外部
3. 网络别名
services:
api:
image: myapi
networks:
backend:
aliases:
- api-server
- backend-api
networks:
backend:
4. 外部网络
services:
app:
image: myapp
networks:
- existing_network
networks:
existing_network:
external: true
依赖关系配置
1. 基本依赖
services:
web:
image: nginx
depends_on:
- api
- database
api:
image: myapi
depends_on:
- database
- redis
database:
image: postgres
redis:
image: redis
2. 条件依赖(需要 Compose 文件版本 2.1)
version: '2.1'
services:
web:
image: nginx
depends_on:
api:
condition: service_healthy
database:
condition: service_started
api:
image: myapi
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:3000/health"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
database:
image: postgres
资源限制
1. 内存和 CPU 限制
services:
app:
image: myapp
deploy:
resources:
limits:
cpus: '0.5' # 限制 CPU 使用
memory: 512M # 限制内存使用
reservations:
cpus: '0.25' # 保留 CPU
memory: 256M # 保留内存
2. 设备限制
services:
app:
image: myapp
deploy:
resources:
limits:
devices:
- driver: nvidia
count: 1
capabilities: [gpu]
健康检查
services:
web:
image: nginx
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 30s # 检查间隔
timeout: 10s # 超时时间
retries: 3 # 重试次数
start_period: 40s # 启动等待时间
disable: false # 是否禁用健康检查
api:
image: myapi
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:3000/health || exit 1"]
interval: 1m
timeout: 30s
retries: 5
start_period: 30s
重启策略
services:
web:
image: nginx
restart: always # 总是重启
api:
image: myapi
restart: unless-stopped # 除非手动停止
worker:
image: myworker
restart: on-failure # 失败时重启
temp:
image: temp-service
restart: "no" # 不重启(默认)
日志配置
services:
web:
image: nginx
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
api:
image: myapi
logging:
driver: "syslog"
options:
syslog-address: "tcp://192.168.1.42:123"
tag: "api-service"
app:
image: myapp
logging:
driver: "none" # 禁用日志
安全配置
1. 用户和权限
services:
app:
image: myapp
user: "1000:1000" # 指定用户 ID 和组 ID
# user: "username" # 或使用用户名
# 只读根文件系统
read_only: true
tmpfs:
- /tmp
- /var/cache
# 权限控制
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
# 安全选项
security_opt:
- no-new-privileges:true
- apparmor:unconfined
2. 特权和设备
services:
privileged_app:
image: myapp
privileged: true # 特权模式(谨慎使用)
device_app:
image: myapp
devices:
- "/dev/sda:/dev/xvda:rwm" # 设备映射
完整示例:Web 应用栈
version: '3.8'
services:
# 反向代理
nginx:
image: nginx:alpine
container_name: web-proxy
ports:
- "80:80"
- "443:443"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/ssl:/etc/nginx/ssl:ro
- static_files:/usr/share/nginx/html/static:ro
depends_on:
- web
networks:
- frontend
restart: unless-stopped
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# Web 应用
web:
build:
context: ./web
dockerfile: Dockerfile.prod
args:
- NODE_ENV=production
container_name: web-app
environment:
- NODE_ENV=production
- API_URL=http://api:3000
- REDIS_URL=redis://redis:6379
env_file:
- .env.production
volumes:
- static_files:/app/static
depends_on:
- api
- redis
networks:
- frontend
- backend
restart: unless-stopped
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8000/health"]
interval: 30s
timeout: 10s
retries: 3
deploy:
resources:
limits:
memory: 512M
reservations:
memory: 256M
# API 服务
api:
build:
context: ./api
target: production
container_name: api-server
environment:
DATABASE_URL: postgresql://postgres:password@db:5432/myapp
REDIS_URL: redis://redis:6379
depends_on:
- db
- redis
networks:
- backend
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "curl -f http://localhost:3000/api/health || exit 1"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
# 数据库
db:
image: postgres:13-alpine
container_name: postgres-db
environment:
POSTGRES_DB: myapp
POSTGRES_USER: postgres
POSTGRES_PASSWORD: password
volumes:
- postgres_data:/var/lib/postgresql/data
- ./db/init.sql:/docker-entrypoint-initdb.d/init.sql:ro
networks:
- backend
restart: unless-stopped
healthcheck:
test: ["CMD-SHELL", "pg_isready -U postgres"]
interval: 10s
timeout: 5s
retries: 5
# 缓存
redis:
image: redis:6-alpine
container_name: redis-cache
command: redis-server --appendonly yes --requirepass mypassword
volumes:
- redis_data:/data
networks:
- backend
restart: unless-stopped
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 3
# 卷定义
volumes:
postgres_data:
driver: local
redis_data:
driver: local
static_files:
driver: local
# 网络定义
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true
最佳实践
1. 服务设计原则
- 单一职责: 每个服务只负责一个功能
- 无状态: 尽量设计无状态服务
- 松耦合: 服务间通过网络通信,避免文件系统依赖
2. 配置管理
- 使用环境变量管理配置
- 敏感信息使用 secrets 或外部配置管理
- 不同环境使用不同的 compose 文件
3. 资源优化
- 合理设置资源限制
- 使用多阶段构建减小镜像大小
- 选择合适的基础镜像(如 alpine)
4. 安全考虑
- 不使用 root 用户运行应用
- 启用只读文件系统
- 最小化容器权限
- 定期更新基础镜像
总结
Docker Compose 服务配置提供了丰富的选项来定义和管理容器化应用程序。通过合理配置镜像、端口、卷、网络、环境变量等,可以构建出稳定、安全、高效的多容器应用系统。掌握这些配置选项是使用 Docker Compose 的基础。