Docker学习路径——10、Docker Compose 一站式编排:从入门到生产级部署
Docker Compose 一站式编排:从入门到生产级部署
在微服务架构中,单个应用往往由多个相互依赖的容器组成(如 Web 服务器 + 数据库 + 缓存)。手动管理这些容器(docker run启动、依赖顺序、网络配置)既繁琐又易错。Docker Compose 应运而生——它用声明式 YAML 文件定义整个应用栈,实现“一键部署、一键销毁”。
为什么必须用 Compose?
- ✅简化复杂度:10 行 YAML 替代 10 条
docker run命令- ✅依赖管理:自动处理启动顺序(如 DB 先于 Web 启动)
- ✅环境一致性:开发、测试、生产环境配置统一
- ✅资源隔离:每个项目独立网络/卷,避免冲突
一、核心概念解析
1. 三大核心要素
| 要素 | 说明 | 示例 |
|---|---|---|
| Project(项目) | 一组关联服务的集合 | my-web-app |
| Service(服务) | 单个容器实例的配置模板 | web,db,redis |
| Compose File | 定义项目的 YAML 文件 | docker-compose.yml |
2. 工作流程
二、安装与验证
安装步骤(Linux)
# 下载二进制文件sudocurl-L"https://github.com/docker/compose/releases/latest/download/docker-compose-$(uname-s)-$(uname-m)"-o/usr/local/bin/docker-compose# 添加执行权限sudochmod+x /usr/local/bin/docker-compose# 创建软链接sudoln-s/usr/local/bin/docker-compose /usr/bin/docker-compose# 验证安装docker-compose--version# 输出:Docker Compose version v2.24.5💡替代方案:
若 GitHub 下载慢,可从 DaoCloud 镜像 获取
三、Compose 文件深度解析
基础结构(v3.8 规范)
version:"3.8"# 指定 Compose 文件版本services:web:# 服务名(自定义)image:nginx:alpineports:-"80:80"networks:-app-netdb:image:mysql:5.7environment:MYSQL_ROOT_PASSWORD:examplevolumes:-db-data:/var/lib/mysql# 定义命名卷volumes:db-data:# 定义自定义网络networks:app-net:driver:bridge关键字段详解
| 字段 | 作用 | 最佳实践 |
|---|---|---|
image | 指定镜像 | 优先使用带 tag 的镜像(如redis:7.0) |
build | 从 Dockerfile 构建 | 与image二选一 |
ports | 端口映射 | 生产环境慎用(建议仅暴露必要端口) |
volumes | 数据卷挂载 | 用命名卷替代绑定挂载(更便携) |
environment | 环境变量 | 敏感信息用env_file或 secrets |
depends_on | 启动依赖 | 注意:仅控制启动顺序,不等待服务就绪 |
networks | 网络连接 | 必须先定义网络 |
⚠️
depends_on陷阱:
它只保证容器启动顺序,不等待服务真正可用!
解决方案:在应用代码中添加重试逻辑,或使用healthcheck
四、实战案例:修复你的 Compose 文件
你提供的配置存在几个关键问题,以下是修正版:
修正后的 docker-compose.yml
version:"3.8"services:# Tomcat 服务(原 cenos 名称有误)tomcat:image:billygoo/tomcat8-jdk8container_name:test01ports:-"8080:8080"# 添加端口映射(否则无法外部访问)networks:-xn_networkdepends_on:-redis-mysql# 添加健康检查(确保 Tomcat 就绪)healthcheck:test:["CMD","curl","-f","http://localhost:8080"]interval:30stimeout:10sretries:3redis:image:redis# 修正拼写(原 images → image)ports:-"6379:6379"volumes:-/opt/redis/redis.conf:/etc/redis/redis.conf:ro# 只读挂载配置-redis-data:/data# 使用命名卷(更安全)networks:-xn_networkcommand:redis-server /etc/redis/redis.conf# Redis 健康检查healthcheck:test:["CMD","redis-cli","ping"]interval:10stimeout:5sretries:3mysql:image:mysql:5.7# 修正拼写environment:MYSQL_ROOT_PASSWORD:"123456"MYSQL_DATABASE:"db2021"MYSQL_USER:"xn"MYSQL_PASSWORD:"123456"volumes:-mysql-data:/var/lib/mysql# 命名卷-/opt/mysql/conf/my.cnf:/etc/mysql/conf.d/my.cnf:ro# 配置文件路径修正networks:-xn_network# MySQL 健康检查healthcheck:test:["CMD","mysqladmin","ping","-h","localhost"]interval:10stimeout:5sretries:3# 定义命名卷(避免直接挂载宿主机路径)volumes:redis-data:mysql-data:# 定义网络networks:xn_network:driver:bridge关键修正点:
- 拼写错误:
images→image - 端口映射:为 Tomcat 添加
8080:8080 - 数据卷优化:
- 使用命名卷(
redis-data,mysql-data)替代直接挂载 - 配置文件挂载为只读(
:ro)
- 使用命名卷(
- 健康检查:确保服务真正就绪后再启动依赖服务
- 配置路径:MySQL 配置应放在
/etc/mysql/conf.d/
五、常用命令速查
| 命令 | 作用 | 场景 |
|---|---|---|
docker-compose up -d | 后台启动所有服务 | 部署应用 |
docker-compose down | 停止并删除容器/网络 | 清理环境 |
docker-compose logs -f web | 实时查看日志 | 调试 |
docker-compose exec db mysql -u root -p | 进入容器执行命令 | 数据库操作 |
docker-compose config | 验证 YAML 语法 | 部署前检查 |
docker-compose ps | 查看服务状态 | 监控 |
💡项目命名:
默认以目录名为项目名,可通过-p指定:docker-compose-pmyapp up-d
六、高级技巧
1. 环境变量分离
创建.env文件:
DB_PASSWORD=supersecret REDIS_HOST=redis在 compose 文件中引用:
environment:MYSQL_ROOT_PASSWORD:${DB_PASSWORD}2. 多环境配置
docker-compose.yml:基础配置docker-compose.override.yml:开发环境覆盖(自动加载)docker-compose.prod.yml:生产环境配置
# 生产环境启动docker-compose-fdocker-compose.yml-fdocker-compose.prod.yml up-d3. 扩展服务(Scale)
# 启动 3 个 Redis 实例(需无状态服务)docker-composeup--scaleredis=3-d七、生产环境最佳实践
1. 安全加固
- 敏感信息:使用 Docker secrets(Swarm 模式)或 HashiCorp Vault
- 最小权限:容器以非 root 用户运行
- 网络隔离:前端/后端服务分属不同网络
2. 资源限制
services:web:deploy:# 仅 Swarm 模式有效resources:limits:cpus:'0.5'memory:512M# Compose 模式用以下方式mem_limit:512mcpus:0.53. 监控集成
- 挂载
/var/run/docker.sock给监控容器 - 使用 Prometheus + cAdvisor 收集指标
八、常见问题排查
Q1:服务启动顺序问题
- 现象:Web 服务因 DB 未就绪而崩溃
- 解决方案:
- 添加
healthcheck - 在应用代码中实现连接重试
- 使用
wait-for-it.sh脚本(GitHub 链接)
- 添加
Q2:卷权限错误
- 现象:MySQL 容器因权限拒绝启动
- 解决方案:
# 初始化卷权限dockerrun--rm-vmysql-data:/var/lib/mysql alpinechown-R999:999 /var/lib/mysql
Q3:网络 DNS 解析失败
- 现象:容器内无法通过服务名访问其他服务
- 检查点:
# 进入容器检查 DNSdocker-composeexecwebcat/etc/resolv.conf# 应包含 nameserver 127.0.0.11(Docker 内置 DNS)
九、总结:Compose 黄金法则
- 明确依赖:用
depends_on+healthcheck双保险 - 持久化数据:数据库必须用命名卷
- 配置分离:敏感信息绝不硬编码
- 资源限制:防止单个服务耗尽资源
- 版本锁定:Compose 文件指定
version
🚀行动清单:
- 将现有
docker run命令迁移至 Compose- 为团队制定 Compose 文件规范
- 在 CI/CD 中集成
docker-compose config验证
掌握 Docker Compose,你就拥有了高效管理多容器应用的核心能力。下一步,我们将探索如何用Docker Swarm或Kubernetes实现集群化部署!
