docker-compose编排多容器怎么写
多个容器要一起跑时一个个启动太累。compose 用一个 YAML 文件把所有服务的镜像、端口、环境变量、数据卷、网络、依赖全描述清楚,一条命令全拉起。同一网络下服务名能直接当主机名互连。depends_on 只保证启动顺序,依赖数据库要配 healthcheck 才稳。
用 Docker 跑单个容器挺爽,一行 docker run 搞定。
但真实项目哪有单打独斗的?一个后端要配 MySQL、要配 Redis,可能还有 Nginx。三四个容器,每个都 docker run 带一长串参数,敲到手软,还得记住谁先启谁后启、谁连谁。
这时候 docker-compose 就该登场了。它让你用一个 YAML 文件把这一摊服务描述清楚,一条命令全拉起来。这篇把 compose 文件怎么写、怎么生效、效果如何,讲明白。
compose 解决什么
先说清它的定位:docker-compose 是用来编排多个容器的工具。
单容器用 docker run,多容器之间有依赖、要互联、要统一管理,就用 compose。
它的核心是一个 docker-compose.yml 文件。你把每个服务(容器)长什么样、用什么镜像、开什么端口、挂什么目录、依赖谁,全写进去。
然后 docker compose up 一条命令,它照着文件把所有容器按顺序创建、连好网络、跑起来。
一句话:把一堆 docker run 参数,变成一个可读、可版本管理的配置文件。
一个完整例子
直接上实例最直观。假设要跑"一个 Go 后端 + MySQL + Redis"的组合,docker-compose.yml 这么写:
# compose 文件版本,3.8 兼容性较好
version: "3.8"
# services 下面每一项就是一个容器
services:
# 服务名叫 app,就是我们的后端
app:
# 用当前目录的 Dockerfile 构建镜像
build: .
container_name: mebugs-app
# 端口映射:宿主机 8080 -> 容器 8080
ports:
- "8080:8080"
# 环境变量,传给程序读
environment:
- DB_HOST=mysql
- REDIS_HOST=redis
# 依赖关系:等 mysql、redis 起来再启动 app
depends_on:
- mysql
- redis
# 加入同一个网络,服务间才能用服务名互相访问
networks:
- mebugs-net
mysql:
image: mysql:8.0
container_name: mebugs-mysql
environment:
- MYSQL_ROOT_PASSWORD=mebugs123
- MYSQL_DATABASE=site_ol
ports:
- "3306:3306"
# 数据卷:把数据存到宿主机,容器删了数据还在
volumes:
- mysql-data:/var/lib/mysql
networks:
- mebugs-net
redis:
image: redis:7
container_name: mebugs-redis
ports:
- "6379:6379"
networks:
- mebugs-net
# 声明命名数据卷
volumes:
mysql-data:
# 声明自定义网络
networks:
mebugs-net:
一个文件,三个服务,依赖、端口、数据卷、网络全交代清楚了。
几个关键配置解释
上面的例子里有几个常用项,单独说说它们干嘛的。
- image / build:
image直接用现成镜像(如mysql:8.0);build是用 Dockerfile 现场构建。二选一。 - ports:端口映射,格式
宿主机端口:容器端口。不写就外部访问不到。 - environment:往容器里塞环境变量,程序和镜像都靠它读配置(比如数据库密码)。
- depends_on:控制启动顺序。注意它只保证"容器启动顺序",不保证"服务真的 ready"——MySQL 容器起来了不代表数据库能连了,这点坑后面说。
- volumes:数据持久化。容器是临时的,删了数据就没,挂 volume 把数据存宿主机上才安全。
- networks:自定义网络。同一网络下的服务,可以直接用服务名当主机名互相访问。
最后这条特别关键。看例子里 app 的环境变量 DB_HOST=mysql——这个 mysql 就是服务名。compose 自动做了内部 DNS,app 容器里连 mysql:3306 就能连到 MySQL 容器,不用管它的 IP。这是 compose 最省心的地方之一。
怎么让它生效
文件写好,常用命令就这几个。
启动全部服务:
# -d 表示后台运行,不加会把日志糊你一脸
docker compose up -d
第一次跑会拉镜像、建网络、建卷、按 depends_on 顺序启动容器。之后再 up 只会启没在跑的。
看状态和日志:
docker compose ps # 看哪些服务在跑
docker compose logs -f app # 跟踪 app 服务的实时日志
停止和清理:
docker compose stop # 停止但保留容器
docker compose down # 停止并删除容器、网络(卷默认保留)
docker compose down -v # 连数据卷一起删,谨慎用,数据会没
改了 docker-compose.yml 之后,重新 up -d,compose 会对比差异,只重建变化的服务,没变的不动。
补充:老版本是
docker-compose(带横杠,独立命令),新版 Docker 把它集成成了docker compose(空格,子命令)。两者用法基本一致,新环境优先用后者。
depends_on 的坑
前面埋了个伏笔,这里展开。
depends_on 只管"容器谁先启动谁后启动",不管"服务是否真的可用"。
MySQL 容器"启动"很快,但容器起来到数据库真正能接受连接,中间还要初始化几秒。这期间 app 要是急吼吼去连,照样连不上报错。
想真正等到服务 ready,得加健康检查 healthcheck:
mysql:
image: mysql:8.0
# ... 省略其他
healthcheck:
# 用 mysqladmin ping 探测数据库是否真能响应
test: ["CMD", "mysqladmin", "ping", "-h", "localhost"]
interval: 5s
timeout: 3s
retries: 5
app:
# 等 mysql 健康检查通过再启动,而不只是容器起来
depends_on:
mysql:
condition: service_healthy
加上 condition: service_healthy,app 才会真正等到 MySQL 能连了再启动。这个细节不处理,本地偶尔好偶尔坏,排查半天才发现是启动竞态。
小结
docker-compose 是多容器编排工具,用一个 docker-compose.yml 把一堆服务的镜像、端口、环境变量、数据卷、网络、依赖关系全描述清楚,docker compose up -d 一键拉起。
记住几个关键点:同一自定义网络下服务名可直接当主机名互连;数据要持久化就挂 volume;端口要外部访问就配 ports。
最容易栽的是 depends_on 只保证启动顺序不保证服务就绪,依赖数据库这类场景要配 healthcheck + service_healthy 才稳。
把常用的那几个命令和配置项记熟,日常本地起一套开发环境,比敲一长串 docker run 舒服太多了。
