Docker06-Compose 与实战
Docker Compose 与实战:多容器编排部署
目录
- 为什么需要 Compose
- Compose 是什么与版本说明
- compose 文件结构详解
- Compose 常用命令
- 服务依赖与健康检查:depends_on
- Compose 中的数据卷与网络
- 环境变量与配置注入
- 端到端实战:部署 Web + 数据库 + 缓存
- 与 Ansible、Podman 的衔接
- 常见问题排查
- 总结
- 参考资料
0. 为什么需要 Compose
一个真实应用很少是单个容器。以典型的 Web 应用为例:前端 + 后端 + 数据库 + 缓存,至少 4 个容器。如果用 docker run 手动一个个启动,要:
- 逐个写命令、记端口、记网络;
- 手动创建网络让它们互通;
- 手动建卷保证数据持久化;
- 每次重复敲。
Docker Compose 把这些都写进一份 YAML 文件(compose.yaml 或 docker-compose.yml),一条 docker compose up 就能把整套服务全部启动,还能一起管理、一起停止。它是开发和生产多容器编排的基础工具。
一、Compose 是什么与版本说明
1.1 两个版本:docker-compose 与 docker compose
- 旧版是独立的 docker-compose 命令(Python 实现);
- 新版是 Compose v2,作为 Docker 的插件,命令是 docker compose(注意中间有空格)。
第 2 篇安装时已带上 docker-compose-plugin,所以你的系统用 docker compose 即可。验证:
docker compose version
1.2 关于 version 字段:不要写
网上很多旧教程的 compose 文件开头有 version: "3.8"。现代 Compose v2 已经废弃/不推荐这个顶层 version 字段,Docker 会给出警告。本系列不写 version 字段,直接以 services: 开头。
二、compose 文件结构详解
一个 compose 文件主要由 services(服务/容器)、networks(网络)、volumes(卷)组成。
2.1 一个最小的 compose 文件
services:
web:
image: nginx:1.25
ports:
- "8080:80"
启动后就是一个映射了端口的 nginx 容器。services 下的每个键(web)是一个服务,对应一个容器。
2.2 常用字段
| 字段 | 作用 | 示例 |
|---|---|---|
| image | 使用的镜像 | image: nginx:1.25 |
| build | 用 Dockerfile 构建(与该服务的 image 二选一或结合) | build: ./app |
| container_name | 自定义容器名 | container_name: web |
| ports | 端口映射 | - "8080:80" |
| volumes | 挂载卷(命名卷或绑定挂载) | - mydata:/data |
| networks | 加入的网络 | - mynet |
| environment | 环境变量 | - MYSQL_ROOT_PASSWORD=secret |
| depends_on | 服务依赖 | 见第 4 章 |
| restart | 重启策略 | restart: unless-stopped |
| healthcheck | 健康检查 | 见第 4 章 |
2.3 一个稍完整的例子
services:
web:
image: nginx:1.25
ports:
- "8080:80"
volumes:
- ./html:/usr/share/nginx/html
restart: unless-stopped
db:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=mysecret
volumes:
- mysql-data:/var/lib/mysql
restart: unless-stopped
volumes:
mysql-data:
这个文件定义了 web 和 db 两个服务,并声明了一个命名卷 mysql-data。
三、Compose 常用命令
所有命令都在包含 compose 文件的目录下执行。
3.1 启动与停止
docker compose up # 前台启动(看日志)
docker compose up -d # 后台启动(推荐)
docker compose down # 停止并删除容器、网络
docker compose down -v # 连同删除卷(慎用,会删数据)
3.2 查看与管理
docker compose ps # 查看当前 compose 的容器状态
docker compose logs -f # 跟踪所有服务日志
docker compose logs web # 只看某个服务的日志
docker compose exec web bash # 进入某个服务的容器
docker compose restart # 重启所有服务
docker compose stop # 停止但不删除
3.3 重新构建
docker compose build # 重新构建(用 build 的服务)
docker compose up -d --build # 重新构建并启动
3.4 指定文件
默认找当前目录的 compose.yaml / docker-compose.yml,也可指定:
docker compose -f prod-compose.yml up -d
四、服务依赖与健康检查:depends_on
4.1 depends_on:控制启动顺序
depends_on 声明服务间的依赖,让 Compose 按顺序启动。基础用法:
services:
app:
image: myapp
depends_on:
- db
db:
image: mysql:8.0
这样 app 会在 db 之后启动。但注意:基础 depends_on 只保证 db 容器「启动了」,不保证 db 真的「可用了」(数据库可能还在初始化)。
4.2 配合 healthcheck:等真正就绪
更可靠的做法是给被依赖服务加 healthcheck,然后用 depends_on 的 condition: service_healthy,让 Compose 等它健康后再启动下游:
services:
app:
image: myapp
depends_on:
db:
condition: service_healthy
db:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=secret
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 3s
retries: 10
这样 app 会一直等到 db 的 healthcheck 通过(数据库真正就绪)才开始启动,避免了「应用启动时连不上数据库」的经典问题。
健康检查(healthcheck)在 compose 里的用法与单容器一致,是编排里保证服务就绪的关键手段。
五、Compose 中的数据卷与网络
5.1 数据卷
compose 里可以声明命名卷(volumes 顶层段),并在服务里引用:
services:
db:
image: mysql:8.0
volumes:
- mysql-data:/var/lib/mysql
volumes:
mysql-data: # 声明一个命名卷
也可以在服务里直接用绑定挂载(宿主机路径):
services:
web:
image: nginx
volumes:
- ./html:/usr/share/nginx/html:ro # 绑定挂载,只读
5.2 网络
Compose 默认会为这个项目自动创建一个网络,所有服务都加入其中,服务之间可以用「服务名」互相访问(利用 Docker 内置 DNS,第 4 篇讲过)。
你不需要手动写 networks,Compose 会隐式管理。若要自定义,也可声明:
services:
web:
image: nginx
networks:
- mynet
networks:
mynet:
六、环境变量与配置注入
6.1 environment:直接写
services:
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: mysecret
MYSQL_DATABASE: mydb
6.2 env_file:从文件读
services:
db:
image: mysql:8.0
env_file:
- .env
6.3 变量替换:$VAR 或 ${VAR}
compose 文件里可以用 $VAR(或 ${VAR})引用宿主环境变量或 .env 文件里的值:
services:
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: $DB_PASSWORD
注意:不要把密码等敏感信息硬编码进 compose 文件并提交到仓库。用环境变量或 .env 文件,并把 .env 加入 .gitignore。
七、端到端实战:部署 Web + 数据库 + 缓存
下面做一个完整的实战:用 compose 部署一个「Web 应用 + MySQL 数据库 + Redis 缓存」。Web 端是一个简单的 PHP 页面,连接数据库和缓存来验证整套链路。
7.1 准备项目结构
myapp/
├── compose.yaml
├── app/
│ ├── Dockerfile
│ └── index.php
└── .env
7.2 编写 app/Dockerfile
FROM php:8.2-apache
# 安装 mysqli 和 redis 扩展
RUN docker-php-ext-install mysqli \
&& pecl install redis && docker-php-ext-enable redis
COPY index.php /var/www/html/
EXPOSE 80
7.3 编写 app/index.php
<?php
$db = new mysqli("db", "root", getenv("MYSQL_ROOT_PASSWORD"), "mydb");
if ($db->connect_error) { die("数据库连接失败: " . $db->connect_error); }
$redis = new Redis();
$redis->connect("redis", 6379);
echo "连接 MySQL 成功!";
echo "<br>连接 Redis 成功!";
?>
这里 Web 连接数据库用的是主机名 db、连接缓存用 redis——正是利用了 compose 自动网络里的服务名 DNS 解析。
7.4 编写 compose.yaml
services:
web:
build: ./app
ports:
- "8080:80"
environment:
- MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD
depends_on:
db:
condition: service_healthy
redis:
condition: service_healthy
db:
image: mysql:8.0
environment:
- MYSQL_ROOT_PASSWORD=$MYSQL_ROOT_PASSWORD
- MYSQL_DATABASE=mydb
volumes:
- mysql-data:/var/lib/mysql
healthcheck:
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 3s
retries: 10
redis:
image: redis:7-alpine
healthcheck:
test: ["CMD", "redis-cli", "ping"]
interval: 5s
timeout: 3s
retries: 10
volumes:
mysql-data:
7.5 编写 .env
MYSQL_ROOT_PASSWORD=mysecretpass
7.6 启动整套服务
# 在 myapp 目录下
docker compose up -d --build
docker compose ps
docker compose logs -f
浏览器访问 http://本机IP:8080,能看到「连接 MySQL 成功!连接 Redis 成功!」——说明 Web、数据库、缓存三个容器通过网络成功协作。
7.7 验证数据持久化
# 停止并删除容器(-v 会删卷,这里先不删)
docker compose down
# 再启动
docker compose up -d
# 数据库数据仍在(因为卷 mysql-data 保留)
这就是一个完整的多容器应用生命周期:构建镜像、编排服务、网络互通、数据持久化、健康检查、一键启停。
八、与 Ansible、Podman 的衔接
8.1 与 Ansible
Ansible 可以用模块管理 compose:在目标机上创建 compose 文件、执行 docker compose up -d,实现「基础设施即代码 + 应用编排」的自动化。这也是你已完成的中级 Ansible 篇的自然延伸。
8.2 与 Podman
如果你在纯 RHEL 环境用 Podman,Podman 也支持 compose:podman compose up -d(需装 podman-compose 或 docker-compose 插件)。compose 文件本身通用,换引擎不换编排描述。
8.3 与 K8s 的关系
Compose 适合单机多容器编排;**K8s(Kubernetes)**是跨多台机器的集群编排。理解了 Compose 的「服务、网络、卷、健康检查」这些概念,学 K8s 的 Pod、Service、Volume 会轻松很多——它们是同一套思想的延伸。
九、常见问题排查
9.1 up 后服务一直 Restarting
看日志定位:
docker compose ps
docker compose logs <服务名>
常见:环境变量缺失、配置错误、依赖服务未就绪。用 healthcheck + depends_on 解决就绪问题。
9.2 应用连不上数据库/缓存
- 确认连接的主机名是服务名(如 db、redis),不是 IP;
- 确认数据库初始化完成(healthcheck 通过后再启动下游);
- 确认端口(容器内部端口,不是映射的宿主机端口)。
9.3 端口冲突
换宿主端口,或用 docker compose down 先停掉旧的。
9.4 down -v 把数据删了
docker compose down -v 会删除卷。重要数据不要轻易 down -v。若已误删,只能从备份恢复(第 4 篇讲过卷备份方法)。
9.5 build 的服务镜像没更新
docker compose up -d --build 强制重新构建;或用 docker compose build --no-cache。
十、总结
- Compose 用一份 YAML 定义并编排多容器应用,docker compose up -d 一键启动;
- 现代 Compose v2 命令是 docker compose(有空格),不再写 version 字段;
- services / networks / volumes 三大段定义服务、网络、卷;
- depends_on + healthcheck 控制启动顺序,等依赖服务真正就绪;
- 服务间用服务名通过 compose 自动网络互通;
- 用 .env / 环境变量注入配置,避免敏感信息硬编码;
- 端到端实战把 Web + 数据库 + 缓存串起来,覆盖构建、编排、网络、持久化、健康检查;
- Compose 是单机编排,K8s 是其思想的集群化延伸。
至此,一个覆盖概念 → 安装 → 镜像与容器管理 → 数据卷与网络 → 镜像构建 → Compose 编排的容器技术栈已经闭环,可用于 Docker 应用的定义、构建、编排与部署。
参考资料
- Docker 官方:Compose 概述:https://docs.docker.com/compose/
- Docker 官方:Compose 文件规范:https://docs.docker.com/reference/compose-file/
- Docker 官方:depends_on 与 healthcheck:https://docs.docker.com/reference/compose-file/services/
- Docker 官方:多容器应用教程:https://docs.docker.com/compose/gettingstarted/
