登录
推荐 文章 Go 技术 课程 下载 专题 AI
首页 >  科技周边 >  业界新闻

Docker Compose 网络文档更新,服务发现实践有哪些共识

来源:17golang原创

时间:2026-10-08 17:21:34 287浏览 收藏

Docker Compose 网络配置看起来不复杂,但团队里最常见的故障仍然集中在四件事:把容器 IP 当成固定地址、把主机端口当成容器间端口、让不该互通的服务共享网络,以及容器重建后继续重试旧连接。

当前官方文档给出的方向很明确:Compose 默认网络已经提供服务名发现;容器重建后 IP 可以变化,但服务名保持稳定;容器间通信使用容器端口;需要隔离时再显式拆分网络。

Docker Compose 网络官方文档:https://docs.docker.com/compose/how-tos/networking/

先看结论:服务发现实践形成了哪些共识

  1. 用服务名,不固定容器 IP。同一 Compose 网络中的服务可通过服务名解析。
  2. 容器间使用容器端口。主机端口主要服务于宿主机或网络外部访问。
  3. 默认网络覆盖多数本地开发场景。只有在隔离、跨项目或接入既有网络时才增加自定义网络。
  4. 容器重建后重新解析并重连。旧连接会关闭,客户端不能把旧 IP 缓存成永久地址。
  5. 按证据排查。先看网络成员,再看 DNS 和端口,最后测试实时连通性。

共识一:服务名是稳定入口,容器 IP 不是

执行 docker compose up 时,Compose 通常会为项目创建一个默认网络。加入该网络的服务可以用服务名互相定位。例如应用连接数据库时,目标应写成 db:5432,而不是某个临时的 172.x.x.x 地址。

这条规则的价值在容器重建时最明显:新容器可能获得新 IP,但 db 这个服务名不变。客户端只要重新解析名称,就能找到新实例。

Compose 默认网络服务发现与端口边界说明图

图1:Compose 默认网络中的服务名发现与端口边界说明图。

共识二:容器端口和主机端口必须分开判断

假设数据库配置为 5432:5432,同一 Compose 网络里的应用仍然应连接 db:5432。左侧主机端口用于宿主机访问,右侧容器端口用于容器网络内部通信。

如果写成 db:15432,而 15432 只是映射到宿主机的端口,容器间连接通常会失败。判断时不要只看 YAML 中有没有 ports,还要明确请求从哪里发出。

出现连接异常时,按五层顺序检查

第一层:配置是否符合预期

先确认服务名、容器端口和网络名称。若只是同一项目内的简单互通,不需要额外声明 links;默认网络已经提供基本服务名发现。

第二层:服务是否共享目标网络

两个服务只有加入同一个网络,才具备直接互通的前提。自定义网络最容易出现“配置看着都在,实际没有交集”的问题。

第三层:服务名能否被解析

从发起请求的容器内部解析目标服务名。能解析出地址,说明名称和网络成员大体正确;不能解析时,优先检查服务名拼写、网络归属和外部网络是否存在。

第四层:请求是否用了容器端口

容器内请求应指向目标容器监听的端口。只有从宿主机或网络外部访问时,才使用已发布的主机端口。

第五层:实时连接是否可达

名称解析成功不等于应用正在监听。继续测试目标端口,并检查进程是否绑定到容器可达地址,而不是只绑定 127.0.0.1。

# 查看 db 的 5432 容器端口映射到哪个主机端口
docker compose port db 5432

# 确认容器是否接入目标网络
docker network inspect myapp_backend

# 从 app 容器内重新解析 db 服务名
docker compose exec app getent hosts db

# 从 app 容器内测试 db 的容器端口
docker compose exec app sh -c 'nc -vz db 5432'

用证据快速判断故障位置

观察到的证据优先判断修复动作
服务名无法解析服务不在共享网络、名称写错或外部网络不存在核对 networks、服务名与外部网络创建状态
能解析但连接被拒绝端口写错或目标进程未监听改用容器端口,检查应用监听地址
宿主机可访问,容器间不可访问误用了主机端口或服务不共享网络改为服务名加容器端口,检查网络交集
更新容器后短暂断连旧连接仍指向已移除容器重新解析服务名并建立新连接
跨项目服务互相看不到项目处于不同默认网络显式接入同一个已创建的 external 网络

