Docker Compose 从入门到实战:多容器编排完全指南
·
Docker Compose 从入门到实战:多容器编排完全指南
一、什么是 Docker Compose
Docker Compose 是 Docker 官方提供的多容器编排工具,用于定义和运行多个 Docker 容器的应用。通过一个 docker-compose.yml 文件,你可以配置应用程序所需的所有服务(容器),然后使用一条命令即可启动所有服务。
Docker Compose 的核心价值:将多个容器的配置、依赖关系、网络、数据卷等集中声明在一个 YAML 文件中,实现多容器应用的一键部署和环境一致性。
1.1 适用场景
| 场景 | 说明 |
|---|---|
| 开发环境 | 快速搭建完整的应用依赖(数据库、缓存、消息队列等) |
| 本地测试 | 模拟生产环境进行集成测试 |
| CI/CD 流水线 | 自动化构建和测试环境 |
| 单机生产部署 | 小型项目或微服务部署(生产环境一般用 K8s) |
二、安装 Docker Compose
安装看这篇:二进制安装 Docker 和 Docker-compose
三、docker-compose.yml 核心语法详解
3.1 基础结构
version: '3.8' # Compose 文件版本
services: # 服务定义(每个服务对应一个容器)
web: # 服务名称
image: nginx # 使用的镜像
ports: # 端口映射
- "8080:80"
volumes: # 数据卷挂载
- ./html:/usr/share/nginx/html
networks: # 网络定义(可选)
default:
driver: bridge
volumes: # 卷定义(可选)
data:
四、核心配置项详解
4.1 image——指定镜像
services:
web:
image: nginx:alpine # 从仓库拉取
app:
build: ./app # 从 Dockerfile 构建
# 或指定构建参数
build:
context: ./app
dockerfile: Dockerfile
args:
VERSION: 1.0
db:
image: mysql:5.7
4.2 ports——端口映射
services:
web:
ports:
- "8080:80" # 宿主机:容器
- "127.0.0.1:8081:81" # 绑定到指定 IP
- "8082:80" # 多个端口映射
# 暴露内部端口但不映射到宿主机(仅服务间通信)
app:
expose:
- "8080"
- "9090"
4.3 volumes——数据卷挂载
services:
web:
volumes:
# 绑定挂载(宿主机目录:容器目录)
- ./app:/app
# 命名卷
- data:/var/lib/mysql
# 只读挂载
- ./config:/etc/app/config:ro
# 相对路径挂载
- ./logs:/var/log/app
db:
volumes:
- db_data:/var/lib/mysql
# 定义命名卷
volumes:
data:
db_data:
4.4 environment 与 env_file——环境变量
services:
web:
# 直接定义
environment:
- NODE_ENV=production
- DB_HOST=mysql
- APP_PORT=8080
db:
# 从文件加载(.env 文件)
env_file:
- .env
- ./config/db.env
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD} # 引用外部变量
.env 文件示例:
MYSQL_ROOT_PASSWORD=123456
MYSQL_DATABASE=myapp
DB_USER=admin
4.5 depends_on——依赖与启动顺序
services:
web:
image: nginx
depends_on:
- app
- db
app:
build: ./app
depends_on:
- db
db:
image: mysql:5.7
注意:
depends_on仅控制容器启动顺序,不等待服务完全就绪。如需健康检查后才启动,需配合condition:
services:
web:
depends_on:
db:
condition: service_healthy # 等待 db 健康后才启动
db:
image: mysql:5.7
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
4.6 restart——重启策略
services:
web:
restart: always # 总是重启
# restart: unless-stopped # 除非手动停止
# restart: on-failure:3 # 失败时重启,最多 3 次
# restart: no # 不自动重启(默认)
4.7 networks——网络配置
services:
web:
networks:
- frontend
- backend
app:
networks:
- backend
db:
networks:
- backend
# 定义网络
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: true # 内部网络(不对外暴露)
4.8 command 与 entrypoint——启动命令
services:
web:
image: python:3.11
command: python app.py
# 或数组格式
command: ["python", "app.py"]
app:
build: .
entrypoint: ["java", "-jar"]
command: ["app.jar"]
# 组合使用:实际执行 java -jar app.jar
4.9 container_name——指定容器名
services:
web:
container_name: my-web-app # 固定容器名
image: nginx
注意:生产环境尽量不要固定容器名,避免冲突。
4.10 logging——日志配置
services:
web:
logging:
driver: "json-file" # 日志驱动
options:
max-size: "10m" # 单个日志文件最大 10M
max-file: "3" # 最多保留 3 个文件
五、配置文件完整参考(含全部常用字段)
version: '3.8'
services:
# ========== Web 服务 ==========
web:
image: nginx:alpine
container_name: nginx-web
restart: always
ports:
- "80:80"
- "443:443"
volumes:
- ./html:/usr/share/nginx/html:ro
- ./nginx.conf:/etc/nginx/conf.d/default.conf:ro
depends_on:
app:
condition: service_healthy
networks:
- frontend
- backend
logging:
driver: "json-file"
options:
max-size: "10m"
max-file: "3"
# ========== 应用服务 ==========
app:
build:
context: ./app
dockerfile: Dockerfile
args:
BUILD_ENV: production
container_name: spring-app
restart: always
environment:
- SPRING_PROFILES_ACTIVE=prod
- DB_HOST=db
- DB_PORT=3306
- REDIS_HOST=redis
env_file:
- ./config/app.env
volumes:
- ./logs:/app/logs
- app_data:/app/data
ports:
- "8080:8080"
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 3s
retries: 3
start_period: 30s
networks:
- backend
- internal
logging:
driver: "json-file"
options:
max-size: "50m"
max-file: "5"
# ========== 数据库服务 ==========
db:
image: mysql:5.7
container_name: mysql-db
restart: always
environment:
- MYSQL_ROOT_PASSWORD=${MYSQL_ROOT_PASSWORD}
- MYSQL_DATABASE=myapp
- MYSQL_USER=appuser
- MYSQL_PASSWORD=${MYSQL_USER_PASSWORD}
volumes:
- db_data:/var/lib/mysql
- ./init.sql:/docker-entrypoint-initdb.d/init.sql:ro
ports:
- "3306:3306"
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "127.0.0.1", "-uroot", "-p${MYSQL_ROOT_PASSWORD}"]
interval: 10s
timeout: 5s
retries: 5
networks:
- backend
- internal
# ========== Redis 缓存 ==========
redis:
image: redis:7.0-alpine
container_name: redis-cache
restart: always
command: redis-server --requirepass ${REDIS_PASSWORD}
volumes:
- redis_data:/data
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 5
networks:
- backend
# ========== 网络定义 ==========
networks:
frontend:
driver: bridge
backend:
driver: bridge
internal: false
internal:
driver: bridge
internal: true # 内部网络,无法访问外部
# ========== 卷定义 ==========
volumes:
db_data:
driver: local
redis_data:
app_data:
六、常用命令详解
6.1 基础命令
| 命令 | 说明 | 示例 |
|---|---|---|
up | 启动所有服务 | docker-compose up -d |
down | 停止并删除所有容器、网络 | docker-compose down |
ps | 查看服务状态 | docker-compose ps |
logs | 查看日志 | docker-compose logs -f web |
stop | 停止服务(不删除容器) | docker-compose stop |
start | 启动已停止的服务 | docker-compose start |
restart | 重启服务 | docker-compose restart web |
exec | 进入容器执行命令 | docker-compose exec web bash |
build | 构建或重新构建服务镜像 | docker-compose build --no-cache |
pull | 拉取服务镜像 | docker-compose pull |
push | 推送服务镜像到仓库 | docker-compose push |
top | 查看容器内进程 | docker-compose top |
config | 验证配置文件格式 | docker-compose config |
6.2 常用组合示例
# 后台启动所有服务
docker-compose up -d
# 只启动特定服务
docker-compose up -d web db
# 查看所有容器状态
docker-compose ps -a
# 实时查看所有服务日志
docker-compose logs -f
# 查看特定服务日志(最近 100 行)
docker-compose logs --tail=100 web
# 进入 Web 容器终端
docker-compose exec web /bin/sh
# 执行数据库备份
docker-compose exec db mysqldump -uroot -p123456 myapp > backup.sql
# 停止并删除所有容器、网络、卷
docker-compose down -v
# 重新构建并启动
docker-compose up -d --build
# 验证配置文件
docker-compose config --quiet
七、实战案例
7.1 案例一:LAMP 环境(WordPress + MySQL)
version: '3.8'
services:
# WordPress 服务
wordpress:
image: wordpress:latest
container_name: wordpress
restart: always
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress_pass
WORDPRESS_DB_NAME: wordpress
volumes:
- wordpress_data:/var/www/html
- ./wp-content:/var/www/html/wp-content
depends_on:
db:
condition: service_healthy
networks:
- webnet
# MySQL 数据库
db:
image: mysql:5.7
container_name: mysql-wp
restart: always
environment:
MYSQL_ROOT_PASSWORD: root_pass
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress_pass
volumes:
- db_data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 10s
timeout: 5s
retries: 5
networks:
- webnet
# phpMyAdmin(可选)
phpmyadmin:
image: phpmyadmin/phpmyadmin
container_name: phpmyadmin
restart: always
ports:
- "8081:80"
environment:
PMA_HOST: db
PMA_PORT: 3306
UPLOAD_LIMIT: 100M
depends_on:
- db
networks:
- webnet
volumes:
wordpress_data:
db_data:
networks:
webnet:
启动访问:
- WordPress: http://localhost:8080
- phpMyAdmin: http://localhost:8081
7.2 案例二:微服务架构(Spring Boot + MySQL + Redis + Nginx)
version: '3.8'
services:
# Nginx 网关
nginx:
image: nginx:alpine
container_name: api-gateway
restart: always
ports:
- "80:80"
volumes:
- ./nginx/nginx.conf:/etc/nginx/nginx.conf:ro
- ./nginx/conf.d:/etc/nginx/conf.d:ro
depends_on:
- user-service
- order-service
- product-service
networks:
- frontend
- backend
# 用户服务
user-service:
build: ./user-service
container_name: user-service
restart: always
environment:
- SPRING_PROFILES_ACTIVE=docker
- DB_HOST=mysql
- REDIS_HOST=redis
ports:
- "8081:8080"
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 3s
retries: 3
start_period: 30s
networks:
- backend
# 订单服务
order-service:
build: ./order-service
container_name: order-service
restart: always
environment:
- SPRING_PROFILES_ACTIVE=docker
- DB_HOST=mysql
- REDIS_HOST=redis
ports:
- "8082:8080"
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 3s
retries: 3
start_period: 30s
networks:
- backend
# 商品服务
product-service:
build: ./product-service
container_name: product-service
restart: always
environment:
- SPRING_PROFILES_ACTIVE=docker
- DB_HOST=mysql
- REDIS_HOST=redis
ports:
- "8083:8080"
depends_on:
mysql:
condition: service_healthy
redis:
condition: service_healthy
healthcheck:
test: ["CMD", "curl", "-f", "http://localhost:8080/actuator/health"]
interval: 30s
timeout: 3s
retries: 3
start_period: 30s
networks:
- backend
# MySQL
mysql:
image: mysql:5.7
container_name: mysql-micro
restart: always
environment:
- MYSQL_ROOT_PASSWORD=root123
volumes:
- mysql_data:/var/lib/mysql
- ./init.sql:/docker-entrypoint-initdb.d/init.sql
ports:
- "3306:3306"
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-uroot", "-proot123"]
interval: 10s
timeout: 5s
retries: 5
networks:
- backend
# Redis
redis:
image: redis:7.0-alpine
container_name: redis-micro
restart: always
volumes:
- redis_data:/data
ports:
- "6379:6379"
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 10s
timeout: 3s
retries: 5
networks:
- backend
volumes:
mysql_data:
redis_data:
networks:
frontend:
driver: bridge
backend:
driver: bridge
八、常用环境变量文件 .env
# .env 文件(与 docker-compose.yml 同目录)
# 数据库配置
MYSQL_ROOT_PASSWORD=root123456
MYSQL_DATABASE=myapp
MYSQL_USER=appuser
MYSQL_PASSWORD=apppass123
# 应用配置
APP_ENV=production
APP_PORT=8080
JWT_SECRET=your-secret-key-here
# Redis 配置
REDIS_PASSWORD=redispass
# 对外域名
DOMAIN=example.com
在 docker-compose.yml 中引用:
services:
db:
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_ROOT_PASSWORD}
MYSQL_DATABASE: ${MYSQL_DATABASE}
MYSQL_USER: ${MYSQL_USER}
MYSQL_PASSWORD: ${MYSQL_PASSWORD}
九、最佳实践总结
9.1 配置文件规范
| 序号 | 最佳实践 | 说明 |
|---|---|---|
| 1 | 使用固定版本号,避免 latest | 保证环境一致性 |
| 2 | 使用 .env 管理敏感信息 | 不将密码硬编码在 YAML 中 |
| 3 | 添加 healthcheck 健康检查 | 确保服务就绪后再启动依赖 |
| 4 | 合理规划网络隔离 | 前后端分离网络,提高安全性 |
| 5 | 使用 restart: always | 保证容器意外退出后自动恢复 |
| 6 | 限制日志文件大小 | 避免磁盘爆满 |
| 7 | 使用命名卷持久化数据 | 容器重启后数据不丢失 |
| 8 | 配置文件添加注释 | 便于团队协作和维护 |
| 9 | 使用 depends_on + condition | 确保依赖服务健康后才启动 |
9.2 常用 .gitignore 内容
# 环境变量(含敏感信息)
.env
*.env
# 日志目录
logs/
*.log
# 数据卷目录(避免提交大文件)
data/
volumes/
# IDE 配置
.idea/
.vscode/
*.iml
9.3 生产环境注意事项
| 注意事项 | 说明 |
|---|---|
禁用 latest 标签 | 指定具体版本号,保证可追溯性 |
| 使用国内镜像加速 | 在 docker-compose.yml 中配置 registry-mirrors |
| 设置资源限制 | 使用 deploy.resources.limits 限制 CPU 和内存 |
| 配置日志轮转 | 避免日志占满磁盘 |
| 使用外部卷 | 便于数据备份和迁移 |
| 定期备份数据 | 数据库卷需要定期备份 |
资源限制示例:
services:
web:
deploy:
resources:
limits:
cpus: '0.5'
memory: 512M
reservations:
cpus: '0.25'
memory: 256M
十、常用命令速查表
| 分类 | 命令 | 说明 |
|---|---|---|
| 启动 | docker-compose up -d | 后台启动所有服务 |
| 停止 | docker-compose down | 停止并删除容器、网络 |
docker-compose down -v | 同时删除数据卷 | |
| 查看 | docker-compose ps | 查看服务状态 |
docker-compose logs -f | 实时查看所有日志 | |
| 操作 | docker-compose exec web bash | 进入容器 |
docker-compose restart web | 重启特定服务 | |
| 构建 | docker-compose build | 构建或重建镜像 |
docker-compose build --no-cache | 不使用缓存构建 | |
| 调试 | docker-compose config | 验证配置文件 |
docker-compose top | 查看容器内进程 |
如果这篇文章对你有帮助,欢迎收藏、分享,也欢迎在评论区交流讨论!
更多推荐
所有评论(0)