Moby 源码实战:用 Swarm Service Driller(ssd)排查 Docker Swarm 网络的控制面与内核数据面不一致
2026/9/6 22:53:07 网站建设 项目流程

Moby 源码实战:用 Swarm Service Driller(ssd)排查 Docker Swarm 网络的控制面与内核数据面不一致

【免费下载链接】mobyThe Moby Project - a collaborative project for the container ecosystem to assemble container-based systems项目地址: https://gitcode.com/GitHub_Trending/mo/moby

ssd(Swarm Service Driller)是 Moby 仓库内置的 Swarm 网络故障排查工具,用于核对 Docker 守护进程内存中的网络控制面状态与内核中实际编程的数据面(IPVS 负载均衡、iptables 转发规则)是否一致,以及各节点通过 gossip 协议同步出的控制面状态是否收敛。本文基于 README 与 ssd.py 源码,完整讲解两类检查的原理、操作命令和输出判读方法,帮助你在出现"网络 inspect 正常但流量不通"这类疑难问题时快速定位责任层。

ssd 的定位:控制面与数据面之间的"一致性探针"

在 Docker Swarm 网络中,服务发现与负载均衡由两部分协作完成:

  • 控制面:由 Docker 守护进程(daemon/libnetwork 下的集群 agent)维护,记录每个服务的 VIP、本地负载均衡索引(LocalLBIndex)与后端任务列表;
  • 数据面:由内核实际编程,overlay 网络在每个容器沙箱内用 IPVS(以 fwmark 标识服务)做本地负载均衡,ingress 网络则用 iptables 的 DNAT 规则把发布端口转发到 ingress 沙箱。

ssd 的核心职责就是把这两份"账本"逐条比对,确认没有漂移。它当前只覆盖负载均衡(IPVS 实现)的一致性检查,这一点在 README 中明确说明。

运行方式与依赖

ssd 以容器形式运行,通过挂载 Docker socket 和 netns 目录获得对 daemon API 与内核网络命名空间的访问权。README 给出的标准命令为:

docker run -v /var/run/docker.sock:/var/run/docker.sock \ -v /var/run/docker/netns:/var/run/docker/netns \ --privileged --net=host sanimej/ssd ov2

从源码看,两个挂载点各有用途:

  • /var/run/docker.sock:ssd 通过 docker-py 客户端(docker.APIClient(base_url='unix://var/run/docker.sock'),见 ssd.py L141)拉取network inspect --verbose的控制面数据;
  • /var/run/docker/netns:ssd 用nsenter --net=<namespace>进入每个容器的网络沙箱执行ipvsadm -ln读取内核中真实的 IPVS 表(ssd.py L94),因此必须--privileged

命令的第一个参数是网络名;第二个可选参数为子命令gossip-consistency,默认值为default(即一致性检查,ssd.py L136-L145)。如果第一个参数是ingress,则只检查 ingress 网络。

仓库提供了现成的 Dockerfile,基于 Alpine,预装了检查所需的工具链:python2iproute2ipvsadmbashnsenter(util-linux)以及网络诊断工具straceiperfethtool等,并将 ssd.py 设为入口python /ssd.py。你可以用它自行构建镜像,替代 README 中引用的外部sanimej/ssd镜像,例如:

docker build -t local/ssd daemon/libnetwork/cmd/ssd

检查一:节点内的控制面 / 数据面一致性(IPVS 编程核对)

default模式下,ssd 对指定网络执行check_network,流程如下(见 check_network):

  1. 拉取控制面真值:调用network inspect --verbose,从返回的Services字段提取每个服务的LocalLBIndex(即 IPVS 中使用的 fwmark)和任务列表的EndpointIP,构建"fwmark → 后端 IP 集合"的期望映射;
  2. 读取内核真值:对网络上每个容器(沙箱键来自NetworkSettings.SandboxKey),nsenter进其网络命名空间执行ipvsadm -ln,解析输出中以FWM开头行的标记值和->开头的后端条目;
  3. 双向比对
    • IPVS 中有、daemon 中没有的 LB Index → 报LB Index X present in IPVS but missing in docker daemon(内核残留);
    • daemon 中有、IPVS 中没有的 → 报present in docker daemon but missing in IPVS(编程丢失);
    • 两边都有但后端集合不一致 → 报Incorrect LB Programming for service ...,并分别打印控制面与内核 IPVS 的后端列表,方便肉眼定位多出来的或少掉的实例。

在 agent.go 中可以看到ServiceInfo结构的定义:VIPLocalLBIndexTasksPorts——这正是 ssd 比对所依赖的network inspect --verbose输出的数据来源。

README 中一个三节点集群(网络ov2,3 个服务各 3 副本)的正常输出如下,每个沙箱下逐一核对所有服务后输出OK,随后自动追加对ingress网络的检查:

$ docker run -v /var/run/docker.sock:/var/run/docker.sock \ -v /var/run/docker/netns:/var/run/docker/netns \ --privileged --net=host sanimej/ssd ov2 Verifying LB programming for containers on network ov2 Verifying container /s2.3.ltrdwef0iqf90rqauw3ehcs56... service s2... OK service s3... OK service s1... OK Verifying container /s3.3.nyhwvdvnocb4wftyhb8dr4fj8... service s2... OK service s3... OK service s1... OK Verifying container /s1.3.wwx5tuxhnvoz5vrb8ohphby0r... service s2... OK service s3... OK service s1... OK Verifying LB programming for containers on network ingress Verifying container Ingress... service web... OK

ingress 网络:iptables 发布端口 DNAT 规则核对

