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。四者缺一不可,排障时也要按这条链路逐段检查。
学习地图:从四层到七层,从原理到排障
本课程按“由内到外、由简到繁”的顺序推进。第一阶段聚焦 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 已分配 IP | kubectl get svc order-svc | CLUSTER-IP 非 None |
| 后端已入列 | kubectl get endpointslice -l kubernetes.io/service-name=order-svc | 3 条 ready=true 记录 |
| 集群内可访问 | 在临时 Pod 中执行 curl -s order-svc | 返回 nginx 欢迎页 |
当这张表全部通过时,说明“Service → EndpointSlice → Pod”这条最小链路已经打通,后续无论是研究 NodePort 的端口映射、LoadBalancer 的 IP 分配,还是 Ingress 的七层路由,都可以在这套环境上直接叠加验证。反之,如果某一项不通过,应先解决环境问题,再进入具体章节的实验,否则很容易把环境缺陷误读为 Service 机制本身的行为。