Docker Swarm 网络互通 — 一个从故障到解决的简明实战教程(初学者友好)

下面把你这次的排查与解决流程精简、结构化地整理成一篇小 blog。目标是让初学者能一步步看懂:为什么容器间不能用服务名通信、如何修复、以及浏览器访问与服务名的区别。文中穿插命令、表格和 > 注解,便于复制执行和复用。


一、问题概述(一句话)

容器间无法通过 服务名 互相访问(报 no such host),并且有 0.0.0.0:50052 作为拨号目标导致连接失败;此外浏览器重定向尝试访问 http://mediahub:5174/ 也失败。

实际症状归为两类:

  1. Swarm 内服务 DNS 不生效 → lookup xxx on 127.0.0.11:53: no such host
  2. 浏览器访问外部主机时使用了 Swarm 内部服务名 → 浏览器无法解析 mediahub

二、核心概念速览(非常重要,读懂就好)

  • Overlay 网络(Swarm):Swarm 的容器互通依赖 overlay 网络与内建 DNS。只有加入同一 overlay 网络的服务,才能互相通过 service-name 解析到对方。

  • 服务名解析范围service-name 仅在 Swarm overlay 网络内部可解析,浏览器/宿主机不认识该域名

  • 监听地址 vs 拨号目标

    • 0.0.0.0 用于监听(表示“所有网卡”),不能作为客户端拨号目标
    • 客户端拨号应使用 service-name:port(跨容器)或 127.0.0.1:port(同容器/同主机)。
  • Config 挂载(docker config):如果配置是通过 docker config 挂载的,可以不重建镜像,按 service update --config-rmdocker config rmdocker config createservice update --config-add 的顺序更新。

小提示:Alpine 镜像没有 bash,用 sh 进入容器;在容器内用 netstat / ss 检查监听地址。


三、你做了什么(关键命令与结果)

  1. 创建 overlay 网络并加入服务:
docker network create --driver overlay app-net

# 把服务加到同一网络(示例)
docker service update --network-add app-net user
docker service update --network-add app-net user-crontab
docker service update --network-add app-net mediahub
docker service update --network-add app-net shorturl
docker service update --network-add app-net shorturl-proxy
  1. 验证服务是否加入网络:
docker service inspect user --format '{{json .Spec.TaskTemplate.Networks}}'
# 期望结果包含 app-net 的 network id
  1. 在容器内看监听地址(示例):
docker exec -it <container_id> sh
# 容器内执行
netstat -tlnp
# 例如看到:127.0.0.1:8080 -> 说明只能容器内部 loopback 访问
  1. 测试服务名解析(在容器内):
docker exec -it <user_container_id> ping -c2 user-crontab

四、为什么你一开始会遇到那些错误(归纳)

报错/现象 根本原因 说明
no such host(lookup user-crontab …) 服务未加入同一个 overlay 网络 / 没有 Swarm DNS 路径 Swarm DNS 只在 overlay 网络生效
dial tcp 0.0.0.0:50052: connect: connection refused 客户端拨号使用 0.0.0.0(错误) 0.0.0.0 只能监听,不能作为目标拨号地址
浏览器访问 http://mediahub:5174 失败 mediahub 是 Swarm 内部名,外部 DNS/主机无法解析 浏览器需访问宿主 IP 或域名(例如 http://192.168.132.134:8080

注:在本地开发(server 和 client 在同一台机器)0.0.0.0 / localhost 有时“蒙对”导致看似正常,但分布式环境下会暴露问题。


五、操作步骤(按顺序复制执行) — 把你的集群弄通用这 7 步

下面写出的命令基于你现有的服务名(mediahub、user、user-crontab、shorturl、shorturl-crontab、shorturl-proxy)。你已经执行了部分操作(创建 app-net 并加入服务),这里列出完整核查与补充步骤。

  1. 创建 overlay 网络(如果还没创建):
docker network create --driver overlay app-net
  1. 把所有相关 service 加入同一个网络:
docker service update --network-add app-net user
docker service update --network-add app-net user-crontab
docker service update --network-add app-net mediahub
docker service update --network-add app-net shorturl
docker service update --network-add app-net shorturl-crontab
docker service update --network-add app-net shorturl-proxy
  1. 验证服务已在网络上(任意服务举例):
docker service inspect user --format '{{json .Spec.TaskTemplate.Networks}}'
  1. 在容器内测试 DNS 分辨(在 user 容器里 ping user-crontab):
# 找到 user 的运行容器 id(示例)
CID=$(docker ps --filter "name=user.1" -q)
docker exec -it $CID ping -c2 user-crontab
  1. 检查服务监听地址(防止只监听 localhost):
docker exec -it $CID sh
# 容器内
netstat -tlnp
# 或
ss -tln

期望:应用监听在 0.0.0.0:PORT:PORT(这两者等效,均可被外部访问)。

  1. 修复 gRPC / 内部拨号代码(示例,Go):
// server 应该 listen ":50052"
lis, _ := net.Listen("tcp", ":50052")

// client 在 Swarm 内跨服务拨号
conn, err := grpc.Dial("user-crontab:50052", grpc.WithInsecure())

注:如果 client 与 server 在同容器中,拨 127.0.0.1:50052;如果跨容器则拨 service-name:port

  1. 浏览器回调/重定向配置(internalSystemEntry
  • 开发(本地前端):http://localhost:5174
  • 集群/局域网部署:填写宿主机 IP 或域名,例如:
internalSystemEntry:
  mediahub: "http://192.168.132.134:5174"

浏览器必须能解析该地址 —— mediahub:5174 只对容器内部有效,不可直接作为浏览器 URL。


六、配置管理:docker config 的快速更新命令

如果你是通过 docker config 挂载配置文件,更新流程如下(以 user 为例):

# 1. 解除服务对旧 config 的使用
docker service update --config-rm user-conf user

# 2. 删除旧 config(只在上一步成功后允许删除)
docker config rm user-conf

# 3. 创建新 config(本地 dev.config.yaml 的路径视情况而定)
docker config create user-conf user/dev.config.yaml

# 4. 把新 config 挂回服务
docker service update --config-add source=user-conf,target=/app/config.yaml user

注:docker config rm 会在 config 正被 service 使用时失败,因此必须先 --config-rm


七、常见问题与快速排查(Checklist)

  • 服务名解析失败 → 检查两个服务是否在同一 overlay 网络:docker service inspect <svc> --format '{{json .Spec.TaskTemplate.Networks}}'
  • 容器间能 DNS 解析但连接被拒绝 → 检查目标容器是否在 相应端口 上监听 0.0.0.0netstat -tlnp
  • 使用 0.0.0.0 作为拨号目标 → 改为 service-name:port127.0.0.1:port
  • 浏览器访问 http://service-name:port 失败 → 这是正常,因为该 name 仅作用于 Swarm 网内 DNS;改为宿主机 IP/域名。
  • docker config rm 报错 → 先 docker service update --config-rm 解绑定。

八、简短示例

  • 内部服务调用(推荐)

    • useruser-crontabgrpc.Dial("user-crontab:50052")
    • 两个服务在 app-net overlay 网络上。
  • 浏览器重定向(外部访问)

    • 回调重定向到:http://192.168.132.134:8080/(或域名),不要mediahub:5174

添加链接描述

Logo

魔乐社区(Modelers.cn) 是一个中立、公益的人工智能社区,提供人工智能工具、模型、数据的托管、展示与应用协同服务,为人工智能开发及爱好者搭建开放的学习交流平台。社区通过理事会方式运作,由全产业链共同建设、共同运营、共同享有,推动国产AI生态繁荣发展。

更多推荐