Docker Compose 实战:从单容器命令到多服务编排
-
- 引言
- [一:为什么需要 Docker Compose?](#一:为什么需要 Docker Compose?)
- [二:Docker Compose 是什么?](#二:Docker Compose 是什么?)
- [三:快速上手:一个 Nginx + PHP 的实例](#三:快速上手:一个 Nginx + PHP 的实例)
-
- [3.1 安装 Docker Compose](#3.1 安装 Docker Compose)
- [3.2 创建项目目录](#3.2 创建项目目录)
- [3.3 编写 docker-compose.yml](#3.3 编写 docker-compose.yml)
- [3.4 启动](#3.4 启动)
- [3.5 查看运行状态](#3.5 查看运行状态)
- [四:docker-compose.yml 核心配置项详解](#四:docker-compose.yml 核心配置项详解)
-
- [4.1 基础结构](#4.1 基础结构)
- [4.2 image](#4.2 image)
- [4.3 container_name](#4.3 container_name)
- [4.4 ports](#4.4 ports)
- [4.5 volumes](#4.5 volumes)
- [4.6 networks](#4.6 networks)
- [4.7 depends_on](#4.7 depends_on)
- 五:常用命令一览
-
- [5.1 容器生命周期管理](#5.1 容器生命周期管理)
- [5.2 查看信息](#5.2 查看信息)
- [5.3 其他实用命令](#5.3 其他实用命令)
- 六:实战经验与避坑指南
-
- [6.1 depends_on 不是万能的](#6.1 depends_on 不是万能的)
- [6.2 网络通信:服务名即域名](#6.2 网络通信:服务名即域名)
- [6.3 环境变量的使用](#6.3 环境变量的使用)
- [6.4 数据持久化](#6.4 数据持久化)
- 七:总结
引言
作为一名后端开发者,你一定经历过这样的场景:本地开发环境需要同时运行 MySQL、Redis、Nginx 和你的应用服务,每次开机都要手动敲一串长长的 docker run,还要操心网络、顺序、数据卷......一旦换了电脑或者同事接手,又得重新回忆那一堆命令。这不只是麻烦,更是效率的杀手。
直到我遇见了 Docker Compose,才真正体会到"一键启停"的快乐。今天,我就带你深入理解这个工具,并用一个实际例子演示如何用它轻松管理多容器项目。
一:为什么需要 Docker Compose?
让我们先感受一下没有 Compose 的"原始时代"。
假设你要启动一个典型的 Web 项目,包含 MySQL、Redis、后端应用和 Nginx。你需要执行类似这样的命令:
bash
# 创建自定义网络
docker network create mynet
# 启动 MySQL
docker run -d --name mysql --network mynet -e MYSQL_ROOT_PASSWORD=root mysql:8.0
# 启动 Redis
docker run -d --name redis --network mynet redis:alpine
# 启动后端(假设已经构建好镜像)
docker run -d --name backend --network mynet -p 8080:8080 my-backend
# 启动 Nginx 代理
docker run -d --name nginx --network mynet -p 80:80 -v ./nginx.conf:/etc/nginx/nginx.conf nginx:alpine
痛点:
- 命令冗长,容易敲错参数。
- 容器启动顺序需要人工控制(比如后端要等 MySQL 和 Redis 就绪)。
- 多个容器需要共享网络,手动创建网络并指定。
- 项目迁移时,需要重新回忆并输入这些命令,不可复制、不可版本化。
而 Docker Compose 正是为解决这些问题而生的。
二:Docker Compose 是什么?
简单来说,Docker Compose 是一个用 YAML 文件定义和运行多个 Docker 容器的工具 。它的核心是一个 docker-compose.yml 文件,里面描述了项目包含哪些服务、每个服务的镜像、端口、数据卷、网络等信息。然后通过一条命令,就能将整个环境创建并启动起来。
本质上,它是将 docker run 的命令行参数"翻译"成了结构化的配置文件,并提供了便捷的管理命令。
三:快速上手:一个 Nginx + PHP 的实例
我们用一个最简单的例子感受一下:启动一个 Nginx 容器和一个 PHP-FPM 容器,让 Nginx 能通过 PHP-FPM 处理 PHP 请求。
3.1 安装 Docker Compose
大多数现代 Linux 发行版都可以通过包管理器直接安装:
bash
# CentOS / RHEL
sudo yum install -y docker-compose
# Ubuntu / Debian
sudo apt install -y docker-compose
当然,你也可以从 GitHub 下载最新的二进制文件。
3.2 创建项目目录
bash
mkdir -p ~/projects/nginx-php && cd ~/projects/nginx-php
3.3 编写 docker-compose.yml
yaml
version: '3.3'
services:
web_nginx:
image: nginx:1.24-alpine
ports:
- "80:80"
links:
- web_php # 让 nginx 能通过服务名访问 php 容器
web_php:
image: php:7-fpm
这个文件定义了两个服务:
web_nginx:使用 nginx 镜像,将宿主机的 80 端口映射到容器的 80 端口,并连接到web_php服务。web_php:使用 php:7-fpm 镜像,内部暴露 9000 端口供 nginx 调用。
注意 :links 在较新的 Docker Compose 中已经不是必须的,因为 Compose 会自动为所有服务创建一个默认网络,服务名就可以作为域名互相访问。但这里保留是为了让初学者理解服务间的连接。
3.4 启动
一定要在 docker-compose.yml 所在的目录执行:
bash
docker-compose up -d
-d 表示后台运行。
3.5 查看运行状态
bash
docker-compose ps
你会看到两个容器已经运行,名称自动被加上项目名前缀(默认是目录名)。
bash
Name Command State Ports
---------------------------------------------------------------------------------------
nginx-php_web_nginx_1 /docker-entrypoint.sh ngin ... Up 0.0.0.0:80->80/tcp
nginx-php_web_php_1 docker-php-entrypoint php-fpm Up 9000/tcp
此时访问 http://你的服务器IP,会看到 nginx 的默认欢迎页,说明两个容器已经成功协作。
四:docker-compose.yml 核心配置项详解
理解了基本用法,我们来逐一拆解 YAML 文件中常见的配置项。
4.1 基础结构
yaml
version: '3.8' # Compose 文件格式版本,与 Docker 引擎版本对应
services: # 定义所有的服务(容器)
服务名1:
# 该服务的配置
服务名2:
# 其他服务的配置
4.2 image
指定服务使用的镜像,相当于 docker run <镜像>。
yaml
services:
app:
image: nginx:1.24-alpine
4.3 container_name
指定容器的自定义名称,如果不写,Compose 会自动生成 项目名_服务名_序号 的格式。
yaml
services:
mysql:
container_name: my-mysql
image: mysql:8.0
提示 :自定义名称后,你无法通过 docker-compose scale 进行水平扩展(因为名称会冲突),所以只在单实例服务中使用。
4.4 ports
端口映射,格式为 "宿主机端口:容器端口"。
yaml
services:
nginx:
ports:
- "80:80"
- "443:443"
4.5 volumes
数据卷挂载,支持三种方式:
- 宿主机绝对路径:
/host/path:/container/path - 相对路径(相对于
docker-compose.yml所在目录):./data:/container/path - 命名卷:先声明,再使用
yaml
services:
web:
volumes:
- ./html:/usr/share/nginx/html # 挂载当前目录下的 html 文件夹
- /etc/nginx/nginx.conf:/etc/nginx/nginx.conf:ro # 只读挂载
# 声明命名卷
volumes:
db_data:
命名卷的声明放在顶层 volumes 下,然后在服务中通过卷名引用:
yaml
services:
mysql:
image: mysql:8.0
volumes:
- db_data:/var/lib/mysql
volumes:
db_data:
4.6 networks
指定服务加入的网络。Compose 会自动创建一个默认网络,所有服务都可以通过服务名互相访问。如果需要自定义网络,可以像下面这样:
yaml
services:
nginx:
networks:
- frontend
app:
networks:
- frontend
- backend
db:
networks:
- backend
networks:
frontend:
backend:
4.7 depends_on
指定服务间的依赖顺序。Compose 会根据 depends_on 的顺序启动容器,但请注意:它只保证容器启动的顺序,不保证容器内的服务已经就绪(比如 MySQL 还没准备好接受连接,后端就启动了)。
yaml
services:
backend:
depends_on:
- mysql
- redis
如果需要等待服务真正就绪,需要借助 wait-for-it 脚本或健康检查。
五:常用命令一览
Docker Compose 的命令几乎都是 docker-compose <子命令> 的形式。以下是我日常最常用的:
5.1 容器生命周期管理
| 命令 | 说明 |
|---|---|
docker-compose up -d |
创建并启动所有容器(后台) |
docker-compose down |
停止并删除所有容器,默认也会删除网络(可通过 -v 同时删除命名卷) |
docker-compose start |
启动已存在的容器 |
docker-compose stop |
停止正在运行的容器 |
docker-compose restart |
重启所有容器 |
docker-compose rm |
删除已停止的容器(加 -f 强制) |
5.2 查看信息
| 命令 | 说明 |
|---|---|
docker-compose ps |
列出当前项目容器状态 |
docker-compose logs |
查看容器日志(加 -f 实时跟踪) |
docker-compose top |
查看每个容器内运行的进程 |
docker-compose images |
列出 Compose 使用的镜像 |
5.3 其他实用命令
docker-compose exec <服务名> <命令>:在运行中的容器内执行命令,例如docker-compose exec web_nginx sh。docker-compose run --rm <服务名> <命令>:运行一次性的命令,完成后自动删除容器,适合执行迁移、测试等。docker-compose up -d --remove-orphans:删除docker-compose.yml中已经不存在的"孤儿"容器,保持环境干净。
六:实战经验与避坑指南
6.1 depends_on 不是万能的
如前所述,depends_on 只能保证容器的启动顺序,但容器内服务未必已就绪。例如后端依赖 MySQL,但 MySQL 容器启动后可能还需要几秒才能接受连接。解决方案:
- 在应用代码中加入重试逻辑。
- 使用脚本等待(例如
wait-for-it.sh)在 entrypoint 中阻塞直到依赖服务可用。
6.2 网络通信:服务名即域名
在 Compose 创建的网络中,每个服务都可以用 docker-compose.yml 中定义的服务名作为主机名互相访问。例如上面的例子,web_nginx 容器内可以通过 web_php:9000 访问 PHP-FPM,非常方便。
6.3 环境变量的使用
推荐在 Compose 文件中使用 ${VARIABLE} 引用外部环境变量,配合 .env 文件管理不同环境的配置。例如:
yaml
services:
mysql:
environment:
MYSQL_ROOT_PASSWORD: ${MYSQL_PASSWORD}
然后在同目录下创建 .env 文件:
MYSQL_PASSWORD=root123
6.4 数据持久化
数据库等有状态服务一定要使用命名卷或宿主机路径挂载,否则 down 之后数据就会丢失。养成好习惯:在 docker-compose down 时不加 -v,或者明确知道数据卷的位置。
七:总结
Docker Compose 让多容器应用的管理变得像单容器一样简单。通过一个声明式的 YAML 文件,我们可以:
- 定义完整的应用栈(包括网络、卷、依赖)。
- 一键启动、停止、重建整个环境。
- 将环境配置纳入版本控制,团队协作更轻松。
希望这篇实战笔记能帮你快速上手 Docker Compose。下次再搭建开发环境时,别忘了用上它,享受那种"一条命令,万物齐备"的畅快感。
如果你有更多关于 Compose 的技巧或踩坑经历,欢迎在评论区分享!