Skip to content

Kubernetes Service 原理由浅入深

本文从“为什么需要 Service”开始,逐步深入到 kube-proxy 实现、EndpointSlice、DNS、负载均衡、高级流量策略等核心机制。适合已经了解 Pod 概念、希望系统掌握 Service 原理的读者。


目录

  1. 初识 Service:解决 Pod 的动态性
  2. Service 的核心抽象
  3. Service 类型详解
  4. Endpoints 与 EndpointSlice
  5. kube-proxy:Service 的实现引擎
  6. Cluster DNS 与服务发现
  7. Headless Service 与有状态服务
  8. ExternalName 与外部服务映射
  9. LoadBalancer 与云厂商集成
  10. Ingress 与 Service 的关系
  11. 高级话题:拓扑感知、会话保持、流量策略
  12. 故障排查常用命令
  13. 总结

1. 初识 Service:解决 Pod 的动态性

1.1 Pod 的问题

在 Kubernetes 中,Pod 是最小的调度单元,但 Pod 具有以下特点:

  • 生命周期短暂:Pod 可能因扩缩容、滚动更新、节点故障、资源不足等原因被销毁和重建。
  • IP 不固定:每个 Pod 被调度后才会分配 IP,重建后 IP 通常改变。
  • 动态扩缩容:ReplicaSet/Deployment 可以随时增加或减少 Pod 数量。

如果直接通过 Pod IP 访问服务,调用方需要时刻跟踪后端 Pod 的变化,这在分布式系统中不可行。

1.2 Service 的引入

Kubernetes 引入 Service 作为一层稳定的抽象:

  • 为后端一组 Pod 提供一个 稳定的虚拟 IP(ClusterIP)
  • 通过 Label Selector 动态关联 Pod。
  • 在 Pod 变化时自动更新转发目标。
  • 提供 负载均衡服务发现 能力。
┌─────────────────────────────────────┐
│              Service                │
│      ClusterIP: 10.96.123.45        │
│      selector: app=web, tier=front  │
└──────────────┬──────────────────────┘

       ┌───────┼───────┐
       ▼       ▼       ▼
   ┌──────┐ ┌──────┐ ┌──────┐
   │ Pod  │ │ Pod  │ │ Pod  │
   │10.244│ │10.244│ │10.244│
   │.1.10 │ │.1.11 │ │.1.12 │
   └──────┘ └──────┘ └──────┘

2. Service 的核心抽象

2.1 Service 定义示例

yaml
apiVersion: v1
kind: Service
metadata:
  name: web-service
  namespace: default
spec:
  type: ClusterIP          # Service 类型
  selector:
    app: web               # 通过标签选择后端 Pod
  ports:
    - port: 80             # Service 暴露的端口
      targetPort: 8080     # 后端 Pod 容器端口
      protocol: TCP        # 默认 TCP,可选 UDP/SCTP

2.2 关键字段说明

字段含义
spec.typeService 类型:ClusterIP / NodePort / LoadBalancer / ExternalName
spec.selector标签选择器,决定哪些 Pod 属于该 Service
spec.ports[].portService 自身暴露的端口
spec.ports[].targetPort后端 Pod 上容器实际监听的端口
spec.ports[].nodePortNodePort 类型时节点上暴露的端口(默认 30000-32767)
spec.clusterIP自动分配的虚拟 IP,可手动指定 None 表示 Headless
spec.sessionAffinity会话保持策略,NoneClientIP
spec.externalTrafficPolicy外部流量策略,ClusterLocal
spec.internalTrafficPolicy内部流量策略,ClusterLocal

2.3 Service 与 Pod 的关联

Service 本身不直接代理流量,它通过 Endpoints/EndpointSlice 对象记录后端 Pod 的 IP:Port。kube-proxy 监听这些对象,并在节点上配置转发规则。


3. Service 类型详解

3.1 ClusterIP(默认)

  • 分配一个仅在集群内部可达的虚拟 IP。
  • 适用于集群内部微服务之间的调用。
  • 流量路径:Client Pod -> Service ClusterIP -> kube-proxy 转发 -> Backend Pod
yaml
spec:
  type: ClusterIP
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 8080

3.2 NodePort

  • 在 ClusterIP 基础上,在每个节点上开放一个固定端口(NodePort)。
  • 外部流量可通过 <NodeIP>:<NodePort> 访问 Service。
  • NodePort 范围默认 30000-32767,可通过 apiserver 参数调整。
