第 6 篇:Docker Compose 组织后端本地环境
0. 本篇定位
上一篇已经讲清楚 Docker 网络和数据卷:容器之间应该优先用服务名和容器端口通信,外部入口才做端口映射,需要保留的数据要放到 volume,开发态热加载才谨慎使用 bind mount。本篇把这些分散命令收束到一份 compose.yaml 里,讨论 Docker Compose 如何组织一个可复制、可审查、可清理的后端本地环境。
Docker Compose 的价值不是“少敲几条命令”。真正的价值是把后端服务依赖图写成声明:有哪些服务,使用哪些镜像或构建上下文,加入哪个项目网络,注入哪些环境变量,挂载哪些数据卷,暴露哪些端口,依赖启动顺序如何表达,健康检查如何观察。只要这些内容进入版本库,新人、CI、测试环境和排障人员看到的就是同一份环境意图。
读完本篇后,你应该能做到三件事。第一,把 API、MySQL、Redis 这类后端本地依赖组织成清晰的 Compose service graph。第二,解释 depends_on、healthcheck、service name、project network、volume、env file 的职责和边界。第三,知道 Compose 适合本地和集成测试,但不能直接等同于生产级编排系统。
1. 问题背景
没有 Compose 之前,本地后端环境通常靠 README 里的多条命令启动。先创建网络,再创建 volume,再启动 MySQL,再启动 Redis,再启动后端 API,还要记住端口、密码、数据库名、连接串和清理命令。只要其中一步顺序错、参数漏、端口冲突或数据残留,环境就会变成“我这里能跑,你那里不能跑”。
这种问题在团队协作里非常常见。新人第一次启动项目,需要在 Docker 命令、数据库初始化脚本、环境变量和本地配置之间来回跳。CI 跑集成测试时,依赖容器启动了但数据库还没 ready,API 立即连接失败。测试环境因为多个项目共用默认网络和默认卷,服务名互相污染,数据状态也越来越难解释。开发临时改了一个环境变量,但没有写回文档,下一个人继续踩同样的坑。
Compose 要解决的正是这种本地环境漂移。它把多条 docker run 命令组织成项目级声明:服务之间默认进入同一个项目网络,服务名自动成为 DNS 名称,命名 volume 可以被声明和复用,端口映射集中管理,docker compose logs 能聚合多个服务日志,docker compose down 能按策略清理容器、网络和 volume。
但 Compose 也很容易被误用。depends_on 不是万能等待,容器启动不等于服务可用;healthcheck 可以让依赖状态更可观察,但不能替代应用自身的连接重试;Compose 的 volume 适合本地和测试,不等于生产数据库存储方案;Compose 的 service 也不是 Kubernetes Service。理解这些边界,才能把 Compose 用成工程工具,而不是另一种更大的脚本。
2. 核心概念
Compose 可以被理解为“本地后端环境的服务图声明”。它把服务、网络、卷、配置和启动行为放在同一份文件中,让环境从口口相传变成可版本化对象。
| 对象 | 解决什么问题 | 不解决什么问题 | 后端关注点 |
|---|---|---|---|
| service | 描述一个可运行组件 | 不等于 Kubernetes Service | API、MySQL、Redis 的镜像、配置、端口和挂载 |
| project | 给资源加统一命名空间 | 不自动隔离外部共享资源 | 避免网络、容器和 volume 命名冲突 |
| default network | 让同项目服务用服务名通信 | 不跨项目共享,除非显式配置 | API 用 mysql:3306 访问数据库 |
| depends_on | 表达启动依赖关系 | 不保证业务逻辑已经完全 ready | 配合 healthcheck 和应用重试 |
| healthcheck | 用命令观察容器健康状态 | 不替代应用 readiness 设计 | MySQL 可连接、API 健康接口可用 |
| volume | 声明本地持久化数据 | 不等于生产备份和容灾 | 数据库数据是否随 down -v 清理 |
2.1 service graph 与项目边界
Compose 的核心不是单个 service,而是 service graph。后端 API 依赖 MySQL、Redis、消息队列、对象存储和配置文件,这些对象之间有网络关系、配置关系、启动关系和数据关系。compose.yaml 把这些关系放到同一个项目里,读者不用从多条命令里反推环境意图。
Compose project 是资源命名空间。默认情况下,项目名通常来自目录名,也可以通过 --project-name 或环境变量指定。Compose 会用项目名给网络、容器和 volume 加前缀,避免不同项目都叫 mysql、redis 时互相撞车。这个边界对本地多项目开发非常重要,否则你以为连接的是当前项目的 MySQL,实际可能连到了另一个项目残留的容器。
service 名会成为默认网络里的 DNS 名称。例如 service 叫 mysql,同项目里的 api 就可以使用 mysql:3306 连接它。这里的 mysql 不是镜像名,也不是宿主机名,而是 Compose 网络中的服务名。理解这一点,才能把上一篇的 Docker 网络知识迁移到 Compose。
2.2 环境变量、端口和网络的分工
环境变量负责把运行时差异注入容器。后端常见配置包括 DB_URL、REDIS_URL、SPRING_PROFILES_ACTIVE、连接池大小和日志级别。Compose 可以直接写 environment,也可以通过 env_file 读取 .env 风格文件。团队协作时要明确哪些变量适合提交默认值,哪些变量必须由个人本地文件或 CI Secret 提供。
端口映射只用于宿主机访问容器。ports: ["8080:8080"] 表示宿主机 8080 转发到 API 容器 8080。MySQL 和 Redis 如果只被 API 容器访问,就不一定需要映射到宿主机。减少依赖端口映射,可以显著降低本地端口冲突和安全暴露面。
网络负责服务之间通信。Compose 会为项目创建默认网络,除非你显式声明自定义网络。服务之间访问应该使用 service name 和容器端口,例如 mysql:3306、redis:6379。不要在 API 容器里写 localhost:3306,也不要把宿主机映射端口写进容器间连接串。
2.3 depends_on、healthcheck 与 volume
depends_on 表达启动依赖关系。它可以告诉 Compose 先创建 MySQL 和 Redis,再创建 API。当前 Docker Compose CLI 中也可以结合 condition: service_healthy,让 API 等依赖容器健康后再启动。但这仍然不是完整的业务 ready 保证,因为健康检查只代表你定义的那个检查命令通过,不代表数据库迁移完成、缓存预热完成或外部依赖都可用。
healthcheck 负责把“进程启动了没有”推进到“服务是否可用”。MySQL 容器进程启动后,数据库可能还在初始化;Redis 进程启动后,可能还没准备好接受命令;API 进程启动后,健康接口可能因为数据库未连接而失败。healthcheck 能把这种状态暴露到 docker compose ps 和事件里,让排障不再只靠日志猜测。
volume 负责持久化本地状态。声明 mysql-data:/var/lib/mysql 后,删除 MySQL 容器不会自动删除数据。docker compose down 默认会删除容器和网络,但保留命名 volume;docker compose down -v 才会删除声明的 volume。这个区别非常关键,因为它决定你的测试环境是保留数据、重用数据,还是每次干净重建。
3. 运行机制
Compose 的运行机制可以理解成“读取声明、规范化配置、创建项目资源、启动服务、持续观察状态”。它不只是按顺序执行命令,而是把一份文件转成一组 Docker 网络、volume 和容器。
read compose.yaml -> interpolate variables -> calculate project name -> create network and volumes -> create service containers -> attach services to project network -> start services by dependency graph -> run healthchecks and collect logs3.1 从 compose.yaml 到项目资源
Compose 首先读取 compose.yaml,解析 services、networks、volumes、profiles 等字段,并处理环境变量插值。比如 ${MYSQL_PASSWORD} 会从 shell 环境或 .env 文件中读取。这个阶段的错误通常是 YAML 语法错误、变量缺失、缩进错误、字段位置错误或路径不存在。
接着 Compose 计算 project name,并据此创建默认网络、命名 volume 和容器名称。即使 service 叫 mysql,实际容器名也可能带项目名前缀。这个设计的好处是多个项目可以同时存在,坏处是如果你手工写死 container_name,反而可能破坏这种隔离能力。除非确实需要和外部系统固定对接,否则不建议给本地业务 service 随意写 container_name。
资源创建完成后,服务会加入项目网络,service name 成为 DNS 名称。API 容器用 mysql:3306 访问数据库,本质上就是通过项目网络内的 DNS 解析到 MySQL service 对应容器。只要服务在同一项目网络中,就不需要 MySQL 暴露宿主机端口。
3.2 启动顺序、健康状态和日志聚合
Compose 会按照 service graph 启动服务。没有依赖关系的服务可以并行启动,有依赖关系的服务按声明顺序处理。depends_on 能减少明显的启动竞态,但它不是应用层容错。即使等待 MySQL 健康,API 仍应该具备连接重试能力,因为数据库可能在后续运行中重启,网络也可能短暂抖动。
healthcheck 会在容器内部周期执行命令,并把结果记录到容器健康状态里。比如 MySQL 可以用 mysqladmin ping 检查,Redis 可以用 redis-cli ping,API 可以用 curl http://localhost:8080/actuator/health。健康检查命令应该轻量、稳定、能代表服务最低可用性,不要把复杂业务流程塞进去。
docker compose logs 能聚合多个服务的 stdout 和 stderr。相比单独 docker logs,它更适合观察启动顺序和依赖关系。比如 API 报数据库连接失败时,可以同时看到 MySQL 是否还在初始化、Redis 是否已经 ready、API 是否读取到了正确的环境变量。日志聚合是 Compose 对后端本地排障最直接的提升。
3.3 伪代码:Compose 如何启动一组后端服务
可以用下面的伪代码理解 Compose 的执行路径。它不是 Docker Compose 源码,但可以帮助你按阶段定位问题。
function composeUp(file, options): model = parseComposeFile(file) model = interpolateEnvironment(model, options.env) project = resolveProjectName(model, options)
desiredResources = planResources(project, model) ensureNetworks(desiredResources.networks) ensureVolumes(desiredResources.volumes)
graph = buildServiceDependencyGraph(model.services)
for service in topologicalOrder(graph): image = resolveImageOrBuild(service) config = mergeServiceDefaults(service, project) container = createOrReuseContainer(config) attachNetworks(container, config.networks) mountVolumes(container, config.volumes) publishPorts(container, config.ports) startContainer(container)
if service.dependsOnHealth: waitUntilHealthy(service.dependencies)
streamLogs(project.services) return observeProjectState(project)这段伪代码给出几个排障切入点。解析失败看 YAML 和变量;资源创建失败看网络、volume、路径和权限;镜像阶段失败看 image 或 build;容器创建失败看端口、挂载和环境变量;启动后失败看服务日志和退出码;健康等待失败看 healthcheck 命令本身和依赖服务状态。
这里还有一个容易误解的点:Compose 负责启动和连接本地服务,但不会替你设计应用级韧性。API 仍然应该有数据库连接重试、启动超时、优雅关闭、健康接口和日志输出。Compose 能降低启动竞态,不能把一个脆弱应用变成健壮应用。
4. 最小可运行示例
下面用一个 compose.yaml 管理 API、MySQL 和 Redis。示例保留了后端本地环境最关键的内容:服务名通信、API 端口映射、MySQL volume、依赖 healthcheck 和环境变量注入。
4.1 编写 compose.yaml
services: api: image: registry.example.com/order-api:1.0.0 ports: - "8080:8080" environment: SPRING_PROFILES_ACTIVE: local DB_URL: jdbc:mysql://mysql:3306/order DB_USERNAME: root DB_PASSWORD: example REDIS_URL: redis://redis:6379 depends_on: mysql: condition: service_healthy redis: condition: service_healthy
mysql: image: mysql:8 environment: MYSQL_ROOT_PASSWORD: example MYSQL_DATABASE: order volumes: - mysql-data:/var/lib/mysql healthcheck: test: ["CMD", "mysqladmin", "ping", "-h", "localhost", "-pexample"] interval: 5s timeout: 3s retries: 20
redis: image: redis:7 healthcheck: test: ["CMD", "redis-cli", "ping"] interval: 5s timeout: 3s retries: 20
volumes: mysql-data:这个文件没有显式声明网络,因为 Compose 会为项目创建默认网络。api 通过 mysql 和 redis 访问依赖,不需要写 IP。只映射 api 的 8080,因为宿主机只需要访问后端入口,不需要直接访问 MySQL 和 Redis。
4.2 启动、观察和进入服务
启动项目:
docker compose up -d查看服务状态:
docker compose psdocker compose logs -f apidocker compose logs -f mysql redis验证 API 容器内能解析依赖:
docker compose exec api getent hosts mysqldocker compose exec api getent hosts redis如果 API 镜像很精简,没有 getent 或 shell,可以临时启动一个调试容器加入同一个项目网络。更简单的方式是先通过 docker compose ps 看容器名,再用 docker network inspect 确认网络成员。学习阶段可以准备一个 debug profile,生产镜像则不必为了调试塞满工具。
4.3 重建、清理和保留数据
如果只修改了 API 镜像版本,可以拉取并重建 API:
docker compose pull apidocker compose up -d --no-deps api如果修改了 compose.yaml,可以重新应用声明:
docker compose up -d停止并删除容器和网络,但保留命名 volume:
docker compose down连同命名 volume 一起删除:
docker compose down -vdown 和 down -v 的区别必须写进团队文档。前者适合重启本地环境但保留数据库数据;后者适合重新初始化干净环境。测试脚本如果使用 down -v,要确认它不会误删开发者想保留的数据。
5. 配置逐行拆解
Compose 文件的关键不是字段多,而是字段之间的关系要清楚。后端工程里最重要的关系包括:service 名如何变成 DNS 名称,环境变量如何指向服务名,端口映射是否只暴露外部入口,volume 是否挂到正确数据目录,healthcheck 是否能表达依赖可用性。
5.1 services、image 和 build
services 是 Compose 文件的主体。每个 service 描述一个可运行组件,可以是业务 API,也可以是数据库、缓存、消息队列或本地模拟服务。service 名要稳定、短、和连接串一致。api、mysql、redis 比 my-db-container-1 更适合作为本地环境声明。
image 表示直接使用已有镜像,适合数据库、中间件和已经由 CI 构建好的业务镜像。build 表示从本地 Dockerfile 构建镜像,适合开发态本地调试。团队要明确什么时候用 image,什么时候用 build。如果 CI 里用的是 image,本地却默认 build,就可能出现“本地构建能跑,发布镜像不能跑”的差异。
不要随意写 container_name。Compose 自动生成的容器名包含项目名,可以避免多个项目冲突。手工固定容器名会让同一个项目无法并行启动多个副本,也容易和别人的本地容器撞名。只有当外部工具必须依赖固定容器名时,才考虑使用。
5.2 environment、env_file、ports 和 expose
environment 适合写少量清晰的运行时变量。连接串应使用 service name,例如 jdbc:mysql://mysql:3306/order。不要写 localhost:3306,除非应用进程和数据库进程在同一个容器内,而这通常不是推荐设计。也不要写宿主机映射端口,因为容器间通信走的是项目网络。
env_file 适合把较多变量放到文件里,例如 .env.local。但要注意,.env 同时也可能被 Compose 用于变量插值,团队要明确命名和加载规则。敏感值不应直接提交到公开仓库。对于个人开发,可以提交 .env.example,真实 .env.local 由开发者自己创建。
ports 表示宿主机端口映射,expose 只表达容器间可见端口意图,不会映射到宿主机。对于后端本地环境,API 通常需要 ports,数据库和缓存不一定需要。依赖服务不映射端口时,宿主机不能直接访问它们,但同项目 service 仍然可以通过服务名访问。
5.3 depends_on、healthcheck、volumes 和 profiles
depends_on 用来表达启动依赖。配合 condition: service_healthy 时,API 可以等 MySQL 和 Redis 通过健康检查后再启动。但应用仍然需要连接重试,因为依赖后续可能重启或短暂不可用。Compose 是本地编排工具,不是应用韧性的替代品。
healthcheck 的命令要足够轻量。MySQL 用 mysqladmin ping,Redis 用 redis-cli ping,API 用健康接口。检查命令太复杂会让本地启动变慢,也容易把业务数据状态和基础可用性混在一起。健康检查的目标是判断“现在是否适合依赖它”,不是跑完整业务验收。
volumes 要区分命名 volume 和 bind mount。数据库数据优先使用命名 volume;源码热加载可以使用 bind mount;配置文件挂载要明确只读,例如 ./config:/app/config:ro。profiles 可以把非必要服务做成可选项,例如本地调试时才启动链路追踪或管理 UI,避免默认环境过重。
6. 后端工程场景
Compose 最适合解决本地和集成测试环境的一致性问题。它不负责所有生产治理,但能把团队从“手工启动依赖”推进到“声明式组织依赖”。
6.1 新人启动和本地开发
优秀的后端项目应该让新人尽量少猜环境。理想情况下,README 里只有三步:复制 .env.example,执行 docker compose up -d,访问 http://localhost:8080/actuator/health。如果新人需要手工创建网络、手工启动数据库、手工导入脚本、手工改连接串,说明环境声明还不完整。
本地开发可以有两种模式。第一,API 也在 Compose 里运行,依赖地址写 mysql:3306、redis:6379。第二,API 在 IDE 中运行,依赖容器在 Compose 中运行,这时需要把 MySQL 或 Redis 端口映射到宿主机,IDE 连接串写 localhost:3306 或 localhost:6379。这两种模式要在文档中分开,不要混成一套配置。
如果支持热加载,可以给 API service 增加开发 profile 或覆盖文件,例如 compose.override.yaml,把源码 bind mount 进去。但默认生产镜像构建流程不要依赖本地 bind mount。开发便利和交付制品要分开,否则很容易出现“本地运行的不是镜像真实内容”的问题。
6.2 集成测试和 CI
CI 中使用 Compose 时,重点是隔离和可清理。每个流水线任务应该使用唯一 project name,避免并发任务共享网络和 volume。可以用分支名、提交 SHA 或流水线 ID 作为项目名。任务结束后执行 docker compose down -v 清理临时资源,防止数据残留影响下一次测试。
集成测试不应该只等容器进程启动。MySQL 初始化、迁移脚本执行、Redis ready、API 健康接口可用,都可能需要时间。Compose 的 healthcheck 能帮你减少“依赖还没好就跑测试”的问题,但测试脚本仍应对 API 健康接口做等待,而不是直接 sleep 固定秒数。
失败时要保留证据。CI 可以在失败后输出 docker compose ps、docker compose logs、docker compose config 和关键容器的 inspect。不要只保存测试失败断言。很多集成测试失败不是业务断言错,而是依赖服务没有 ready、环境变量缺失、端口冲突或数据库残留。
6.3 从 docker run 到 Compose,再到 Kubernetes
从手工 docker run 迁移到 Compose 的关键,是把隐含知识变成显式声明。以前写在 README、聊天记录和个人脚本里的网络、端口、volume、环境变量、启动顺序,都应该进入 compose.yaml。这样本地环境才有版本记录,也能被 code review。
从 Compose 迁移到 Kubernetes 时,不是机械地把 YAML 转换成 YAML。Compose service 更像本地服务声明,Kubernetes 里通常要拆成 Deployment、Service、ConfigMap、Secret、PVC、Ingress 等对象。Compose 的 service name 思想可以迁移到 Kubernetes Service name;Compose volume 思想可以迁移到 PVC;Compose healthcheck 思想可以迁移到 readiness/liveness/startup probes。
最重要的是识别边界:Compose 适合本地和测试环境组织,Kubernetes 适合生产级调度和控制循环。Compose 帮你学会服务图和环境声明,Kubernetes 则进一步接管副本、滚动发布、自动恢复、服务发现、网络入口、资源限制和存储声明。
7. 常见错误与排障
Compose 排障要先看“声明最终长什么样”,再看“资源是否创建”,最后看“服务运行是否符合预期”。不要一上来就删容器或改 YAML,因为你可能会丢掉最有价值的运行态证据。
7.1 API 连接依赖失败
API 报数据库连接失败时,先确认 API 是在容器里运行还是在宿主机 IDE 里运行。如果 API 在容器里,连接串应该是 mysql:3306;如果 API 在宿主机 IDE 里,则需要 MySQL 映射宿主机端口,连接串才可能是 localhost:3306。运行位置不同,网络路径完全不同。
如果 API 在 Compose 中运行,继续看 service 是否在同一个项目网络里。
docker compose psdocker compose logs api --tail 100docker compose logs mysql --tail 100docker compose exec api getent hosts mysqldocker compose config能解析 mysql 但连接失败,可能是 MySQL 还没 ready、账号密码错误、数据库名不存在或端口没监听。不能解析 mysql,优先看 service 名、项目网络和是否使用了不同 project name。depends_on 写了也不代表数据库业务可用,必须结合 healthcheck 和应用日志判断。
7.2 环境变量、端口和数据污染
环境变量不生效时,先看最终渲染结果。
docker compose configdocker compose exec api envdocker inspect $(docker compose ps -q api)docker compose config 能看到 Compose 解析后的声明,适合排查变量插值和 YAML 合并问题;env 和 inspect 能看到容器运行态实际环境。不要只看 .env 文件,因为变量可能被 shell 环境、override 文件或 CI 参数覆盖。
端口被占用时,错误通常发生在宿主机端口绑定。解决方案不是修改容器内部端口,而是换宿主机端口或减少端口映射。例如 18080:8080 表示宿主机用 18080 访问 API,容器内部仍然监听 8080。依赖服务如果只给 API 使用,可以不映射端口。
数据污染通常来自 volume 复用。docker compose down 不删除命名 volume,所以数据库数据会保留。想重置环境需要执行 docker compose down -v,或者手工删除对应 volume。团队要明确哪些测试保留数据,哪些测试必须干净初始化,避免把残留数据误判成业务 bug。
7.3 证据链模板
Compose 排障可以按下面的顺序收集证据。
docker compose configdocker compose psdocker compose logs --tail 200docker compose events如果是单个服务异常,再看服务日志和容器事实。
docker compose logs api --tail 200docker compose exec api envdocker inspect $(docker compose ps -q api)如果是网络问题,看项目网络。
docker network lsdocker network inspect <project>_default如果是 volume 问题,看声明和运行态挂载。
docker volume lsdocker volume inspect <project>_mysql-datadocker inspect $(docker compose ps -q mysql)最后把排障结论写回 compose.yaml、.env.example、README 或 CI 脚本。临时在本机修改环境变量、手工连接网络、手工删 volume,只能解决一次问题;写回声明,才能让团队环境变得更稳。
8. 生产化边界
Compose 是后端本地工程化的重要工具,但它不是完整生产编排平台。它可以帮助你建立服务图、配置注入、网络隔离和数据卷意识,却不能替代生产级调度、弹性、发布、观测和安全体系。
8.1 Compose 不是生产调度器
Compose 可以启动多个容器,但它没有 Kubernetes 那样的集群调度、节点故障迁移、滚动发布控制、声明式副本管理和服务治理能力。一个 Compose 项目在单台机器上跑得很好,不代表它能承受节点宕机、灰度发布、资源抢占和多实例流量分配。
Compose 的 restart 策略也不是完整自愈体系。容器退出后可以重启,但它不知道业务流量是否被正确摘除,不知道多副本是否平滑替换,也不负责跨节点重新调度。后端服务如果要上线生产,需要进入更完整的发布系统或 Kubernetes 平台。
这并不贬低 Compose。Compose 的定位是把本地和测试环境的依赖声明化,让团队用低成本理解服务图。正因为它简单,才适合学习和开发。但不要把简单工具硬推到它不擅长的生产问题上。
8.2 配置、密钥和数据的边界
本地 Compose 文件里可以用示例密码,但真实密钥不能直接提交。至少要区分 .env.example 和本地 .env.local,并把真实文件加入忽略列表。CI 中的敏感值应该来自流水线 Secret,生产中则进入平台密钥系统。
数据库 volume 在本地很方便,但生产数据需要备份、恢复、权限、加密、容量监控和迁移流程。docker compose down -v 对本地来说是重置环境,对生产来说可能是灾难。任何会删除 volume 的命令都应该被限制在明确的开发或 CI 上下文里。
配置还要可审查。compose.yaml 适合提交默认拓扑,环境差异可以通过 override 文件、profile 或 CI 参数表达。但不要让每个人维护一份完全不同的 Compose 文件,否则又会回到“我这里能跑”的状态。差异可以存在,但差异必须有命名、有边界、有文档。
8.3 迁移到 Kubernetes 的映射关系
Compose 中的 service graph 可以迁移为 Kubernetes 对象组合。业务 API service 通常会变成 Deployment 加 Service;数据库如果仍由平台内运行,可能需要 StatefulSet、PVC 和 Service;环境变量会进入 ConfigMap 和 Secret;健康检查会进入 startupProbe、readinessProbe、livenessProbe;外部入口会进入 Ingress 或 Gateway。
迁移时要避免机械转换。Compose 的 depends_on 在 Kubernetes 里通常不是同样的对象,而是由应用重试、initContainer、readinessProbe 和依赖服务可用性共同解决。Compose 的 ports 也不能简单等同于 Kubernetes Service 和 Ingress。二者抽象层级不同,不能只按字段名迁移。
更好的方式是沿着职责迁移:服务发现迁移到 Service,外部入口迁移到 Ingress 或 Gateway,配置迁移到 ConfigMap 和 Secret,状态数据迁移到 PVC,健康检查迁移到探针,发布策略迁移到 Deployment rollout。这样迁移出来的 Kubernetes 配置才是平台化设计,而不是 Compose 文件的翻译稿。
9. 什么时候用,什么时候不用
Compose 的边界很清楚:它适合组织本地和测试依赖,不适合替代生产编排。用得好,它是团队环境一致性的加速器;用错了,它会变成生产治理缺失的遮羞布。
9.1 适合使用的场景
本地开发非常适合 Compose。一个命令启动 API、数据库、缓存和模拟服务,一个命令查看聚合日志,一个命令清理环境。对新人和跨团队协作来说,这比手工命令可靠得多。
集成测试也适合 Compose。测试任务可以创建独立 project,启动依赖服务,等待健康检查,通过后执行测试,失败时收集日志和状态,结束后清理资源。相比共享一套长期运行测试环境,这种方式更可重复。
技术学习和架构推演也适合 Compose。你可以用它观察服务名解析、端口映射、volume 生命周期、健康检查和启动依赖,再把这些概念迁移到 Kubernetes。它是从单机 Docker 到集群编排之间很自然的过渡层。
9.2 不适合直接使用的场景
生产高可用服务不适合只靠 Compose。它缺少集群调度、滚动发布、自动扩缩容、复杂流量治理、网络策略和平台级观测。小团队可以在极简部署中临时使用,但必须清楚风险和恢复方式。
关键数据库不适合只靠 Compose volume 保障。volume 能保留本机数据,但不能替代备份、恢复、快照、跨节点存储和权限治理。生产数据要用更成熟的数据库服务或平台存储方案。
多租户、多环境、大规模服务治理也不适合靠一份 Compose 文件硬撑。服务数量增多后,配置差异、资源限制、发布顺序、密钥管理和观测都需要平台能力。Compose 的优势是简单,不是无限扩展。
9.3 默认建议
默认建议是:本地后端依赖用 Compose 组织,API 入口映射宿主机端口,内部依赖走 service name,数据库数据用命名 volume,开发态热加载用 override 或 profile,敏感配置只提交示例,不提交真实值。
排障默认顺序是:先 docker compose config 看最终声明,再 docker compose ps 看服务状态,然后 docker compose logs 看多服务日志,最后用 inspect、exec 和网络/volume 命令看运行态事实。不要先删容器,也不要先猜 YAML。
演进默认路径是:先把手工 docker run 收束为 Compose,再把 Compose 里的职责映射到 Kubernetes 对象。Compose 不是终点,而是帮助你把后端环境从“个人机器状态”推进到“团队可版本化声明”的关键台阶。
10. 下一篇衔接
下一篇会讨论“从 Docker Compose 迁移到 Kubernetes”。这不是简单的工具替换,而是抽象层级升级:Compose 解决本地服务图,Kubernetes 解决集群期望状态;Compose service name 迁移到 Kubernetes Service;Compose volume 迁移到 PVC;Compose healthcheck 迁移到探针;Compose 的环境变量和 env file 迁移到 ConfigMap 与 Secret。
读下一篇前,可以先检查自己是否能解释这些问题:Compose project name 为什么重要,service name 为什么能当 DNS 名称,depends_on 为什么不能替代应用重试,docker compose down 和 down -v 有什么区别,为什么数据库和缓存通常不需要映射宿主机端口。如果这些问题清楚,迁移到 Kubernetes 时就不会只盯着 YAML 字段名。