K8s 学习笔记(十):调用链路深挖

写在前面

承接篇9 组件。本篇把那些组件串起来,演示两条最核心的调用链路:

  • 管理面:一次 kubectl apply 怎么把一个 Deployment 跑起来(组件协作部署)
  • 数据面:一次外部 HTTP 请求怎么从公网打到 Pod(流量怎么进来)

读完这两条,“apiserver / etcd / controller / scheduler / kubelet / kube-proxy / CNI / CoreDNS / Ingress 这些到底怎么配合"就彻底通了——排查问题也知道该看哪个环节。


一、两条链路总览

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
管理面(控制流)—— 部署一个 Pod
  你 → kubectl → apiserver → etcd → controller-manager → scheduler
     → kubelet → runtime → Pod Ready

  这是"声明 → 调谐 → 执行"链路,组件靠 watch apiserver 协作

数据面(数据流)—— 一次外部请求
  用户 → 公网 DNS → 外部入口(Gateway/Ingress/LoadBalancer 的具体实现)
     → Service 虚拟 IP 或后端地址 → 集群网络数据面 → Pod → container

  这是"流量 → 路由 → 转发 → 到达"链路,靠网络组件 + 内核规则

两条链路分开看,但共享组件(apiserver 是管理面枢纽,kube-proxy / CNI 是数据面枢纽)。


二、管理面:kubectl apply 全流程

场景:kubectl apply -f deploy.yaml(一个 replicas: 3 的 Deployment)。

步骤拆解

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
① kubectl apply
   kubectl 读 YAML;首次创建通常发 POST,apply 更新通常发 PATCH
   附上 kubeconfig 里的证书/Token(认证)

② apiserver 收请求
   认证(你是谁)→ 授权(你能执行该操作吗)→ mutating admission
   → 对象校验 → validating admission → 持久化
   返回成功给 kubectl

③ etcd 存储
   Deployment 对象持久化(期望状态:replicas=3,image=nginx)
   此时还没有任何 Pod —— 只是"账本上记了要 3 个"

④ Deployment Controller(在 controller-manager 里)watch 到
   它 watch apiserver 的 Deployment 资源
   看到新 Deployment → 创建一个 ReplicaSet(版本 v1)

⑤ ReplicaSet Controller watch 到
   看到新 RS 期望 3 副本,但当前 0 → 创建 3 个 Pod 对象(Pod 还没绑定节点)

⑥ kube-scheduler watch 到未调度的 Pod
   对每个 Pod:过滤可用节点 → 打分 → 选定 → 通过 Binding 完成节点绑定
   Pod 现在"知道"自己该跑在哪个节点

⑦ 目标节点的 kubelet watch 到分给自己的 Pod
   kubelet 一直 watch apiserver:"有没有分给我的新 Pod?"
   收到 → 调 CRI(containerd)拉镜像、起容器
   挂载 volume、启动容器,并按配置执行 startup/liveness/readiness probe

⑧ kubelet 上报状态
   Pod Running、容器就绪 → 写回 apiserver → etcd 更新实际状态
   ReplicaSet Controller 看到实际=期望,停止创建

⑨ Service 数据面更新(如果有 Service)
   EndpointSlice Controller 根据 Pod 和 Service selector 更新 EndpointSlice
   kube-proxy 或替代它的数据面实现据此更新转发规则
   现在 Service 的 ClusterIP 才能选择到就绪后端

⑩ 用户检查 Pod 的 Running、Ready 条件和 Deployment 可用副本
   —— 链路闭合

关键认知:watch + reconcile

1
2
3
4
5
6
组件间不互相直连:
  kubectl 不通知 controller,controller 不通知 scheduler
  主要靠 API Server 上的 watch、list 和写操作协作;etcd 不直接暴露给这些客户端组件

  控制器观察状态后主动写入下一步对象并持续 reconcile
  这构成了 K8s 的事件驱动与声明式控制循环

排查 Pod 没起来:① kubectl get 卡在 Pending → scheduler 问题(资源 / 亲和);② ImagePullBackOff → kubelet 拉镜像失败;③ CrashLoopBackOff → kubelet 起了但容器崩(应用问题)。每个阶段对应不同组件,kubectl describe pod 的 Events 串起链路。


三、数据面:外部请求进 K8s 全流程

场景:用户访问 http://app.example.com,集群里有个 Ingress 把它路由到 web Service(后面 3 个 Pod)。

步骤拆解

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
17
18
19
20
21
22
① 用户浏览器:http://app.example.com
② 公网 DNS 解析 app.example.com → 一个公网 IP
   这个 IP 是云 LoadBalancer / Ingress Controller 的对外入口

③ 流量到外部入口
   它可能是云 LoadBalancer、Gateway 或 Ingress Controller 的前置负载均衡器
   后续可能走节点端口,也可能由实现直接路由到节点或 Pod,不能假定只有 NodePort 一条路径

