引言
Docker Compose 用一个 YAML 文件描述多容器应用的服务、网络、数据卷和依赖关系。本文以当前的 Compose 插件和 docker compose 命令为准,从本地开发讲到生产检查;旧版独立命令 docker-compose 只用于兼容历史环境。
目录
什么是Docker Compose
Docker Compose是一个用于定义和运行多容器Docker应用程序的工具。它使用YAML文件来配置应用程序的服务、网络和卷,使开发人员能够在一个地方定义和管理多个容器。通过简单的命令,您可以创建和启动配置中定义的所有服务,极大地简化了容器化应用的开发和部署流程。
安装Docker Compose
安装Docker Compose
Docker Desktop 已内置 Compose。已经通过 Docker 官方仓库安装 Engine 与 CLI 的 Debian / Ubuntu 用户,可以安装 Compose 插件:
sudo apt-get update
sudo apt-get install docker-compose-plugin
其他系统和手动安装方式请参考 Docker Compose 官方安装文档。独立版属于兼容方案,新项目优先使用插件。
检查安装
安装完成后,可以通过以下命令检查Docker Compose的版本:
docker compose version
基本概念
版本与名称
版本(Version)
现代 Compose 使用统一的 Compose Specification,顶层 version 字段已经过时。新文件直接从 services 开始;历史项目保留该字段通常也能运行,但 Compose 会忽略它并可能显示提示。
名称(Name)
可以为项目指定一个名称,这在管理多个项目时非常有用:
name: myapp
服务(Service)
服务是Docker Compose中定义的一个容器,它可以是一个应用程序、数据库、缓存等。每个服务都有自己的配置,包括镜像、端口、环境变量、依赖关系等。
镜像(Image)
指定服务使用的Docker镜像:
image: nginx:latest
端口(Ports)
将容器端口映射到主机端口:
ports:
- "80:80"
环境变量(Environment Variables)
设置容器的环境变量:
environment:
- "DB_HOST=db"
- "DB_PORT=3306"
也可以使用对象语法:
environment:
DB_HOST: db
DB_PORT: 3306
或者使用环境变量文件:
env_file:
- ./common.env
- ./app.env
依赖关系(Depends On)
指定服务之间的依赖关系,确保服务按正确的顺序启动:
depends_on:
- db
命令(Command)
覆盖容器的默认命令:
command: "python app.py"
构建(Build)
从Dockerfile构建镜像:
build: ./dir
指定Dockerfile和构建参数:
build:
context: ./dir
dockerfile: Dockerfile-alternate
args:
buildno: 1
gitcommithash: cdc3b19
重启策略(Restart)
配置容器的重启策略:
restart: "no" # 不自动重启
restart: always # 总是重启
restart: on-failure # 仅在失败时重启
restart: unless-stopped # 除非手动停止,否则总是重启
健康检查(Healthcheck)
配置容器的健康检查:
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 1m30s
timeout: 10s
retries: 3
start_period: 40s
禁用健康检查:
healthcheck:
disable: true
日志配置(Logging)
配置容器的日志驱动:
logging:
driver: json-file
options:
max-size: "200k"
max-file: "10"
用户(User)
指定运行容器的用户:
user: postgres
或者使用UID:GID格式:
user: "1000:1000"
网络(Network)
网络是用于连接服务之间的通信通道。Docker Compose会自动创建一个默认网络,但也可以定义自定义网络。
自定义网络
networks:
mynetwork:
driver: bridge
服务连接网络
services:
web:
image: nginx:latest
networks:
- mynetwork
db:
image: mysql:latest
networks:
- mynetwork
networks:
mynetwork:
driver: bridge
服务指定网络配置
services:
web:
image: nginx:latest
networks:
mynetwork:
ipv4_address: 172.16.238.10
ports:
- "80:80"
db:
image: mysql:latest
networks:
mynetwork:
ipv4_address: 172.16.238.11
environment:
- "MYSQL_ROOT_PASSWORD=secret"
networks:
mynetwork:
driver: bridge
ipam:
config:
- subnet: 172.16.238.0/24
卷(Volume)
卷是用于持久化存储数据的容器。Docker Compose会自动创建一个默认卷,但也可以定义自定义卷。
自定义卷
volumes:
myvolume:
driver: local
服务指定卷
services:
web:
image: nginx:latest
volumes:
- myvolume:/var/www/html
db:
image: mysql:latest
volumes:
- dbdata:/var/lib/mysql
volumes:
myvolume:
driver: local
dbdata:
driver: local
挂载主机目录
services:
web:
image: nginx:latest
volumes:
- ./html:/var/www/html
- ./nginx/conf.d:/etc/nginx/conf.d
项目(Project)
项目是一个包含多个服务的Docker Compose应用程序。每个项目都有自己的配置文件(docker-compose.yml),用于定义服务、网络和卷。
常用命令
启动项目
docker compose up
使用-d参数可以在后台运行:
docker compose up -d
停止项目
docker compose down
添加--volumes参数可以同时删除卷:
docker compose down --volumes
查看项目服务
docker compose ps
查看项目日志
docker compose logs
使用-f参数可以持续查看日志:
docker compose logs -f
重启项目服务
docker compose restart
停止项目服务
docker compose stop
启动项目服务
docker compose start
查看项目网络
docker network ls
查看项目卷
docker volume ls
执行容器命令
docker compose exec web bash
构建或重建服务
docker compose build
拉取服务镜像
docker compose pull
推送服务镜像
docker compose push
查看配置
docker compose config
验证配置
docker compose config --quiet
查看容器运行的进程
docker compose top
暂停服务
docker compose pause
恢复服务
docker compose unpause
强制停止服务
docker compose kill
实际应用场景
Web应用 + 数据库
services:
web:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./html:/usr/share/nginx/html
depends_on:
- app
app:
build: ./app
environment:
- DB_HOST=db
- DB_USER=root
- DB_PASSWORD=example
- DB_NAME=myapp
depends_on:
- db
db:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=example
- MYSQL_DATABASE=myapp
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
微服务架构
services:
gateway:
image: nginx:latest
ports:
- "80:80"
volumes:
- ./nginx/conf.d:/etc/nginx/conf.d
depends_on:
- service1
- service2
service1:
build: ./service1
environment:
- DB_HOST=db
depends_on:
- db
- redis
service2:
build: ./service2
environment:
- DB_HOST=db
depends_on:
- db
- redis
db:
image: postgres:13
environment:
- POSTGRES_PASSWORD=example
- POSTGRES_DB=microservices
volumes:
- db_data:/var/lib/postgresql/data
redis:
image: redis:6
volumes:
- redis_data:/data
volumes:
db_data:
redis_data:
前端 + 后端 + 数据库的完整应用
services:
# 前端服务
frontend:
build: ./frontend
ports:
- "80:80"
depends_on:
- backend
environment:
- API_URL=http://backend:3000
# 后端API服务
backend:
build: ./backend
ports:
- "3000:3000"
depends_on:
- db
- redis
environment:
- DB_HOST=db
- DB_USER=postgres
- DB_PASSWORD=example
- DB_NAME=app
- REDIS_HOST=redis
volumes:
- ./backend:/app
- /app/node_modules
# 数据库服务
db:
image: postgres:13
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=example
- POSTGRES_DB=app
volumes:
- postgres_data:/var/lib/postgresql/data
ports:
- "5432:5432"
# Redis缓存服务
redis:
image: redis:6
volumes:
- redis_data:/data
ports:
- "6379:6379"
volumes:
postgres_data:
redis_data:
CI/CD流水线
services:
# Jenkins CI/CD服务
jenkins:
image: jenkins/jenkins:lts
ports:
- "8080:8080"
- "50000:50000"
volumes:
- jenkins_home:/var/jenkins_home
- /var/run/docker.sock:/var/run/docker.sock
environment:
- JAVA_OPTS=-Djenkins.install.runSetupWizard=false
# SonarQube代码质量分析
sonarqube:
image: sonarqube:latest
ports:
- "9000:9000"
environment:
- SONARQUBE_JDBC_URL=jdbc:postgresql://sonardb:5432/sonar
- SONARQUBE_JDBC_USERNAME=sonar
- SONARQUBE_JDBC_PASSWORD=sonar
volumes:
- sonarqube_data:/opt/sonarqube/data
- sonarqube_extensions:/opt/sonarqube/extensions
- sonarqube_logs:/opt/sonarqube/logs
depends_on:
- sonardb
# SonarQube数据库
sonardb:
image: postgres:12
environment:
- POSTGRES_USER=sonar
- POSTGRES_PASSWORD=sonar
- POSTGRES_DB=sonar
volumes:
- sonardb_data:/var/lib/postgresql/data
# Nexus制品库
nexus:
image: sonatype/nexus3
ports:
- "8081:8081"
volumes:
- nexus_data:/nexus-data
volumes:
jenkins_home:
sonarqube_data:
sonarqube_extensions:
sonarqube_logs:
sonardb_data:
nexus_data:
开发环境配置
services:
# 开发环境的应用服务
app:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- .:/app
- /app/node_modules
ports:
- "3000:3000"
environment:
- NODE_ENV=development
- CHOKIDAR_USEPOLLING=true # 在Docker中启用热重载
command: npm run dev
# 测试服务
test:
build:
context: .
dockerfile: Dockerfile.dev
volumes:
- .:/app
- /app/node_modules
command: npm run test
environment:
- NODE_ENV=test
# 数据库服务
db:
image: postgres:13
environment:
- POSTGRES_USER=postgres
- POSTGRES_PASSWORD=postgres
- POSTGRES_DB=dev
ports:
- "5432:5432"
volumes:
- postgres_dev_data:/var/lib/postgresql/data
- ./init-scripts:/docker-entrypoint-initdb.d # 初始化脚本
# 数据库管理工具
adminer:
image: adminer
ports:
- "8080:8080"
depends_on:
- db
volumes:
postgres_dev_data:
监控系统
services:
# Prometheus监控服务
prometheus:
image: prom/prometheus
ports:
- "9090:9090"
volumes:
- ./prometheus/prometheus.yml:/etc/prometheus/prometheus.yml
- prometheus_data:/prometheus
command:
- '--config.file=/etc/prometheus/prometheus.yml'
- '--storage.tsdb.path=/prometheus'
- '--web.console.libraries=/usr/share/prometheus/console_libraries'
- '--web.console.templates=/usr/share/prometheus/consoles'
# Grafana可视化服务
grafana:
image: grafana/grafana
ports:
- "3000:3000"
volumes:
- grafana_data:/var/lib/grafana
depends_on:
- prometheus
# Node Exporter服务器指标收集
node_exporter:
image: prom/node-exporter
ports:
- "9100:9100"
volumes:
- /proc:/host/proc:ro
- /sys:/host/sys:ro
- /:/rootfs:ro
command:
- '--path.procfs=/host/proc'
- '--path.sysfs=/host/sys'
- '--collector.filesystem.ignored-mount-points=^/(sys|proc|dev|host|etc)($$|/)'
# cAdvisor容器指标收集
cadvisor:
image: gcr.io/cadvisor/cadvisor
ports:
- "8080:8080"
volumes:
- /:/rootfs:ro
- /var/run:/var/run:ro
- /sys:/sys:ro
- /var/lib/docker/:/var/lib/docker:ro
- /dev/disk/:/dev/disk:ro
volumes:
prometheus_data:
grafana_data:
常见问题与解决方案
容器间通信问题
问题:服务无法通过服务名访问其他服务。
解决方案:
- 确保服务在同一网络中
- 使用服务名作为主机名进行访问
- 检查网络配置是否正确
卷挂载权限问题
问题:容器无法写入挂载的卷。
解决方案:
- 检查宿主机目录的权限
- 在容器中使用适当的用户运行应用
- 使用命名卷而不是绑定挂载
services:
app:
image: myapp
user: "1000:1000" # 使用特定UID:GID运行
volumes:
- myvolume:/app/data
volumes:
myvolume:
服务启动顺序问题
问题:依赖的服务尚未准备好,导致应用启动失败。
解决方案:
- 使用
depends_on指定依赖关系 - 实现健康检查
- 在应用中实现重试逻辑
services:
app:
image: myapp
depends_on:
db:
condition: service_healthy
db:
image: mysql:5.7
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 5s
retries: 5
使用环境变量
使用.env文件和环境变量来配置服务,避免在配置文件中硬编码敏感信息:
services:
db:
image: mysql:5.7
environment:
- MYSQL_ROOT_PASSWORD=${DB_ROOT_PASSWORD}
- MYSQL_DATABASE=${DB_NAME}
分离开发和生产环境
使用多个Compose文件来分离开发和生产环境的配置:
docker-compose.yml:基本配置docker-compose.override.yml:开发环境特定配置docker-compose.prod.yml:生产环境特定配置
# 开发环境
docker compose up
# 生产环境
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
使用命名卷
使用命名卷而不是绑定挂载来持久化数据,这样可以更好地管理数据:
services:
db:
image: postgres:13
volumes:
- postgres_data:/var/lib/postgresql/data
volumes:
postgres_data:
限制资源使用
在生产环境中,限制容器的资源使用:
services:
app:
image: myapp
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
使用多阶段构建
使用Docker的多阶段构建来创建更小、更安全的镜像:
services:
app:
build:
context: ./app
dockerfile: Dockerfile.multistage
对应的Dockerfile.multistage示例:
# 构建阶段
FROM node:14 AS builder
WORKDIR /app
COPY package*.json ./
RUN npm install
COPY . .
RUN npm run build
# 运行阶段
FROM node:14-alpine
WORKDIR /app
COPY --from=builder /app/dist ./dist
COPY --from=builder /app/package*.json ./
RUN npm install --production
CMD ["node", "dist/index.js"]
使用健康检查
为服务配置健康检查,确保服务正常运行:
services:
web:
image: nginx:latest
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost"]
interval: 30s
timeout: 10s
retries: 3
start_period: 40s
使用配置文件
将配置文件挂载到容器中,而不是将配置硬编码到镜像中:
services:
app:
image: myapp
volumes:
- ./config:/app/config
使用Docker Compose覆盖文件
使用多个Docker Compose文件来覆盖配置,适应不同环境:
# 基本配置 + 开发环境配置
docker compose -f docker-compose.yml -f docker-compose.dev.yml up
# 基本配置 + 生产环境配置
docker compose -f docker-compose.yml -f docker-compose.prod.yml up -d
安全最佳实践
不使用root用户
在容器中避免使用root用户运行应用:
services:
app:
image: myapp
user: "1000:1000"
限制容器权限
限制容器的权限,只授予必要的权限:
services:
app:
image: myapp
cap_drop:
- ALL
cap_add:
- NET_BIND_SERVICE
使用只读文件系统
将容器的文件系统设置为只读,只有特定目录可写:
services:
app:
image: myapp
read_only: true
tmpfs:
- /tmp
- /var/run
volumes:
- data:/app/data
高级网络配置
使用外部网络
使用已存在的外部网络:
services:
app:
image: myapp
networks:
- external_network
networks:
external_network:
external: true
name: existing_network
配置网络别名
为服务配置网络别名:
services:
app:
image: myapp
networks:
frontend:
aliases:
- webapp
- app.local
扩展性考虑
使用服务扩展
使用docker compose up --scale命令扩展服务:
docker compose up --scale web=3 --scale worker=2
对应的配置:
services:
web:
image: nginx:latest
ports:
- "8080-8082:80" # 动态端口映射
worker:
image: worker:latest
使用Docker Swarm
对于更大规模的部署,考虑使用Docker Swarm:
services:
web:
image: nginx:latest
deploy:
replicas: 3
update_config:
parallelism: 1
delay: 10s
restart_policy:
condition: on-failure
监控和日志管理
集中式日志管理
配置日志驱动将日志发送到集中式日志系统:
services:
app:
image: myapp
logging:
driver: "fluentd"
options:
fluentd-address: "localhost:24224"
tag: "docker.{{.Name}}"
使用Prometheus监控
配置Prometheus监控指标:
services:
app:
image: myapp
labels:
- "prometheus.enable=true"
- "prometheus.port=8080"
- "prometheus.path=/metrics"
生产环境部署检查清单
在将Docker Compose应用部署到生产环境之前,请检查以下事项:
- 移除开发环境特定的配置
- 设置适当的资源限制
- 配置健康检查
- 实现适当的日志管理
- 配置备份策略
- 设置监控
- 实现安全最佳实践
- 使用稳定的镜像标签,避免使用
latest - 测试高可用性和故障恢复
- 文档化部署和操作流程
总结
Docker Compose是一个强大的工具,它简化了多容器应用的定义和管理。通过使用YAML配置文件,开发人员可以轻松地定义服务、网络和卷,使应用程序的部署和管理更加简单和高效。本文介绍了Docker Compose的基本概念、配置选项、使用方法以及最佳实践,希望能帮助您更好地使用Docker Compose来管理容器化应用。
无论是开发环境还是生产环境,Docker Compose都是容器编排的理想选择,特别是对于中小型应用。对于更大规模的部署,可以考虑使用Kubernetes等更强大的容器编排平台。



