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 命令去搜答案,资料多得多。

新手三个建议

  1. 先跑起来,再求甚解。 上面的例子先跑通,有成就感了再回头看字段表。
  2. 改完先 config 再 up。 养成习惯,省排错时间。
  3. 一个项目一个目录。 现在就开始,别等乱了再整理。

下一步

Compose 入门到这就够了。后面几篇小够会讲:Dockerfile 怎么写自己的镜像、数据卷到底存在哪、日志怎么管、容器怎么升级不断档。一步一步来,不着急。下一篇先讲 Dockerfile,把"自己的网站打包成镜像"这事办了。