LabHub
学习 学习路径 课程

CKA — Kubernetes 管理员

Service 不是代理,是一个承诺

在 LabHub 中继续学习

一句话总结

Service 对象不传送流量。它只是声明通过 selector 建立 backend 列表(EndpointSlice),实际转发 packet 的是节点 data plane(kube-proxy 的 iptables/nftables 或 CNI 的 eBPF)。理解这种分离,就能把“Service 存在却无法连接”拆成三层检查。

概念图: 声明通过 selector 建立 backend 列表(EndpointSlice) · 谁维护 backend 列表 · 正常创建,但内容为空 · “endpoint 中有 IP 吗?”

为什么需要它

Pod 死亡重建时 IP 会改变,因此需要名称和稳定的虚拟 IP。Service 提供了这两项。

问题在于谁维护 backend 列表。Service 写入 selector 后,endpoint 控制器会寻找标签匹配且 Ready 的 Pod,填充 EndpointSlice。selector 哪怕差一个字符,EndpointSlice 也会正常创建,但内容为空,不会报错。Service、Deployment 和 Pod 全都 Ready,只有连接失败。

所以诊断 Service 故障的第一个问题永远相同:**“endpoint 中有 IP 吗?”**有,就是 data plane 问题;没有,就是 selector 或 Pod Ready 问题。

它如何运作

类型 工作 使用场景
ClusterIP 一个集群内部虚拟 IP 默认值
NodePort 打开所有节点的 30000~32767 端口 临时从外部访问
LoadBalancer NodePort + 外部 LB provisioning 云/MetalLB
ExternalName 不使用 IP,只返回 CNAME 指向集群外系统
headless (clusterIP None) 不使用 VIP,直接返回 Pod IP StatefulSet、客户端 LB

有两个以上端口时,每个端口都必须有 name,以便 Ingress 或其他对象通过名称引用端口。

NetworkPolicy 最容易写错的是 from 数组的结构。

YAML 只差一个短横线(-),含义却完全相反。考试和实际工作都会在这里分出结果。

在实际工作中会遇到的情况

**案例 1——完全没有 kube-proxy 的集群。**用 kubeadm 1.34 重建家庭实验室时,通过 --skip-phases=addon/kube-proxy 从一开始就不安装 kube-proxy,并以 kubeProxyReplacement=true 安装 Cilium 1.20.1。仅凭声称不够,还进行了实际计数。

kube-proxy 파드 수: 0
노드의 iptables KUBE- 체인 개수: 0

使用 kube-proxy 的集群中,KUBE-SERVICESKUBE-SVC-*KUBE-SEP-* 链会随服务数量达到数十到数百条,但这里为 0。那么 Service 如何工作?dump eBPF map 会看到如下内容。

SERVICE ADDRESS             BACKEND ADDRESS (REVNAT_ID) (SLOT)
10.96.0.10:53/TCP (1)       10.244.0.150:53/TCP (4) (1)
10.96.0.1:443/TCP (1)       10.0.0.120:6443/TCP (1) (1)

frontend 与 backend 直接保存在内核 hash map 中。iptables 方式会随服务增多而线性拉长规则链,eBPF 使用 hash map 查询,与服务数量无关。Service 对象保持不变,只替换 data plane,这种分离在这里成为实物。

随之而来还有 bootstrap 问题。启用 kubeProxyReplacement 时,必须同时设置 k8sServiceHost=10.0.0.120k8sServicePort=6443。没有 kube-proxy,就还没有把 kubernetes Service ClusterIP(10.96.0.1)转换为真实 apiserver 地址的主体,而将承担该职责的 Cilium 自己尚未启动。为解决鸡生蛋问题,必须直接告知真实地址。

**案例 2——iptables 无法处理 L7。**同一集群中曾应用一条让 GET 返回 200、POST 返回 403 的策略。IP 和端口相同,只按 HTTP method 区分。iptables 位于 L3/L4,看不到 method,因此原理上就不可能做到。标准 NetworkPolicy 同样只到 L3/L4。这个例子清楚划定了 CKA 范围内 NetworkPolicy 的能力边界。

**案例 3——Endpoints 已成为旧称。**v1.33 中 Endpoints API 已 deprecated。直接读取 Endpoints 的代码或脚本,应改为通过 kubernetes.io/service-name 标签查询 EndpointSlice。这是升级前检查的常见项目。

后续实验要做什么

第一个实验会创建 ClusterIP、NodePort、headless、multi-port、ExternalName 和 Ingress,并故意让 selector 拼错,使 endpoint 为空,再进行修复。第二个实验从默认拒绝开始,把 NetworkPolicy 逐步缩小为六种形式。本实验环境没有执行策略的 CNI,因此无法确认真实流量拦截,只对对象 spec 评分,转而集中处理 AND 与 OR 等 spec 陷阱。