yaml
spec:
  type: NodePort
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 8080
      nodePort: 30080   # 可选,不指定则自动分配

3.3 LoadBalancer

  • 在 NodePort 基础上,请求云厂商(或 MetalLB 等)创建一个外部负载均衡器。
  • 自动分配一个外部 IP(EXTERNAL-IP),外部用户可直接访问。
  • 云厂商负责将流量转发到节点 NodePort 或 Pod(取决于实现)。
yaml
spec:
  type: LoadBalancer
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 8080

3.4 ExternalName

  • 没有 selector,也不分配 ClusterIP。
  • 将 Service 名称映射到一个外部 DNS 名称(CNAME)。
  • 常用于将集群内服务平滑迁移到外部服务,或反之。
yaml
apiVersion: v1
kind: Service
metadata:
  name: external-db
spec:
  type: ExternalName
  externalName: db.example.com

查询 external-db.default.svc.cluster.local 会返回 db.example.com 的 CNAME 记录。


4. Endpoints 与 EndpointSlice

4.1 Endpoints(旧机制)

当 Service 定义了 selector,Kubernetes 控制平面会自动创建同名的 Endpoints 对象,记录所有匹配 Pod 的 IP:targetPort

yaml
apiVersion: v1
kind: Endpoints
metadata:
  name: web-service
subsets:
  - addresses:
      - ip: 10.244.1.10
      - ip: 10.244.1.11
    ports:
      - port: 8080

4.2 EndpointSlice(推荐)

Endpoints 在大规模集群中存在性能和可扩展性问题(单个对象过大)。Kubernetes 1.21+ 默认使用 EndpointSlice

  • 将后端端点拆分为多个 Slice,每个最多 100 个端点。
  • 支持更丰富的元数据(拓扑信息、条件状态等)。
  • 更高效的增量更新,降低网络和控制平面压力。
yaml
apiVersion: discovery.k8s.io/v1
kind: EndpointSlice
metadata:
  name: web-service-abc12
  labels:
    kubernetes.io/service-name: web-service
addressType: IPv4
ports:
  - name: http
    protocol: TCP
    port: 8080
endpoints:
  - addresses:
      - 10.244.1.10
    conditions:
      ready: true
    nodeName: node-1
    zone: cn-north-1a

4.3 无 Selector 的 Service

如果 Service 没有 selector,需要手动创建 Endpoints/EndpointSlice,用于指向集群外部服务或自定义后端。


5. kube-proxy:Service 的实现引擎

Service 的 ClusterIP 是一个虚拟 IP,本身没有进程监听。真正实现负载均衡的是运行在每个节点上的 kube-proxy

5.1 kube-proxy 三种工作模式

5.1.1 userspace 模式(已废弃)

  • kube-proxy 作为用户态代理进程监听端口。
  • 流量先进入 kube-proxy,再由它转发给后端 Pod。
  • 性能差、用户态/内核态切换开销大,现代集群已不再使用。

5.1.2 iptables 模式(默认)

  • kube-proxy 监听 Service/EndpointSlice 变化,动态生成 iptables 规则。
  • 数据包在内核态直接被 DNAT 到后端 Pod,无需用户态进程参与。
  • 负载均衡采用随机算法(probability 规则链)。

优点:性能较好,无额外进程。 缺点

  • 后端 Pod 数量多时规则链庞大,更新慢。
  • 负载均衡算法单一。
  • 无法处理长连接的优雅重试(老连接可能仍指向失效 Pod)。
数据包流向:
Client -> PREROUTING -> KUBE-SERVICES -> KUBE-SVC-XXX -> KUBE-SEP-XXX -> DNAT -> Pod

5.1.3 ipvs 模式(推荐大规模使用)

  • kube-proxy 调用 Linux IPVS(IP Virtual Server)模块创建虚拟服务器。
  • 每个 Service 对应一个 IPVS virtual server,每个后端 Pod 对应一个 real server。
  • 支持多种调度算法:rr(轮询)、lc(最少连接)、dhshsednq

优点

  • 转发性能接近直接路由,规则更新快。
  • 支持的负载均衡算法丰富。
  • 后端数量大时优势明显。

启用方式

bash
kube-proxy --proxy-mode=ipvs --ipvs-scheduler=rr

需要节点加载 ip_vs 等相关内核模块。

5.2 数据包完整流程(以 iptables 为例)