④ 所选 Gateway/Ingress 实现收到请求
   读 Host: app.example.com,查 Ingress 规则
   匹配到 → 找到目标 Service(web)

⑤ 控制器按实现解析 Service 与 EndpointSlice
   EndpointSlice 记录 web Service 的后端地址及就绪状态
   实现可以选择后端地址,也可以把流量交给 Service 虚拟 IP

⑥ 集群数据面把流量送往后端
   某些控制器直接连接 EndpointSlice 中的 Pod IP,另一些会访问 Service ClusterIP
   跨节点路径由所选网络实现完成,可能使用原生路由、overlay、eBPF 等机制

⑦ 流量到目标节点的 Pod 网络命名空间 → container 端口
   container 处理请求,返回响应(原路或直接出网)

关键认知:入口路径由实现决定

1
2
3
4
不能把某个 Ingress Controller 的实现写成 Kubernetes 规范:
  - ClusterIP 通常是虚拟 IP,由 kube-proxy 或替代数据面实现
  - 控制器可能 watch EndpointSlice 后直连 Pod,也可能使用 Service ClusterIP
  - 是否绕过 Service、怎样负载均衡、怎样处理连接排空,都要查具体控制器文档

四、对比:集群内 Pod 访问 Service

下面展示传统 kube-proxy 数据面的常见路径;使用替代数据面时,具体内核规则和转发位置会不同:

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
集群内 Pod → http://web-app(Service 名)
① CoreDNS 把 web-app 解析成 Service 的 ClusterIP(如 10.96.0.10)
② Pod 发包到 10.96.0.10:80
③ 包到达本节点内核 → 命中 kube-proxy 写的 iptables/nftables 等规则
④ 规则把目的地址 DNAT:10.96.0.10 → 某个真实 Pod IP(如 10.244.1.5)
⑤ CNI 把包路由到 Pod(本节点直连;跨节点靠 overlay/BGP)
⑥ Pod 收到

  关键:ClusterIP 是"虚拟入口",真正干活的还是 Pod IP
        kube-proxy 的规则就是"虚拟入口 → 真实 Pod"的映射
1
2
3
两种访问路径对比:
  外部 → 入口实现 → Service ClusterIP 或 Pod IP(取决于实现)
  内部 → Service 名 → CoreDNS → ClusterIP → Service 数据面 → Pod IP

五、组件在两条链路里的角色

1
2
3
4
5
6
7
8
9
管理面(apply)的主力:
  apiserver(枢纽)/ etcd(账本)/ controller-manager(reconcile)
  / scheduler(调度)/ kubelet(执行)

数据面(请求)的主力:
  CoreDNS(名字解析)/ Ingress Controller(七层路由)
  / EndpointSlice(后端列表)/ Service 数据面 / Pod 网络实现

  共享:apiserver 是管理面 API 枢纽;具体网络实现负责数据面

六、按故障现象定位环节

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
现象                         卡在哪              查
─────────────────────────────────────────────────────────────
kubectl apply 后 Pod 不出现   controller/调度     kubectl get events
Pod Pending                  scheduler          kubectl describe pod(FailedScheduling)
ImagePullBackOff             kubelet/runtime    镜像名/仓库权限
CrashLoopBackOff             应用               kubectl logs
Service 名解析失败           CoreDNS            kubectl get pods -n kube-system(coredns)
Service ClusterIP 不通       Service/Pod 网络   EndpointSlice、数据面规则与跨节点连通性
Ingress 503/502              Ingress Controller kubectl describe ingress + controller 日志
外部访问超时                 LB/Ingress 入口    LB 健康检查、NodePort、安全组

七、小结

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
14
15
16
管理面(kubectl apply):
  apply → apiserver → etcd → controller 创建 RS/Pod
       → scheduler 选节点 → kubelet 起容器 → kube-proxy 更新规则
  组件靠 watch apiserver 协作,不直连

数据面(外部请求):
  公网 → DNS → 外部入口实现(Gateway/Ingress/LoadBalancer)
       → Service ClusterIP 或后端 Pod → 集群网络数据面
  具体是否直连 Pod、使用何种规则,取决于控制器和网络实现

核心认知:
  ✓ apiserver/etcd 是管理面总线,组件 watch 它协作
  ✓ Service ClusterIP 通常是虚拟入口,由 kube-proxy 或替代数据面实现
  ✓ 入口控制器可能直连 Pod,也可能经过 ClusterIP,必须查看实现文档
  ✓ Pod 网络实现负责地址配置与跨节点连通,具体技术路径并不唯一
  ✓ 故障按"管理面 vs 数据面"先分流,再定位具体组件

至此 K8s 学习笔记 10 篇走完:资源怎么用(1-8)+ 组件是什么(9)+ 组件怎么协作(10)。配上本站「云托管 K8s 实战」5 篇(云上落地),K8s 从原理到生产就齐了。

参考资料

Licensed under CC BY-NC-SA 4.0
最后更新于 Thursday, August 20, 2026