LabHub
学习 学习路径 课程

卷、网络与 Compose

用一个文件声明整个栈意味着什么

在 LabHub 中继续学习

一句话总结

Compose 文件是以声明方式记录多个容器运行参数的文件。它并非魔法,而是与 docker run 的选项一一对应。

概念图: 以声明方式记录多个容器运行参数的文件 · 因为这些信息没有记录在任何地方 · 第一,Compose 会为每个项目自动创建自定义网络,并把服务名称注册为别名。 · 第二,dependson 只保证顺序,不保证服务已经就绪。

为什么需要它

如果手动启动三个容器,就必须创建网络、创建卷,并按正确顺序为每个容器添加 --network-v-e-p。一个人操作一次没有问题,但从第二个人试图复现同一套栈开始,就会陷入困境,因为这些信息没有记录在任何地方

Compose 真正解决的就是这个问题。整个栈的形态写在一个文件中,并将该文件提交到代码仓库。

工作原理

核心对应关系如下。

Compose 键 对应的 docker run 参数
image 镜像参数
command 镜像后的命令
ports -p
volumes -v / --mount
environment -e
networks --network
depends_on (无对应参数——仅控制启动顺序)

这里必须指出两点。

第一,Compose 会为每个项目自动创建自定义网络,并把服务名称注册为别名。 因此,有些配置“在 Compose 中正常,改成 docker run 就不能工作”。原因不是 Compose 的魔法,而是手动迁移时没有创建网络。

第二,depends_on 只保证顺序,不保证服务已经就绪。 DB 容器“已启动”和数据库“已准备好接受连接”是两回事。因此,必须同时设置健康检查条件,或让应用程序进行重试。忽略这一差别,每次部署后的最初几秒都会涌现连接错误。

实际现场中的情况

实战配置中常用的模式是划分两个网络。前端网络只放反向代理,后端网络放数据库和缓存,只有应用同时加入两边。这样,代理一侧甚至无法解析数据库的名称。

也不要混淆 exposeports。**expose 不会在主机上开放端口,**它只用于文档说明。仅供容器之间通信的服务根本不应使用 ports

最后,声明与实际状态开始偏离的那一刻,就是事故的起点。有人手动修改容器后,文件与现实便会分离,而且在下次部署前无人察觉。因此,养成核对声明与实际状态的习惯非常重要。

正确设置依赖顺序

仅有 depends_on 并不足够。它只表示容器已启动,不表示服务已经就绪。 DB 容器虽已运行,但 PostgreSQL 仍在初始化时,应用会因连接失败而退出。

services:
  db:
    image: postgres:16
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U app"]
      interval: 5s
      timeout: 3s
      retries: 10
      start_period: 10s          # 이 동안의 실패는 세지 않는다
  app:
    build: .
    depends_on:
      db:
        condition: service_healthy    # ← 건강해질 때까지 기다린다

start_period 很重要。如果没有它,初始化过程中的失败会消耗重试次数,使启动较慢的服务最终一直被判定为 unhealthy。

即便如此,应用程序仍必须具备重新连接能力。 生产环境中可能没有 Compose,数据库也可能重启。健康检查只是开发便利功能,不能替代重连逻辑。

按环境叠加文件

可以叠加使用多个 Compose 文件。

docker compose -f compose.yaml -f compose.dev.yaml up

后面的文件覆盖前面的文件。公共配置放在 compose.yaml,开发用挂载和调试端口放在 compose.dev.yamlcompose.override.yaml 仅凭文件名就会自动应用,因此适合存放开发者个人设置(应加入 .gitignore)。

# compose.dev.yaml — 소스를 마운트해 즉시 반영
services:
  app:
    volumes: ["./src:/app/src"]
    environment: {DEBUG: "1"}
    command: ["python", "-m", "uvicorn", "app:app", "--reload"]

Compose 与 Kubernetes 的边界

在 Compose 中正常运行的配置,无法原样搬到 Kubernetes。迁移时会遇到以下差异。

Compose Kubernetes
depends_on 无——改用 initContainer 或重试
按服务名称进行 DNS 解析 相同(Service 名称)
volumes: ./src:/app hostPath——生产环境应避免
restart: always 默认行为(restartPolicy)
ports: 8080:80 Service + Ingress

虽然有 kompose 这类转换工具,但不能直接使用其输出结果,因为其中资源请求与限制、探针、安全上下文全都为空。转换结果只是起点,必须手动补全。

下一项实验要做什么

用 Compose 文件声明一个由两个服务组成的栈,再手动启动相同的栈,然后亲自核对声明的值与实际运行的值是否一致