在前一篇文章中,我们完成了 Docker 的安装与容器生命周期管理,掌握了 docker run、docker ps、docker logs 等基础命令。但在真实的生产环境中,一个应用往往由多个服务组成:Web 服务、数据库、缓存、消息队列……如果每一个容器都靠一条条 docker run 命令手动启动,不仅参数冗长、容易出错,还难以维护和迁移。今天我们就来学习解决这一痛点的利器——Docker Compose,并动手完成一次多容器应用编排实战。

一、为什么需要 Docker Compose
Docker Compose 是 Docker 官方推出的一个编排工具,它通过一个声明式的 YAML 文件(通常命名为 docker-compose.yml 或 compose.yaml)来描述应用所需的所有服务、网络和数据卷。一次执行 docker compose up,就能把整个应用栈一键拉起;一次执行 docker compose down,就能优雅地清理掉整个环境。
它的核心价值在于:
- 声明式配置:所有服务配置都写在文件中,可纳入版本控制,团队协作和审计都非常方便。
- 一键启停:省去手动拼装长命令的麻烦,减少人为失误。
- 环境一致性:开发、测试、生产使用同一份配置,真正做到”一次编写,处处运行”。
- 内置网络与依赖管理:Compose 会自动创建网络,并通过
depends_on控制启动顺序。
在 Ubuntu 系统上,Docker Compose 分为两种形态:独立的 docker-compose 二进制(v1,已停止维护)和作为 Docker CLI 插件的 docker compose(v2,官方推荐)。本文以 v2 为准。
二、安装 Docker Compose 插件
如果你已经按照上一篇文章安装了 Docker,那么在 Ubuntu 上最便捷的方式就是通过 APT 安装 Compose 插件:
sudo apt update
sudo apt install -y docker-compose-plugin
安装完成后,验证插件是否可用:
docker compose version
正常情况下会输出类似 Docker Compose version v2.x.x 的信息。如果你的 Docker 是通过官方脚本安装的,docker-compose-plugin 通常已经自带,直接运行上述命令即可确认。
三、编写第一个 Compose 文件
接下来我们以一个经典的 WordPress 博客应用为例,它需要两个服务:wordpress 和 db。创建项目目录并编写配置文件:
mkdir -p ~/compose-demo && cd ~/compose-demo
编写 docker-compose.yml:
services:
db:
image: mysql:8.0
restart: always
environment:
MYSQL_DATABASE: wordpress
MYSQL_USER: wordpress
MYSQL_PASSWORD: secret123
MYSQL_ROOT_PASSWORD: rootsecret
volumes:
- db_data:/var/lib/mysql
wordpress:
image: wordpress:latest
restart: always
depends_on:
- db
ports:
- "8080:80"
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: secret123
WORDPRESS_DB_NAME: wordpress
volumes:
- wp_data:/var/www/html
volumes:
db_data:
wp_data:
这份文件清晰地描述了两个服务之间的依赖关系、端口映射、环境变量和数据卷。depends_on 保证 wordpress 在 db 之后启动。
四、常用 Compose 命令实战
编写好配置文件后,就可以开始操作了。以下是运维最常用的一组命令:
启动整个应用栈(后台运行):
docker compose up -d
查看运行状态与日志:
docker compose ps
docker compose logs -f wordpress
单独重启某个服务:
docker compose restart db
停止并清理所有容器、网络(保留数据卷):
docker compose down
如果需要连数据卷一起删除,加 -v 参数:
docker compose down -v
这些命令都默认读取当前目录下的 docker-compose.yml 文件,如果需要指定文件,可以使用 -f 参数:
docker compose -f /path/to/prod.yml up -d
五、实战:搭建 Nginx + PHP + MySQL 应用栈
我们再来看一个更接近生产环境的例子。假设我们要部署一个 PHP 应用,架构为 Nginx 作为反向代理、PHP-FPM 处理动态请求、MySQL 存储数据。目录结构如下:
compose-stack/
├── docker-compose.yml
├── nginx/
│ └── default.conf
└── app/
└── index.php
docker-compose.yml 内容:
services:
web:
image: nginx:alpine
ports:
- "80:80"
volumes:
- ./app:/var/www/html
- ./nginx/default.conf:/etc/nginx/conf.d/default.conf
depends_on:
- php
- db
php:
image: php:8.2-fpm-alpine
volumes:
- ./app:/var/www/html
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: rootpass
MYSQL_DATABASE: app
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
Nginx 配置 default.conf 需要把 PHP 请求转发给 php 服务:
server {
listen 80;
root /var/www/html;
index index.php;
location ~ .php$ {
fastcgi_pass php:9000;
fastcgi_index index.php;
include fastcgi_params;
fastcgi_param SCRIPT_FILENAME $document_root$fastcgi_script_name;
}
}
这里的关键点是 fastcgi_pass php:9000,其中的 php 正是 Compose 自动创建的网络中该服务的服务名,容器之间通过服务名即可互相访问,无需关心具体 IP。
六、常见问题与排障
1. depends_on 是否保证依赖服务完全就绪?
不是。depends_on 只控制容器启动的先后顺序,无法保证数据库已完成初始化。对于 MySQL、PostgreSQL 这类需要初始化时间的服务,建议在应用侧加入重试逻辑,或使用 healthcheck 配合 depends_on 的 condition 选项:
depends_on:
db:
condition: service_healthy
2. 端口被占用怎么办?
如果宿主机 80 端口已被占用,只需修改 ports 映射,例如 "8080:80",把宿主端口换成其他空闲端口即可。
3. 数据卷数据如何备份?
可以使用 docker run 挂载同名卷执行备份,或直接进入容器使用 mysqldump 导出,把导出的 SQL 文件挂载到宿主机目录。
4. 修改配置后不生效?
修改 docker-compose.yml 后需要执行 docker compose up -d 让改动生效;如果是镜像或环境变量变化,Compose 会自动重建对应容器。
七、总结
今天我们从”为什么要用 Compose”出发,学习了 Compose 插件的安装、YAML 文件的结构、常用命令,并动手完成了 WordPress 双服务应用与 Nginx + PHP + MySQL 三服务应用栈的编排实战。掌握 Docker Compose 后,多容器应用的部署将从繁琐的手动命令变成一份可版本化、可复现的配置文件,运维效率和可靠性都大幅提升。建议你在自己的测试环境中反复练习 up、down、logs、exec 等命令,感受编排的便利。
下期预告:第 22 天我们将进入虚拟化领域,学习 KVM 虚拟化的虚拟机部署、快照与资源管理,敬请期待。


















暂无评论内容