共识三:自定义网络表达信任边界

默认网络适合简单项目,但当代理不应直接访问数据库时,应通过网络成员关系表达边界。下面的配置让 proxy 只进入前端网络,让 db 只进入内部后端网络,而 app 作为两侧唯一桥接服务。

services:
  proxy:
    image: nginx:alpine
    # 代理只接入前端网络
    networks:
      - frontend

  app:
    image: example/app:latest
    environment:
      # 数据库地址使用服务名和容器端口
      DATABASE_URL: postgres://app:secret@db:5432/app
    # 应用同时接入前端与后端网络
    networks:
      - frontend
      - backend

  db:
    image: postgres:18
    environment:
      POSTGRES_PASSWORD: secret
    # 数据库只暴露在内部后端网络
    networks:
      - backend

networks:
  frontend:
    driver: bridge
  backend:
    # 内部网络不提供默认外部连通性
    internal: true

Compose 前端和内部后端网络信任边界图

图2:前端网络与内部后端网络组成的最小信任边界。

internal: true 的作用是让该网络不具备默认外部连通性。需要注意,若某个服务同时加入另一个可出站网络,它仍然可能通过另一个网络访问外部。因此隔离效果取决于服务加入的全部网络,不能只看单个网络定义。

共识四:容器重建后应重新解析并重连

Compose 更新服务时,旧容器会被移除,新容器以同一个服务名加入网络,但 IP 可能变化。指向旧容器的已打开连接会关闭;正确恢复方式是让客户端重新解析服务名并建立新连接。

这意味着连接池应具备失败淘汰、有限退避和重建连接能力。若应用把首次解析到的 IP 永久缓存,即使 Compose 网络本身正常,也会在重建后持续失败。

容器重建后的重新解析与重连关系图

图3:容器重建后的名称重解析与连接恢复关系。

跨项目发现:external 网络要克制使用

两个独立 Compose 项目默认处于不同网络。如果业务确实需要跨项目发现,可以让双方加入同一个预先创建的外部网络。Compose 不会替你创建声明为 external 的网络;网络不存在时会直接报错。

外部网络扩大了可见范围,也弱化了项目边界。团队应为它设定固定名称、创建责任、接入审批和清理策略。能通过 API、消息队列或网关解耦时,不要把共享外部网络当成默认方案。

反向验证:主动重建一次服务

修复后不要只验证“现在能连”。还应重建目标服务,确认客户端能从断连状态恢复。测试重点有三个:服务名是否仍可解析、新 IP 是否被采用、业务连接是否能在合理时间内恢复。

# 记录当前 db 服务名解析结果
docker compose exec app getent hosts db

# 强制重建 db,模拟更新后的容器替换
docker compose up -d --force-recreate db

# 再次解析服务名,确认客户端不依赖旧 IP
docker compose exec app getent hosts db

# 验证应用到数据库容器端口的连接已经恢复
docker compose exec app sh -c 'nc -vz db 5432'

发布前检查清单

  • 服务间地址是否全部使用 Compose 服务名,而不是固定容器 IP?
  • 容器内请求是否使用目标容器端口,而不是主机端口?
  • 每一对需要互通的服务是否至少共享一个网络?
  • 每一个不应直连的服务对是否通过网络成员关系隔离?
  • 内部网络上的服务是否还加入了其他可出站网络?
  • 外部网络是否已创建,并有明确的生命周期负责人?
  • 连接池是否会淘汰失效连接、重新解析服务名并重连?
  • 是否执行过一次目标服务重建后的恢复验证?

小结

Docker Compose 当前网络文档传递的核心并不是增加配置,而是减少隐式假设:把服务名作为稳定身份,把容器端口作为内部通信边界,把自定义网络作为信任边界,再把重建后的重新解析与重连当成正常运行条件。

排障时坚持“网络成员、名称解析、端口选择、实时连通、重建恢复”这条证据链,多数 Compose 服务发现问题都能在几分钟内缩小范围。

声明:本文转载于:17golang原创 如有侵犯,请联系study_golang@163.com删除
相关阅读
更多>
最新阅读
更多>
课程推荐
更多>