Docker Compose 入门:一个文件管起多个容器
单个容器用 docker run 还行,应用一多就乱套。Compose 让你用一个 YAML 文件描述所有容器、网络和数据卷,一条命令全拉起来。小够带你从零写出第一个 compose 文件,再讲透常用字段和命令。
我是小够,只推够用的 VPS。
昨天把 Docker 装好了,今天解决下一个痛点:容器一多,docker run 后面跟十几个参数,记不住、易出错、换机器还得重来。Compose 就是干这个的——用一个 YAML 文件把所有容器、网络、数据卷写清楚,一条命令全部拉起来。
先看一个最小例子
建个目录,写个 docker-compose.yml:
services:
web:
image: nginx:alpine
ports:
- "8080:80"
restart: unless-stopped
然后:
docker compose up -d
打开 http://你的服务器IP:8080,Nginx 欢迎页出来了。就这么简单。-d 是后台运行,不加的话日志会占住终端。
停掉:
docker compose down
容器删掉了,但刚才没挂数据卷,所以这个例子里本来也没啥可留的——数据卷是下一篇的主题。
文件里每一行是什么意思
services::你要跑的容器列表,每个服务就是一个容器。web::服务名,自己起,容器之间用这个名字互相访问。image::用的镜像,nginx:alpine是轻量版 Nginx。ports::"8080:80"表示把容器的 80 端口映射到主机的 8080 端口,格式是"主机:容器"。restart: unless-stopped:容器挂了自动重启,服务器重启也自动拉起来。除非你手动停掉,否则它一直在。
YAML 对缩进敏感,统一用两个空格,别用 Tab。这是新手报错最多的地方,记住就行。冒号后面要有空格,image:nginx 是错的,image: nginx 才对。
再加一个数据库,感受编排
真正的应用很少只有一个容器。加个 MySQL:
services:
web:
image: nginx:alpine
ports:
- "8080:80"
restart: unless-stopped
db:
image: mysql:8.0
environment:
MYSQL_ROOT_PASSWORD: 这里换成你自己的强密码
volumes:
- db-data:/var/lib/mysql
restart: unless-stopped
volumes:
db-data:
environment 传环境变量,volumes 让数据落到具名数据卷里——容器删了数据还在。改完文件再跑一次 docker compose up -d,Compose 只会更新变化的部分,没变的容器不动。这个"增量更新"的特性,改配置时特别省心。
这里有个细节:web 和 db 在同一个 compose 项目里,默认就在同一个网络,web 容器里可以直接用 db 这个主机名访问数据库,不用记 IP。这是 Compose 最省心的地方之一,也是它比一堆 docker run 强的地方:网络、依赖都帮你管了。
常用字段速览
| 字段 | 干嘛的 | 例子 |
|---|---|---|
image | 用哪个镜像 | nginx:alpine |
ports | 端口映射(主机:容器) | "8080:80" |
volumes | 数据卷/目录挂载 | db-data:/var/lib/mysql |
environment | 环境变量 | MYSQL_ROOT_PASSWORD: xxx |
restart | 重启策略 | unless-stopped |
depends_on | 启动顺序依赖 | depends_on: [db] |
networks | 指定网络 | 见进阶篇 |
command | 覆盖默认启动命令 | command: --verbose |
container_name | 指定容器名 | 一般不用,默认的就行 |
depends_on 只保证启动顺序,不等数据库真正就绪——这个坑进阶篇会讲怎么用 healthcheck 填上。container_name 小够不建议写,默认的"目录-服务-序号"命名挺好,写死了反而在扩缩容时碍事。
常用命令就这几个
docker compose up -d # 启动(后台)
docker compose down # 停掉并删容器(数据卷默认保留)
docker compose ps # 看状态
docker compose logs -f # 看日志,-f 持续跟
docker compose logs -f web # 只看 web 服务的日志
docker compose pull # 拉取最新镜像(不重建容器)
docker compose config # 校验文件并打印解析结果,改完先跑它
注意 down 默认不删数据卷,加上 -v 才会删——删之前想清楚,这个月数据卷那篇会细讲。小够见过太多人 down -v 手滑把数据库扬了的。
docker compose config 是个被低估的命令:改完 compose 文件先跑它,YAML 缩进错了、变量没替换,都会直接暴露出来,比 up 了再排错省时间。
文件放哪、怎么管
小够的习惯:每个应用一个目录,里面放 docker-compose.yml,比如 ~/apps/blog/、~/apps/monitor/。目录名无所谓,但一个目录只放一个项目的 compose 文件,因为 Compose 默认用目录名做项目名前缀,混在一起会打架。想自定义项目名可以加 -p 参数:
docker compose -p myblog up -d
另外,docker-compose.yml 里如果写了密码(比如上面的 MySQL 密码),别传到公开仓库。自己用可以建个 .env 文件放敏感信息,Compose 会自动读取同目录的 .env,文件里用 ${MYSQL_PASSWORD} 引用。.env 记得加进 .gitignore,权限设 600。
和 docker run 的关系
Compose 不是魔法,它最后调的还是 Docker,只不过把参数都写进文件了。你完全可以用 docker run 手动复刻,但参数一多就乱。记住这个对应关系,出了问题也知道去哪查:
# 这行 compose
# ports: ["8080:80"]
# 等价于 docker run 的
# -p 8080:80
理解了这层,Compose 出怪问题时,你能翻译成 docker 命令去搜答案,资料多得多。
新手三个建议
- 先跑起来,再求甚解。 上面的例子先跑通,有成就感了再回头看字段表。
- 改完先 config 再 up。 养成习惯,省排错时间。
- 一个项目一个目录。 现在就开始,别等乱了再整理。
下一步
Compose 入门到这就够了。后面几篇小够会讲:Dockerfile 怎么写自己的镜像、数据卷到底存在哪、日志怎么管、容器怎么升级不断档。一步一步来,不着急。下一篇先讲 Dockerfile,把"自己的网站打包成镜像"这事办了。