Kubernetes

K8s Service 核心原理

·13 分钟阅读·5074 字
📋 目录

K8s Service 核心原理

📖 K8s 网络模型(4 层通信契约)

K8s 官方规定集群四层流量模型,Pod 独占集群唯一 IP,同集群所有 Pod 直连互通、无 NAT

1. Pod 内部通信(容器 ↔ 同 Pod 容器)

同一 Pod 所有容器共享同一个 network namespace,通过 localhost/127.0.0.1 本地通信,无需走网卡/网桥。Pause 容器占位网络栈,业务容器共用 pause 的 net ns。

2. Pod ↔ Pod 通信(CNI 实现)

场景实现方式
同节点veth pair + Linux 网桥(cni0/bridge)二层转发
跨节点CNI 插件(Flannel/Calico/Cilium)完成跨主机路由/隧道转发,源 Pod IP 不变、不 NAT

3. Pod ↔ Service 通信

kube-proxy 实现,三种代理模式:userspace(淘汰)、iptables(默认)、IPVS(生产首选)。

4. 集群外部 ↔ Service 通信

四种暴露方式:NodePort、LoadBalancer、Ingress、ExternalIPs。

Pod 访问外网:Pod 出网经过节点 SNAT,源 IP 转为宿主机 IP。


⚡ veth pair(容器网络基础)

veth pair 是成对出现的虚拟网卡设备,像一根网线两端各插一块网卡,一端进数据另一端立刻出数据。

在 K8s 中的作用

  • 一端留在宿主机 netns(挂在网桥 cni0/主机路由)
  • 另一端放进 Pod 的 netns,作为 Pod 网卡 eth0
  • 实现 Pod 和宿主机互通

数据流Pod eth0 → veth peer → 宿主机网桥/协议栈 → 跨节点/外网


🔧 Pod 端口命名

在 Pod 的 yaml 中给容器端口起名字,Service 的 targetPort 直接引用名字而非端口号:

## 📝 Pod 定义
ports:
- name: http
  containerPort: 80

## 🔗 Service 引用
targetPort: http

优势:端口更改时(如 80→8080)只需改 Pod,Service 无需修改。


⚙️ 4 种 Service 类型底层原理

1️⃣ ClusterIP(默认,最基础)

  • 作用:集群内部访问,外部无法访问
  • 实现:kube-proxy 生成虚拟 IP(ClusterIP),内核规则拦截访问该 IP 的包,做 DNAT 转发到 Pod IP
  • 数据流Pod → ClusterIP → DNAT → PodIP

2️⃣ NodePort(对外暴露最常用)

  • 作用:让集群外部能访问服务
  • 实现:自动创建 ClusterIP,在每个节点打开相同端口(30000-32768),节点端口收到流量 → 转发给 ClusterIP → 转发给 Pod
  • 数据流浏览器 → 节点IP:NodePort → ClusterIP → Pod
  • 关键:本质是节点端口 → 转发到 ClusterIP

3️⃣ LoadBalancer(云厂商入口)

  • 作用:给服务独立公网 IP
  • 实现:自动创建 ClusterIP + NodePort,调用云厂商 API 创建负载均衡器,后端绑定所有节点的 NodePort
  • 数据流公网用户 → 公网LB IP → 节点NodePort → ClusterIP → Pod
  • 限制:依赖云厂商,裸机 K8s 无法使用

4️⃣ ExternalName(特殊类型)

  • 作用:把 K8s 内部域名映射到外部域名
  • 实现:没有 ClusterIP,没有 kube-proxy 规则,仅在 CoreDNS 生成一条 CNAME 记录
  • 数据流Pod 请求 service 域名 → CoreDNS 返回外部域名 → Pod 直接访问外部服务

包含关系

LoadBalancer 包含 NodePort → NodePort 包含 ClusterIP → ExternalName 独立

🚀 Service 负载均衡完整流程

  1. Service 是抽象资源 — 拥有固定 ClusterIP,但没有进程监听
  2. Endpoint / EndpointSlice — 通过标签选择器自动收集后端 Pod IP,形成可用后端列表
  3. kube-proxy 监听变化 — 一旦 Pod 增删,立刻更新节点内核规则
  4. 流量被内核规则拦截 — 拦截访问 ClusterIP 的包,负载均衡算法选择后端 Pod,执行 DNAT
  5. 返回流量原路返回(自动 SNAT 修正)

关键特性

特性说明
转发方式DNAT(目标地址 ClusterIP → PodIP)
层级4 层转发(TCP/UDP),不解析 HTTP
会话保持默认无,需开启 sessionAffinity: ClientIP
转发位置节点内核态,非中心化转发
健康检查依赖 Pod 的 readinessProbe,不可用 Pod 被移出 Endpoint

🌐 K8s 服务发现

环境变量方式

Pod 启动时,集群把同命名空间已存在的 Service 信息注入容器环境变量: SVC_NAME_SERVICE_HOST=ClusterIP

缺点:Service 晚于 Pod 创建则无变量、不能跨命名空间、不动态刷新,生产极少使用。

