1. 课程导入与工程全景

在 Kubernetes 集群里,Pod 是最小的可调度单元,但它天生“短命”:滚动更新会替换 Pod、节点故障会驱逐 Pod、扩缩容会新增或删除 Pod。每一次变化都会带来 IP 地址的变动。如果客户端直接访问 Pod IP,那么任何一次发布都可能让调用方连接失败。这正是 Kubernetes Service 要解决的核心工程问题——为一组动态变化的 Pod 提供一个稳定的虚拟访问入口,并在其后端完成流量的分发与健康筛选。

但 Service 只是问题的一半。Service 的 ClusterIP 是集群内部的虚拟地址,集群外的用户无法直接访问;同时,Service 默认的四层转发能力也无法处理 HTTP 路径、域名、TLS 终止等七层需求。因此完整的工程链路通常由三层构成:Service(服务发现与四层负载均衡)→ Ingress/Gateway(七层路由与入口)→ 外部负载均衡器(云 LB 或 MetalLB 等裸金属方案)。理解这三层各自解决什么问题、边界在哪里,是本课程的主线。

本节要建立的核心认知

先看一个具体场景。假设集群中部署了一个订单服务,副本数为 3,Pod IP 分别是 10.244.1.7、10.244.2.9、10.244.3.4。我们创建一个 ClusterIP 类型的 Service,分配到的虚拟 IP 是 10.96.0.10,端口 80 映射到容器的 8080。此时集群内的调用方只需访问 http://order-svc:80,kube-proxy 会在每个节点上写入转发规则,把发往 10.96.0.10:80 的流量按规则分发到三个 Pod 的 8080 端口。当某个 Pod 被替换、IP 变为 10.244.2.15 时,Endpoints/EndpointSlice 对象会自动更新,调用方完全无感知。

这里出现了几个必须分清的对象:Service 是稳定入口的抽象;Endpoints / EndpointSlice 是 Service 与真实 Pod IP 之间的绑定关系;kube-proxy 是把这个抽象落到每个节点网络规则上的执行者;CoreDNS 则负责把 order-svc 这样的名字解析成 ClusterIP。四者缺一不可,排障时也要按这条链路逐段检查。

Kubernetes Service 与负载均衡工程全景 集群外客户端 浏览器 / 移动端 / 第三方 外部负载均衡器 云 LB / MetalLB NodePort 或 LB IP 七层入口 Ingress / Gateway API 域名 · 路径 · TLS Service ClusterIP 10.96.0.10:80 selector: app=order 稳定虚拟入口 EndpointSlice 10.244.1.7:8080 10.244.2.9:8080 · 10.244.3.4:8080 kube-proxy iptables / IPVS 每节点写入转发规则 四层负载均衡 后端 Pod(3 副本) 容器端口 8080 就绪探针通过才入列 CoreDNS order-svc → 10.96.0.10 集群内服务发现 调用链:客户端 → 外部 LB → 七层入口 → Service ClusterIP → EndpointSlice → Pod 排障链:DNS 解析 → Service 规则 → EndpointSlice 就绪 → kube-proxy 规则 → Pod 监听

学习地图:从四层到七层,从原理到排障

本课程按“由内到外、由简到繁”的顺序推进。第一阶段聚焦 Service 本身:ClusterIP、NodePort、LoadBalancer、ExternalName 四种类型的适用边界,Endpoints 与 EndpointSlice 的生成逻辑,以及 kube-proxy 在 iptables 与 IPVS 两种模式下的转发差异。第二阶段进入七层:Ingress 资源模型、Ingress Controller 的选型与部署、基于域名和路径的路由规则、TLS 证书挂载与重定向。第三阶段处理工程化问题:会话保持、超时与重试、灰度发布、健康检查与就绪探针的配合、跨命名空间访问、NetworkPolicy 对 Service 流量的影响。第四阶段是排障与性能:如何用 kubectl get endpoints、kubectl describe svc、conntrack、tcpdump 逐段定位“Service 不通”的问题,以及大规模集群下 IPVS 与 iptables 的性能取舍。

实验环境搭建

为了让每个实验都可复现,建议使用一套本地多节点集群。下面给出基于 kind 的最小可用环境,它能在单机上模拟一个控制平面加两个工作节点,足以演示 Service 转发、NodePort 访问和 Ingress 入口。