ingress网络(或 default 模式自动追加的 ingress 检查),ssd 额外调用check_iptables(ssd.py L25-L45):

  • nsenter进入ingress_sbox网络命名空间,读取eth1的 IP(ingress 沙箱在docker_gwbridge网络上的地址,发布端口最终会被 DNAT 到该 IP);
  • 对服务Ports中的每个Target: x, Publish: y条目,用iptables -t nat -C DOCKER-INGRESS -p tcp --dport <publish> -j DNAT --to <ingressIP>:<publish>探测 nat 表DOCKER-INGRESS链中是否存在对应规则;
  • 缺失时输出:Service <name>: host iptables DNAT rule for port <x> -> ingress sandbox <ip>:<x> missing

这与数据面实现相互印证:libnetwork 的 bridge 驱动内部在主机命名空间的 nat 表 PREROUTING 中挂接DOCKER-INGRESS链(见 iptabler/network.go L408),服务流量经 DNAT 进入 ingress 沙箱后再由 IPVS 分发到后端。

检查二:跨节点控制面一致性(gossip-consistency)

Swarm 网络状态通过 gossip 协议在集群内同步。gossip-consistency子命令验证所有节点对该网络的控制面状态是否一致(README):

docker run -v /var/run/docker.sock:/var/run/docker.sock \ -v /var/run/docker/netns:/var/run/docker/netns \ --privileged sanimej/ssd ov2 gossip-consistency

三节点集群、ov2网络上的正常输出——三行 hash 完全相同即表示已收敛:

Node id: sjfp0ca8f43rvnab6v7f21gq0 gossip hash c57d89094dbb574a37930393278dc282 Node id: bg228r3q9095grj4wxkqs80oe gossip hash c57d89094dbb574a37930393278dc282 Node id: 6jylcraipcv2pxdricqe77j5q gossip hash c57d89094dbb574a37930393278dc282

源码级实现:全局服务 + 每节点 hash

该子命令的机制比表面更巧妙(ssd.py L147-L165):

  1. ssd 在本地节点通过 daemon API创建一个名为gossip-hash的 global 服务,其任务镜像为docker/ssd,参数为<网络名> gossip-hash,并把/var/run/docker.sock挂载进每个任务;
  2. global 服务保证集群中每个节点各运行一个任务,每个任务执行gossip-hash分支:inspect_network --verbose后,把该节点视角下所有服务的 VIP 及任务明细字段排序,逐条喂给 MD5,打印节点 ID 与摘要,然后signal.pause()挂起等待被收集;
  3. 创建服务后短暂等待,用service logs gossip-hash收集全部任务的输出(即每节点一行 hash),最后调用remove_service清理。

因此输出的每行Node id: <node-id> gossip hash <md5>对应集群中的一个节点。hash 相同说明各节点经 gossip 同步出的网络控制面状态一致;如果出现不一致,按 README 的建议,在各节点上执行docker network inspect --verbose逐个对比输出,即可定位具体差异字段(通常是某个服务的任务列表或端点 IP 未同步到位)。值得注意的是:hash 是对"排序后的状态字段"计算的,与任务的枚举顺序无关,可以消除字段顺序造成的假阳性。

故障排查建议路径

结合两类检查,可以形成一条从现象到结论的定位路径:

  1. 服务 VIP 可达性异常、个别后端失联→ 先跑 default 模式的一致性检查。若报missing in IPVS/Incorrect LB Programming,问题在本机内核数据面编程,可进一步用ipvsadm -ln(经 nsenter 到对应沙箱)与docker network inspect --verbose手工复核;
  2. ingress 发布端口不通、容器内直连正常→ 关注 iptables DNAT 规则缺失输出,检查iptables -t nat -L DOCKER-INGRESS -n中发布端口规则;
  3. 部分节点行为与主节点不一致(如新加入节点上服务不可见)→ 跑gossip-consistency。若 hash 不一致,逐节点docker network inspect --verbosediff 出未收敛的节点与字段。

适用前提与注意事项

  • 工具依赖 Linux 内核特性(IPVS、iptables、netns + nsenter),在 Linux 节点上运行才有效;
  • ssd.py 使用 Python 2 语法(print语句),Dockerfile 中显式安装python2并建立python软链,自行移植到 Python 3 环境需做语法迁移;
  • 一致性检查当前仅覆盖 IPVS 负载均衡这一项数据面内容(README 明示 "currently the tool checks only for the consistency of the Load balancer"),其他数据面要素(如路由、VXLAN 配置)不在核对范围内;
  • gossip-consistency会在集群中短暂创建并删除一个 global 服务,请确认当前节点具有 swarm 管理权限,且集群允许创建临时服务。

延伸阅读(仓库内相关路径)

  • README:ssd 工具官方说明与示例输出;
  • ssd.py:检查逻辑全部实现,约 194 行,可读性高,适合作为理解 Swarm 网络数据面编程的"活文档";
  • agent.go:ServiceInfo(VIP / LocalLBIndex / Tasks / Ports)结构定义,即 ssd 比对的控制面数据来源;
  • service_linux.go:daemon 侧通过moby/ipvs库在沙箱内创建/删除 IPVS 服务与后端的实现,与 ssd 读取的内核状态一一对应;
  • networkdb:gossip 同步的集群数据库层,gossip-consistency校验的对象即其收敛结果。

【免费下载链接】mobyThe Moby Project - a collaborative project for the container ecosystem to assemble container-based systems项目地址: https://gitcode.com/GitHub_Trending/mo/moby

创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询