CoreDNS 域名解析(主流方案)

  1. 集群内置 CoreDNS,监听域名解析请求
  2. Service 域名规则:
    • 同命名空间:服务名
    • 跨命名空间:服务名.命名空间.svc.cluster.local
  3. 流程:Pod 发起解析 → CoreDNS 查询 → 返回 ClusterIP → kube-proxy 转发到 Pod

Headless ServiceclusterIP: None):DNS 直接返回全部 Pod IP,不用 ClusterIP 与 kube-proxy,多用于有状态应用。


💾 Pod 访问外网完整链路

Pod 内部 → PodIP 发出报文(10.244.x.x:公网IP)
  → 通过 veth pair 到达宿主机
  → 宿主机路由匹配默认网关(0.0.0.0/0)
  → iptables SNAT(源 PodIP 替换为节点物理 IP)
  → 经过物理网卡 → 机房网关 → 公网
  → 回程报文原路返回(DNAT 还原为 PodIP)

关键点

  • NodePort/LoadBalancer 入站 ≠ 出站:Pod 主动出外网是 SNAT;外网主动进集群是 DNAT
  • hostNetwork: true 的 Pod 共享宿主机网络栈,直接使用节点 IP 出网,无额外 SNAT

🔒 静态 Pod

静态 Pod = kubelet 直接管理、不经过 APIServer、配置存在节点本地 yaml 的 Pod。

五大特点

  1. 管理权在 kubelet — 不经过 APIServer、scheduler、controller-manager
  2. 镜像 Pod(Mirror Pod) — kubelet 向 APIServer 注册只读镜像,kubectl delete 删不掉
  3. 固定节点 — 不能调度漂移
  4. 自愈 — 容器崩溃自动重启
  5. 限制 — 不能引用 ConfigMap/Secret/SA

典型场景

Master 控制平面组件全是静态 Pod:kube-apiserver、kube-controller-manager、kube-scheduler、etcd

管理方式

## 放 yaml 到 manifest 目录自动创建
cp pod.yaml /etc/kubernetes/manifests/

## 删掉 yaml 自动删除 pod
rm /etc/kubernetes/manifests/pod.yaml

kubelet 默认 20s 扫描一次目录,改文件自动更新 Pod。


📊 无头服务(Headless Service)

Headless Service 是将 .spec.clusterIP 设置为 "None" 的 Service,Kubernetes 不会为其分配 ClusterIP。

特性普通 ServiceHeadless Service
ClusterIP✅ 分配虚拟 IP❌ 不分配(None
负载均衡✅ kube-proxy DNAT❌ 无负载均衡
DNS 解析解析到 ClusterIP返回所有 Pod IP 列表
适用场景普通服务发现StatefulSet、需要直连 Pod 的场景

典型场景:StatefulSet 使用 Headless Service,每个 Pod 通过固定 DNS 名称直连:

  • pod-0.svc-name.ns.svc.cluster.local
  • pod-1.svc-name.ns.svc.cluster.local

🎯 流量策略

internalTrafficPolicy(内部流量策略)

控制集群内部流量如何路由到端点:

行为适用场景
Cluster(默认)流量可路由到集群中任意节点的端点默认行为
Local流量仅路由到本地节点的端点减少跨节点转发,保留源 IP

externalTrafficPolicy(外部流量策略)

控制外部流量如何路由到端点:

行为源 IP
Cluster(默认)流量可能被转发到其他节点丢失源 IP(SNAT)
Local流量仅路由到本地节点的端点保留客户端源 IP

trafficDistribution(流量分发)

特性状态:Kubernetes v1.33 [stable]

控制流量路由偏好,不同于流量策略的严格语义保证,流量分发表达偏好

行为
PreferSameZone优先路由到同区域的端点
PreferSameNode优先路由到同节点的端点

📋 会话亲和性(Session Affinity)

确保来自同一客户端的连接总是转发到同一个 Pod。

spec:
  sessionAffinity: ClientIP
  sessionAffinityConfig:
    clientIP:
      timeoutSeconds: 10800  # 默认 3 小时

适用场景:有状态应用(如 Web 会话)、需要本地缓存的场景。


🔄 应用协议(appProtocol)

特性状态:Kubernetes v1.20 [stable]

appProtocol 字段为每个 Service 端口设置应用协议:

spec:
  ports:
  - port: 80
    targetPort: 8080
    protocol: TCP
    appProtocol: kubernetes.io/h2c  # HTTP/2 明文

常用取值:kubernetes.io/h2c(HTTP/2 明文)


关联文档

  • K8s Service DNS 实现原理 — DNS 解析流程
  • K8s Service 高级配置 — externalIPs、Endpoint 手动配置
  • ../network/kube-proxy 流量转发与代理模式详解 — 流量转发底层机制
  • K8s 核心概念#🌐 网络与通信 — Service 概念基础

关联文档

  • ../core/K8s 核心概念 — 核心概念速查
  • K8s Service DNS 实现原理 — CoreDNS 域名解析
  • ../../network/网络 — 网络基础模型
  • K8s 组件详解#kube-proxy — kube-proxy 组件详解

关联文档