# 1. 安装 kind 与 kubectl(示例版本,可按官方文档替换)
#    kind: https://kind.sigs.k8s.io/docs/user/quick-start/
#    kubectl: https://kubernetes.io/docs/tasks/tools/

# 2. 编写集群配置,暴露 80/443 供 Ingress 使用
cat <<'EOF' > kind-svc-lab.yaml
kind: Cluster
apiVersion: kind.x-k8s.io/v1alpha4
name: svc-lab
nodes:
  - role: control-plane
    kubeadmConfigPatches:
      - |
        kind: InitConfiguration
        nodeRegistration:
          kubeletExtraArgs:
            node-labels: "ingress-ready=true"
    extraPortMappings:
      - containerPort: 80
        hostPort: 80
        protocol: TCP
      - containerPort: 443
        hostPort: 443
        protocol: TCP
  - role: worker
  - role: worker
EOF

# 3. 创建集群
kind create cluster --config kind-svc-lab.yaml

# 4. 确认节点与核心组件
kubectl get nodes -o wide
kubectl -n kube-system get pods -l k8s-app=kube-proxy
kubectl -n kube-system get svc kube-dns

集群就绪后,部署一个用于观察的示例应用,副本数设为 3,容器监听 8080,并暴露为 ClusterIP 类型的 Service:

kubectl create deployment order-svc \
  --image=nginx:1.25-alpine --replicas=3 --port=8080

kubectl expose deployment order-svc \
  --name=order-svc --port=80 --target-port=8080 --type=ClusterIP

kubectl get svc order-svc
kubectl get endpointslice -l kubernetes.io/service-name=order-svc

预期可以看到 Service 分配到一个 10.96.0.0/12 网段内的 ClusterIP,EndpointSlice 中出现三条 10.244.x.x:8080 记录,且 ready=true。如果 EndpointSlice 为空,通常说明 Pod 未就绪或 selector 不匹配,这是后续排障章节要反复用到的第一个判断点。

工具链准备

建议在实验机上固定安装以下工具,它们覆盖了从资源查看、网络抓包到七层调试的完整链路:

  • kubectl:基础资源操作,配合 -o wide、--show-labels 观察 Service 与 EndpointSlice。
  • kubens / kubectx:快速切换命名空间与上下文,减少多命名空间实验时的误操作。
  • curl 与 dig:在集群内 Pod 中验证 DNS 解析与 ClusterIP 连通性,例如 dig order-svc.default.svc.cluster.local。
  • tcpdump 与 conntrack:在节点上抓取 NodePort 或 ClusterIP 流量,观察 DNAT 前后的地址变化。
  • metrics-server:为后续 HPA 与负载观察提供基础指标。
  • Ingress Controller:本课程以 ingress-nginx 为例,通过 kind 的 ingress-ready=true 标签完成部署。
建议为每个实验单独创建命名空间,例如 kubectl create ns svc-lab,并在实验结束后用 kubectl delete ns svc-lab 清理,避免 Service 与 Ingress 规则互相干扰。

一个可复用的环境自检清单

在开始后续章节前,用下面这张检查表确认环境处于可用状态。每一项都对应一个明确的观察命令和通过标准,便于快速定位环境问题而不是把环境故障误判为 Service 配置错误。

检查项观察命令通过标准
集群节点就绪kubectl get nodes全部为 Ready
kube-proxy 运行kubectl -n kube-system get pods -l k8s-app=kube-proxy每个节点一个 Running
CoreDNS 可用kubectl -n kube-system get svc kube-dns存在 ClusterIP 且端口 53
Service 已分配 IPkubectl get svc order-svcCLUSTER-IP 非 None
后端已入列kubectl get endpointslice -l kubernetes.io/service-name=order-svc3 条 ready=true 记录
集群内可访问在临时 Pod 中执行 curl -s order-svc返回 nginx 欢迎页

当这张表全部通过时,说明“Service → EndpointSlice → Pod”这条最小链路已经打通,后续无论是研究 NodePort 的端口映射、LoadBalancer 的 IP 分配,还是 Ingress 的七层路由,都可以在这套环境上直接叠加验证。反之,如果某一项不通过,应先解决环境问题,再进入具体章节的实验,否则很容易把环境缺陷误读为 Service 机制本身的行为。