4. 镜像拉取流程剖析:kubelet → containerd → registry 的完整链路、网络路径与 DNS 解析关键点

镜像拉取是集群生命周期中最频繁的操作之一,也是多集群场景下故障的高发区。当 Cilium 网络策略生效时,kubelet 到 containerd 再到远端 registry 的每一跳都可能因策略、路由或 DNS 解析异常而中断。本节从进程级调用链、网络数据流和 DNS 解析三个维度拆解完整链路。

4.1 进程级调用链:kubelet → containerd → registry

kubelet 并不直接与 registry 通信,而是通过 CRI(Container Runtime Interface)调用容器运行时。在大多数生产集群中,运行时为 containerd,其内部又通过 cri-plugin 和 image service 完成镜像层下载。完整调用链如下:

步骤 组件 动作 关键接口/协议
1 kubelet 根据 PodSpec 中的 image 字段,调用 CRI PullImage() gRPC over Unix Socket
/run/containerd/containerd.sock
2 containerd
cri-plugin
解析镜像名称(含 registry 地址),检查本地缓存 本地元数据存储
(boltDB / 文件系统)
3 containerd
image service
若缓存未命中,发起 HTTPS 请求到远端 registry HTTP/1.1 或 HTTP/2
默认端口 443
4 containerd
snapshotter
下载 manifest 和各层 blob,解压到本地快照目录 overlayfs / devicemapper
5 containerd
cri-plugin
返回 PullImageResponse 给 kubelet gRPC over Unix Socket
排障要点: 步骤 1 和 5 走本地 Unix Socket,不受网络策略影响;步骤 3 是唯一跨主机网络跳,也是 Cilium 网络策略、DNS 解析和路由配置的生效点。

4.2 网络路径:从 containerd 到 registry 的完整数据流

当 containerd 发起 HTTPS 请求到 registry 时,数据包在节点内和集群网络中经过以下路径:

  1. containerd 进程 → 本地 lo 或 eth0:containerd 作为用户态进程,通过系统调用 connect() 发送 TCP SYN。
  2. 节点内核路由决策:根据目标 IP(registry 解析结果)查路由表,决定下一跳是直连网段还是网关。
  3. Cilium eBPF 钩子:在 tc ingress/egress 或 XDP 层,Cilium 执行网络策略匹配和负载均衡(如果 registry 通过 ClusterIP Service 暴露)。
  4. 物理网络 / 隧道封装:跨节点流量可能经过 VXLAN、Geneve 或直接路由。
  5. 公网 / 专线到达 registry:最终到达镜像仓库的负载均衡器或 CDN 边缘。
多集群场景: 如果 registry 部署在另一个集群(如通过 Submariner 或 Cilium ClusterMesh 暴露 Service),数据流会额外经过集群间网关和隧道,此时 Cilium 的 toFQDN 策略和 Egress Gateway 成为关键排障点。
镜像拉取网络路径与 Cilium 策略生效点 镜像拉取网络路径与 Cilium 策略生效点 kubelet containerd Cilium eBPF 节点路由 Registry 网络策略 & LB 生效点 DNS 解析在此发生 注:kubelet → containerd 走本地 Unix Socket,不经过网络栈

4.3 DNS 解析关键点

containerd 在发起 HTTPS 请求前,必须先解析镜像仓库的域名。DNS 解析的成败直接影响拉取速度与成功率。在多集群和 Cilium 环境下,以下三个环节最容易出问题:

环节 默认行为 Cilium 影响 排障命令
1. 节点级 DNS 配置 /etc/resolv.conf 指向集群 DNS(如 CoreDNS) Cilium 可劫持 DNS 流量做 toFQDN 策略匹配 cat /etc/resolv.conf
nslookup registry.example.com
2. CoreDNS 解析 先查集群内 Service,再转发上游 Cilium 可能阻断非白名单的外部 DNS 请求 kubectl logs -n kube-system -l k8s-app=kube-dns
3. containerd 内置 DNS 缓存 containerd 1.6+ 默认启用 resolv.conf 热加载 缓存过期时间与 Cilium DNS 策略 TTL 可能不一致 ctr images pull --debug ...
常见故障模式: Cilium 的 toFQDN 策略要求显式放行 registry 域名。如果策略中只写了 docker.io 但镜像实际拉取自 registry-1.docker.io,DNS 解析成功但 TCP 连接会被 eBPF 策略拒绝,表现为 ImagePullBackOff 且 containerd 日志中出现 connection refused。

4.4 完整链路故障排查清单

当镜像拉取失败时,按以下顺序逐层排查:

  1. 检查 kubelet 日志:journalctl -u kubelet | grep PullImage,确认是否发出 CRI 调用。
  2. 检查 containerd 日志:crictl pull <image> --debug,观察是否进入网络请求阶段。
  3. 验证 DNS 解析:在节点上 dig registry.example.com,确认返回 IP 且不被 Cilium 策略丢弃。
  4. 验证网络连通性:curl -v https://registry.example.com/v2/,确认 TLS 握手成功。
  5. 检查 Cilium 策略:cilium endpoint list 查看 containerd 所在 Pod 的策略命中计数,确认 toFQDN 规则匹配。
  6. 检查 Cilium DNS 代理:cilium bpf fqdn list 查看缓存的 DNS 记录是否过期或缺失。
DNS 解析与 Cilium toFQDN 策略交互流程 DNS 解析与 Cilium toFQDN 策略交互流程 containerd Cilium DNS Proxy CoreDNS 上游 DNS Registry IP toFQDN 策略匹配 DNS 缓存 (eBPF map) Cilium DNS Proxy 拦截 DNS 请求,缓存解析结果并关联 toFQDN 策略 后续 containerd 访问 Registry IP 时,eBPF 程序查缓存判断是否放行

4.5 关键排障命令速查

目标 命令 预期输出
查看 containerd 拉取日志 crictl pull --debug nginx:latest 2>&1 | grep -i error 无 error 或明确的 HTTP 错误码
验证 DNS 解析 dig +short registry.example.com @$(kubectl get svc -n kube-system kube-dns -o jsonpath='{.spec.clusterIP}') 返回 A 记录 IP
检查 Cilium DNS 缓存 cilium bpf fqdn list 显示域名与 IP 映射,TTL 未过期
检查 Cilium 策略命中 cilium endpoint list → 找到 containerd 所在 Pod 的 endpoint ID → cilium endpoint get <id> | jq '.policy' "ingress": {"enforcing": true} 且无拒绝计数
抓包验证 TCP 连接 tcpdump -i any -nn host <registry-ip> and port 443 看到 SYN → SYN-ACK → ACK 三次握手
最佳实践: 在多集群环境中,建议将常用镜像仓库域名加入 Cilium 的 toFQDN 策略白名单,并设置合理的 TTL(建议 300s 以上),避免 DNS 缓存频繁过期导致策略重新评估延迟。同时开启 Cilium 的 DNS 代理日志:cilium config set dns-proxy-log-level debug。