Docker Compose 实战:简化多容器应用管理与部署
在现代微服务架构和复杂应用部署中,我们常常需要同时管理和运行多个相互依赖的 Docker 容器(例如,Web 应用 + 数据库 + 缓存服务)。手动使用 docker run 命令逐一启动、配置和连接这些容器,不仅繁琐易错,而且难以维护和复现。
Docker Compose 应运而生,它是一个用于定义和运行多容器 Docker 应用程序的工具。通过一个单独的 YAML 文件(通常是 docker-compose.yaml),你可以配置应用程序所需的所有服务(容器)、网络、卷以及它们之间的依赖关系。然后,使用简单的命令,就可以一键创建、启动、停止和重建整个应用环境。
本文将深入探讨 Docker Compose 的核心概念和常用操作,并通过两个实例——一个简单的双服务应用和一个真实的 Zabbix 监控系统部署——展示其在实际生产环境中的强大威力。
一、 Docker Compose 核心概念
- 服务 (Services): 一个服务对应一个应用容器。它定义了该容器的配置,例如使用的镜像 (
image)、构建指令 (build)、端口映射 (ports)、环境变量 (environment)、依赖关系 (depends_on)、重启策略 (restart) 等。 - 项目 (Project): 由
docker-compose.yaml文件定义的一组相关服务构成一个项目。Compose 会为项目创建一个默认的网络,使得项目内的服务可以通过服务名相互访问。项目名称通常基于包含docker-compose.yaml的目录名。 - YAML 文件 (
docker-compose.yaml): Compose 的配置文件,采用 YAML 格式,描述了整个多容器应用的架构。
二、 实战案例 1:构建并管理简单的双服务应用
假设我们需要部署两个简单的 Web 游戏服务:doudizhu (斗地主) 和 motuo (摩托)。每个服务都基于 Nginx,并包含各自的应用代码。
1. 项目结构
/oldboyedu/docker-compose/01-motuo-doudizhu/
├── docker-compose.yaml
└── dockerfile/
├── code/
│ ├── oldboyedu-doudizhu.tar.gz
│ └── oldboyedu-motuo.tar.gz
├── config/
│ ├── doudizhu.conf
│ └── motuo.conf
├── scripts/
│ └── start.sh
├── doudizhu.dockerfile
└── motuo.dockerfile
2. Docker Compose 配置文件 (docker-compose.yaml)
# 声明 docker compose 的版本号
version: '3.8'
# 定义需要管理的服务
services:
# 斗地主服务定义
doudizhu:
# 指定最终镜像的名称和标签
image: linux92-games:doudizhu-v0.1
# 指定镜像的构建信息 (如果本地没有该镜像,Compose 会执行构建)
build:
# 指定构建上下文路径 (Dockerfile 中 ADD/COPY 指令的相对路径起点)
# './dockerfile' 表示 docker-compose.yaml 同级目录下的 dockerfile 文件夹
context: ./dockerfile
# 指定用于构建该服务的 Dockerfile 文件名
dockerfile: doudizhu.dockerfile
# 摩托服务定义
motuo:
image: linux92-games:motuo-v0.1
build:
context: ./dockerfile
dockerfile: motuo.dockerfile
解释:
version: '3.8': 指定了 Compose 文件格式的版本。services: 包含所有要管理的服务定义。doudizhu:和motuo:: 自定义的服务名称。image:: 定义了服务最终使用的镜像名称和标签。build:: 如果指定了build,Compose 会在需要时(如镜像不存在或强制重建)根据提供的context和dockerfile构建镜像。context: 定义了构建上下文的路径。所有Dockerfile中的COPY或ADD指令都是相对于这个路径的。dockerfile: 指定了用于构建该服务镜像的Dockerfile文件名。
3. Dockerfile 文件 (doudizhu.dockerfile, motuo.dockerfile)
这两个 Dockerfile 非常相似,都基于 Alpine Linux,安装 Nginx 和 SSH,配置 SSH 允许 Root 登录,生成 SSH 密钥,并将 Nginx 日志重定向到标准输出/错误流(参考上一篇关于日志管理的文章)。主要区别在于 ADD 和 COPY 指令,它们分别添加了各自的游戏代码压缩包和 Nginx 配置文件。
doudizhu.dockerfile: (内容如您原文所示,添加oldboyedu-doudizhu.tar.gz,复制doudizhu.conf)motuo.dockerfile: (内容如您原文所示,添加oldboyedu-motuo.tar.gz,复制motuo.conf)start.sh: (内容如您原文所示,用于启动 sshd 和 nginx)
4. Docker Compose 基本操作
在包含 docker-compose.yaml 文件的目录 (/oldboyedu/docker-compose/01-motuo-doudizhu/) 下执行以下命令:
-
构建镜像 (
build): 如果docker-compose.yaml中定义了build指令,此命令会根据配置构建或重新构建服务的镜像。root@docker101:/oldboyedu/docker-compose/01-motuo-doudizhu# docker-compose build # ... (构建过程输出,会利用缓存) ... Successfully tagged linux92-games:motuo-v0.1 Successfully tagged linux92-games:doudizhu-v0.1 -
后台创建并启动容器 (
up -d): 这是最常用的命令,它会根据docker-compose.yaml创建(如果不存在)并启动所有服务。-d参数表示在后台 (detached) 模式运行。root@docker101:/oldboyedu/docker-compose/01-motuo-doudizhu# docker-compose up -d [+] Running 2/2 ✔ Container 01-motuo-doudizhu-doudizhu-1 Started ✔ Container 01-motuo-doudizhu-motuo-1 StartedCompose 会自动创建默认网络,并将两个服务的容器连接到该网络。容器名称通常是
<project_name>-<service_name>-<instance_number>的格式。 -
查看服务状态 (
ps): 显示项目中所有容器的状态信息。root@docker101:/oldboyedu/docker-compose/01-motuo-doudizhu# docker-compose ps NAME IMAGE COMMAND SERVICE CREATED STATUS PORTS 01-motuo-doudizhu-doudizhu-1 linux92-games:doudizhu-v0.1 "/bin/sh -x /start.sh" doudizhu 2 minutes ago Up 2 minutes 22/tcp, 80/tcp 01-motuo-doudizhu-motuo-1 linux92-games:motuo-v0.1 "/bin/sh -x /start.sh" motuo 2 minutes ago Up 2 minutes 22/tcp, 80/tcp -
停止服务 (
stop): 停止正在运行的服务容器,但不删除它们。-t参数指定停止超时时间(秒),-t 0表示立即停止。root@docker101:/oldboyedu/docker-compose/01-motuo-doudizhu# docker-compose stop -t 0 [+] Stopping 2/2 ✔ Container 01-motuo-doudizhu-doudizhu-1 Stopped ✔ Container 01-motuo-doudizhu-motuo-1 Stopped root@docker101:/oldboyedu/docker-compose/01-motuo-doudizhu# docker-compose ps # (无输出,因为容器已停止) root@docker101:/oldboyedu/docker-compose/01-motuo-doudizhu# docker ps -a # (可以看到容器状态为 Exited) -
启动已停止的服务 (
start): 启动之前被stop命令停止的服务容器。root@docker101:/oldboyedu/docker-compose/01-motuo-doudizhu# docker-compose start [+] Running 2/2 ✔ Container 01-motuo-doudizhu-motuo-1 Started ✔ Container 01-motuo-doudizhu-doudizhu-1 Started -
重启服务 (
restart): 重启正在运行的服务。可以指定服务名只重启特定服务,或不指定服务名重启所有服务。# 重启 doudizhu 服务 root@docker101:/oldboyedu/docker-compose/01-motuo-doudizhu# docker-compose restart doudizhu [+] Restarting 1/1 ✔ Container 01-motuo-doudizhu-doudizhu-1 Started温馨提示: 服务名 (
doudizhu,motuo) 是在docker-compose.yaml文件的services下定义的键名。 -
停止并删除容器、网络 (
down): 停止所有服务容器,并删除由up命令创建的容器、网络和(可选的)卷。这是清理环境的常用命令。-t参数同样适用。root@docker101:/oldboyedu/docker-compose/01-motuo-doudizhu# docker-compose down -t 0 [+] Running 3/3 ✔ Container 01-motuo-doudizhu-motuo-1 Removed ✔ Container 01-motuo-doudizhu-doudizhu-1 Removed ✔ Network 01-motuo-doudizhu_default Removed root@docker101:/oldboyedu/docker-compose/01-motuo-doudizhu# docker ps -a # (无输出,容器已被删除)
三、 添加端口映射和重启策略
我们可以进一步在 docker-compose.yaml 中定义端口映射和容器重启策略。
# 声明docker compose的版本号
version: '3.8'
# 定义常用的服务
services:
# 斗地主服务
doudizhu:
image: linux92-games:doudizhu-v0.1
# 配置端口映射: [HOST_PORT]:[CONTAINER_PORT]
ports:
- "2481:80" # 将宿主机的 2481 端口映射到容器的 80 端口
- "2422:22" # 将宿主机的 2422 端口映射到容器的 22 端口
# 配置重启策略
# always: 无论退出状态码是什么,总是重启容器
# no: (默认) 不自动重启
# on-failure[:max_retries]: 仅在非 0 退出时重启,可选指定最大重试次数
# unless-stopped: 总是重启,除非容器被手动停止 (docker stop)
restart: always
build:
context: ./dockerfile
dockerfile: doudizhu.dockerfile
# 摩托服务
motuo:
image: linux92-games:motuo-v0.1
# 配置端口映射: 将容器端口映射到宿主机的随机端口
ports:
- ":80" # 宿主机随机端口 -> 容器 80
- ":22" # 宿主机随机端口 -> 容器 22
# (未指定 restart,默认为 no)
build:
context: ./dockerfile
dockerfile: motuo.dockerfile
修改 docker-compose.yaml 后,通常需要重新执行 docker-compose up -d 来应用更改。如果修改了 Dockerfile,可能需要先执行 docker-compose build 或使用 docker-compose up -d --build。
四、 实战案例 2:一键部署 Zabbix 监控系统
Docker Compose 非常适合部署像 Zabbix 这样由多个组件构成的复杂应用。
docker-compose.yaml(/oldboyedu/docker-compose/02-zabbix/docker-compose.yaml)
version: '3.8'
services:
# MySQL 数据库服务
mysql-server:
image: mysql:8.3.0-oracle
container_name: mysql-server # 指定固定容器名
restart: unless-stopped # 推荐的生产环境重启策略
environment: # 通过环境变量配置 MySQL
MYSQL_ROOT_PASSWORD: oldboyedu
MYSQL_DATABASE: zabbix
MYSQL_USER: linux92
MYSQL_PASSWORD: "123456"
networks: # 连接到自定义网络
- zabbix-net
# MySQL 8 需要指定字符集和认证插件以兼容 Zabbix
command: ["--character-set-server=utf8", "--collation-server=utf8_bin", "--default-authentication-plugin=mysql_native_password"]
# Zabbix Java Gateway (用于 JMX 监控)
zabbix-java-gateway:
container_name: zabbix-java-gateway
image: zabbix/zabbix-java-gateway:alpine-6.4-latest
restart: unless-stopped
networks:
- zabbix-net
# Zabbix Server 服务
zabbix-server:
container_name: zabbix-server-mysql
depends_on: # 声明依赖关系,确保 DB 先启动
- mysql-server
# - zabbix-java-gateway # 可选,如果 server 配置需要连接 gateway
image: zabbix/zabbix-server-mysql:alpine-6.4-latest
restart: unless-stopped
environment: # 配置 Zabbix Server 连接 DB 和 Java Gateway
DB_SERVER_HOST: mysql-server # 使用服务名作为主机名
MYSQL_DATABASE: zabbix
MYSQL_USER: linux92
MYSQL_PASSWORD: "123456"
MYSQL_ROOT_PASSWORD: oldboyedu # 可能用于初始化检查
ZBX_JAVAGATEWAY: zabbix-java-gateway # Java Gateway 的服务名
networks:
- zabbix-net
ports: # 暴露 Zabbix Server Agent 监听端口
- "10051:10051"
# Zabbix Web UI (Nginx + PHP-FPM) 服务
zabbix-web-nginx-mysql:
container_name: zabbix-web-nginx-mysql
depends_on: # 依赖 Zabbix Server
- zabbix-server
# - mysql-server # Web UI 也需要直连 DB
image: zabbix/zabbix-web-nginx-mysql:alpine-6.4-latest
ports: # 暴露 Web 访问端口
- "80:8080" # 宿主机 80 映射到容器 8080
restart: unless-stopped
environment: # 配置 Web UI 连接 DB
DB_SERVER_HOST: mysql-server
MYSQL_DATABASE: zabbix
MYSQL_USER: linux92
MYSQL_PASSWORD: "123456"
# MYSQL_ROOT_PASSWORD: oldboyedu # Web UI 通常不需要 root 密码
# ZBX_SERVER_HOST: zabbix-server # Web UI 需要知道 Server 在哪
networks:
- zabbix-net
# 自定义网络定义
networks:
zabbix-net:
name: oldboyedu-zabbix # 指定网络名称
driver: bridge # 使用默认的 bridge 驱动
ipam: # IP 地址管理 (可选,用于静态分配)
driver: default
config:
- subnet: 172.20.100.0/16
gateway: 172.20.100.254
labels: # 为网络添加元数据标签
school.oldboyedu.com: "老男孩IT教育"
class.oldboyedu.com: "Linux92"
auther.oldboyedu.com: "JasonYIN"
关键点分析:
- 多服务协作: 定义了四个核心服务:MySQL 数据库、Zabbix Server、Zabbix Java Gateway 和 Zabbix Web UI。
- 镜像使用: 直接使用了官方提供的预构建镜像。
- 环境变量配置: 通过
environment向各个服务传递数据库连接信息、密码等配置,避免硬编码。 - 服务发现: 在自定义网络
zabbix-net中,服务可以通过其服务名(如mysql-server,zabbix-server)相互访问,Compose 提供了内置的 DNS 解析。 - 依赖管理: 使用
depends_on确保服务按正确的顺序启动(例如,Zabbix Server 依赖于 MySQL)。注意:depends_on只保证容器启动顺序,不保证服务内部完全就绪。对于需要等待服务就绪的场景,可能需要额外的健康检查或等待脚本。 - 自定义网络: 创建了一个名为
oldboyedu-zabbix的独立网络,提供了更好的隔离性,并允许进行 IP 地址规划。 - 端口映射: 只将需要从宿主机访问的端口(Web UI 的 80 端口和 Zabbix Server 的 10051 端口)映射出来。
部署 Zabbix:
在包含此 docker-compose.yaml 的目录 (/oldboyedu/docker-compose/02-zabbix/) 下,只需执行:
docker-compose up -d
Compose 会自动下载所需镜像,创建网络,并按依赖顺序启动所有容器。稍等片刻,即可通过浏览器访问 http://<宿主机IP> (因为我们将宿主机的 80 端口映射到了 Web UI 容器的 8080 端口) 来访问 Zabbix 的 Web 界面。
五、 总结
Docker Compose 是管理多容器应用程序的瑞士军刀。它通过简洁的 YAML 文件实现了对复杂应用架构的声明式定义,极大地简化了开发、测试和生产环境的部署与管理流程。
核心优势:
- 简化管理: 使用简单命令即可管理整个应用的生命周期。
- 环境一致性:确保开发、测试、生产环境的应用栈配置一致。
- 快速部署与复现: 轻松分享和重建应用环境。
- 服务编排: 定义服务依赖、网络连接和数据卷,实现容器间的有效协作。
掌握 Docker Compose 是现代 DevOps 工程师和开发人员的必备技能。通过它,你可以更高效、更可靠地构建和运行容器化应用。
浙公网安备 33010602011771号