Appearance
Service 与转发
Service 解决的是 Pod IP 不稳定的问题。Pod 会重建、漂移、扩缩,IP 跟着变。Service 给调用方提供稳定的名称和虚拟 IP(ClusterIP),再把流量转给后端 Ready Pod。
Service 和 EndpointSlice
Service 通过 selector 找 Pod,控制器生成 EndpointSlice 保存后端 IP 列表:
bash
kubectl get svc web -n demo
kubectl get endpointslice -n demo -l kubernetes.io/service-name=web
kubectl get pod -n demo -l app=web -o wideService 存在但 EndpointSlice 为空——通常是 selector 没匹配到任何 Ready Pod,或者 Pod 的 readinessProbe 没通过。
ClusterIP
ClusterIP 是集群内服务发现的基础入口,只在集群内部可达:
yaml
apiVersion: v1
kind: Service
metadata:
name: web
namespace: demo
spec:
type: ClusterIP
selector:
app: web
ports:
- name: http
port: 80 # Service 端口
targetPort: 8080 # Pod 容器端口访问:
bash
curl http://web.demo.svc.cluster.local同 namespace 可以直接用短名 web。跨 namespace 用完整 DNS 名更清楚——域名里 namespace 写错是常见问题。
NodePort
NodePort 在每个节点上打开一个端口,外部通过 NodeIP:NodePort 能访问到 Service:
yaml
apiVersion: v1
kind: Service
metadata:
name: web-nodeport
namespace: demo
spec:
type: NodePort
selector:
app: web
ports:
- port: 80
targetPort: 8080
nodePort: 30080 # 默认范围 30000-32767NodePort 适合实验和裸机临时入口。生产里用 NodePort 时,前面通常还有 HAProxy、LVS、硬件负载均衡或云负载均衡做统一入口。
LoadBalancer
LoadBalancer 依赖云控制器或裸机负载均衡实现来分配外部 IP:
| 环境 | 常见实现 |
|---|---|
| 公有云 | 云厂商 SLB/ELB/NLB |
| 裸机 | MetalLB、kube-vip、外部 LB |
| 本地测试 | minikube tunnel、kind + 额外组件 |
裸机集群直接创建 LoadBalancer 类型的 Service,EXTERNAL-IP 会一直显示 <pending>——不是 Service 写错了,而是集群里没有能分配外部 IP 的控制器。
kube-proxy——把 Service 规则落到节点
kube-proxy 负责把 Service 规则变成节点上的转发规则。常见两种模式:
| 模式 | 特点 |
|---|---|
| iptables | 规则链转发,通用,但规则多时排查很重 |
| IPVS | 内核级负载均衡,适合大规模 Service |
bash
kubectl -n kube-system get cm kube-proxy -o yaml | grep mode
ipvsadm -Ln # IPVS 模式看转发规则
iptables-save | grep KUBE-SVC | head # iptables 模式看转发规则Service 转发不通时,先直连 Pod IP 测试。Pod IP 通但 Service 不通,问题在 Service、EndpointSlice、kube-proxy 或节点转发规则;Pod IP 就不通,问题更可能在 CNI。
DNS
CoreDNS 把 Service 名称解析到 ClusterIP,不负责后面 Service 到 Pod 的转发:
bash
kubectl -n kube-system get pods -l k8s-app=kube-dns
kubectl run dns-test --rm -it --image=busybox:1.36 --restart=Never -- sh
# Pod 内
nslookup kubernetes.default.svc.cluster.local
nslookup web.demo.svc.cluster.localDNS 解析成功只说明名字能转成 ClusterIP。后端是否可用还要看 EndpointSlice 和 Pod 状态。
常见排查链路
bash
kubectl -n demo get svc web
kubectl -n demo get endpointslice -l kubernetes.io/service-name=web
kubectl -n demo get pod -l app=web -o wide临时 Pod 验证:
bash
kubectl run curl --rm -it --image=curlimages/curl --restart=Never -- sh
# Pod 内
curl -v http://web.demo.svc.cluster.local
curl -v http://<pod-ip>:8080| 现象 | 方向 |
|---|---|
| DNS 不解析 | CoreDNS、Pod DNS 配置、NetworkPolicy |
| Service 无后端 | selector、labels、readiness |
| 直连 Pod 通,Service 不通 | kube-proxy、EndpointSlice、Service 端口 |
| 同节点通,跨节点不通 | CNI、节点路由、防火墙 |