┌─────────────┐         ┌─────────────────┐         ┌─────────────┐
│  Client Pod │ ──────> │  Service:80     │         │             │
│ 10.244.1.5  │         │ 10.96.123.45    │         │  Backend    │
└─────────────┘         └────────┬────────┘         │   Pod       │
                                 │                  │ 10.244.1.10 │
                                 │ kube-proxy       └─────────────┘
                                 │ iptables DNAT    ┌─────────────┐
                                 └────────────────> │  Backend    │
                                                    │   Pod       │
                                                    │ 10.244.1.11 │
                                                    └─────────────┘

5.3 查看 kube-proxy 规则

bash
# 查看 iptables 中 Service 相关链
iptables -t nat -L KUBE-SERVICES -n | grep <service-name>

# 查看 ipvs 虚拟服务
ipvsadm -Ln

6. Cluster DNS 与服务发现

6.1 DNS 解析机制

Kubernetes 集群通常运行 CoreDNS(或旧版 kube-dns),为 Service 提供 DNS 记录:

记录类型示例说明
A / AAAAweb-service.default.svc.cluster.local解析为 ClusterIP
SRV_http._tcp.web-service.default.svc.cluster.local端口服务记录
PTR反向解析 Pod / Service IP用于日志、监控
CNAMEexternal-db.default.svc.cluster.localExternalName 类型

6.2 Pod DNS 策略

通过 dnsPolicy 控制 Pod 的 DNS 行为:

  • ClusterFirst(默认):优先使用集群 DNS。
  • Default:继承节点 DNS 配置。
  • ClusterFirstWithHostNet:hostNetwork Pod 使用集群 DNS。
  • None:完全自定义 DNS 配置,配合 dnsConfig

6.3 同命名空间与跨命名空间访问

bash
# 同命名空间
curl http://web-service

# 跨命名空间
curl http://web-service.production

# 完整 FQDN
curl http://web-service.production.svc.cluster.local

7. Headless Service 与有状态服务

7.1 什么是 Headless Service

spec.clusterIP 设为 None,Service 不再分配 ClusterIP,kube-proxy 也不为其创建转发规则。

DNS 查询直接返回后端 Pod 的 IP 列表(A 记录)或有状态 Pod 的 SRV 记录。

yaml
apiVersion: v1
kind: Service
metadata:
  name: web-headless
spec:
  clusterIP: None
  selector:
    app: web
  ports:
    - port: 80
      targetPort: 8080

7.2 适用场景

  • 需要客户端自己决定连接哪个后端(如自定义负载均衡、分片)。
  • 有状态服务需要稳定的网络标识(配合 StatefulSet 使用)。
  • 需要直接获取所有后端 Pod IP(如 Prometheus 服务发现)。

7.3 StatefulSet 与 Headless Service

StatefulSet 每个 Pod 拥有稳定的:

  • 名称<statefulset-name>-<ordinal>,如 web-0web-1
  • 网络标识<pod-name>.<service-name>.<namespace>.svc.cluster.local
  • 存储:通过 volumeClaimTemplates 每个 Pod 拥有独立 PVC。
Pod: web-0
DNS: web-0.web-headless.default.svc.cluster.local

8. ExternalName 与外部服务映射

ExternalName 本质是一个 CNAME 别名:

yaml
apiVersion: v1
kind: Service
metadata:
  name: external-api
spec:
  type: ExternalName
  externalName: api.external-provider.com

集群内应用可以像访问内部 Service 一样访问外部域名:

bash
curl http://external-api

DNS 会返回 api.external-provider.com 的 CNAME,再由外部 DNS 解析为实际 IP。


9. LoadBalancer 与云厂商集成

9.1 云厂商 LoadBalancer

在公有云(AWS、GCP、Azure、阿里云、腾讯云等)中,创建 type: LoadBalancer 的 Service 会触发云控制器管理器(Cloud Controller Manager)调用云平台 API 创建负载均衡器:

  • 分配外部 IP。
  • 配置健康检查。
  • 将流量转发到节点 NodePort 或 Pod(部分云厂商支持直接路由)。

9.2 裸金属方案:MetalLB

在自建机房或裸金属集群中,可使用 MetalLB 为 LoadBalancer Service 分配 IP:

  • Layer 2 模式:通过 ARP/NDP 宣告 IP,简单但存在单点瓶颈。
  • BGP 模式:与路由器建立 BGP 会话,实现真正的负载均衡和高可用。

9.3 负载均衡器健康检查

云厂商 LB 通常探测节点上的 NodePort。如果节点上没有后端 Pod(例如 externalTrafficPolicy=Local),LB 不应将流量发送到该节点,否则会出现连接失败。


10. Ingress 与 Service 的关系

Ingress 不是 Service 类型,而是基于 HTTP/HTTPS 的七层路由规则。Ingress Controller(如 NGINX Ingress Controller、Traefik)通过监听 Ingress 资源,将外部流量按域名、路径路由到不同的 Service。

Internet


┌─────────────┐
│   Ingress   │  <- Ingress Controller (e.g., NGINX)
│  Controller │
└──────┬──────┘


┌─────────────┐
│   Service   │  <- 四层 ClusterIP/NodePort
│  ClusterIP  │
└──────┬──────┘


   Backend Pods

Service 是四层的,Ingress 是七层的。Ingress 最终依赖 Service 将流量转发到 Pod。


11. 高级话题:拓扑感知、会话保持、流量策略

11.1 会话保持(Session Affinity)

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

开启后,同一客户端 IP 的流量始终转发到同一个后端 Pod(基于 iptables/ipvs 的 recent 模块)。注意:对 NAT 后的多客户端可能集中到同一 IP。

11.2 外部流量策略(externalTrafficPolicy)

  • Cluster(默认):外部流量进入任意节点后,可能再被转发到其他节点的 Pod。SNAT 后源 IP 被改写为节点 IP。
  • Local:流量只转发到本节点上的 Pod,保留真实客户端源 IP。但如果本节点没有 Pod,连接会被丢弃。

11.3 内部流量策略(internalTrafficPolicy)

  • Cluster(默认):内部流量可转发到任意节点的 Pod。
  • Local:只转发到与客户端同一节点的 Pod,减少跨节点流量,但可能降低负载均衡效果。

11.4 拓扑感知路由(Topology Aware Routing / Topology Aware Hints)

EndpointSlice 可携带 zonenodeName 等拓扑信息,配合 Service 的注解或 topologyKeys 历史字段,使流量优先在同一可用区或同一节点内路由,降低延迟和跨区带宽。

yaml
metadata:
  annotations:
    service.kubernetes.io/topology-mode: Auto

11.5 健康检查与就绪

只有 Readiness Probe 通过且未处于 Terminating 状态的 Pod 才会被加入 Endpoints/EndpointSlice。因此,务必为生产服务配置 readinessProbe,否则未就绪的 Pod 会收到流量。


12. 故障排查常用命令

bash
# 查看 Service 列表
kubectl get svc -o wide

# 查看 Endpoints/EndpointSlice
kubectl get endpoints <svc-name>
kubectl get endpointslices -l kubernetes.io/service-name=<svc-name>

# 查看 Pod 标签是否匹配 Service selector
kubectl get pods -l app=web --show-labels

# 从 Pod 内访问 Service
curl http://<svc-name>.<namespace>.svc.cluster.local:<port>

# 查看 kube-proxy 日志
kubectl logs -n kube-system -l k8s-app=kube-proxy

# 节点上查看 iptables/ipvs 规则
iptables -t nat -L KUBE-SERVICES -n | grep <svc-name>
ipvsadm -Ln

# 检查 DNS 解析
kubectl run -it --rm debug --image=busybox:1.28 --restart=Never -- nslookup <svc-name>

# 查看 Service 事件
kubectl describe svc <svc-name>

13. 总结

主题核心要点
Service 本质为一组 Pod 提供稳定访问入口的抽象
服务发现通过 DNS(CoreDNS)+ Endpoints/EndpointSlice 实现
流量转发kube-proxy 通过 iptables/ipvs 将 ClusterIP 映射到后端 Pod
类型选择ClusterIP 内网、NodePort 测试、LoadBalancer 公网、ExternalName 别名
有状态服务Headless Service + StatefulSet 提供稳定网络标识
七层路由Ingress 依赖 Service 完成最终 Pod 转发
高级策略会话保持、externalTrafficPolicy、internalTrafficPolicy、拓扑感知
生产注意配置 readinessProbe,理解 externalTrafficPolicy=Local 的源 IP 保留与风险

掌握 Service,就掌握了 Kubernetes 集群内部服务通信的“交通枢纽”。


文档生成时间:2026-07-17