16.4.6 负载均衡与流量调度

在 Kubernetes 中,负载均衡与流量调度覆盖 Service 四层与 Ingress 七层入口,是确保请求稳定、可控、可观测的关键。本节从原理、安装与配置、验证、排错与练习串起完整链路,便于落地。

文章图片

一、Service 四层负载均衡原理与配置示例#

Service 由 kube-proxy 转发,核心是 Endpoints 与 iptables/IPVS 规则。推荐生产使用 IPVS。

1.1 kube-proxy 切换 IPVS 模式(示例)#

# 查看当前模式
kubectl -n kube-system get cm kube-proxy -o yaml | grep mode

# 修改为 ipvs 并重启 kube-proxy
kubectl -n kube-system edit cm kube-proxy
# 将 mode: "" 改为 mode: "ipvs"

kubectl -n kube-system delete pod -l k8s-app=kube-proxy

命令解释:
- edit cm kube-proxy 修改转发模式
- 删除 pod 触发重建以加载新配置
- IPVS 规则更适合大规模集群(性能与规则可控性)

1.2 Service 示例(ClusterIP)#

/root/k8s/service-demo.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-demo
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web-demo
  template:
    metadata:
      labels:
        app: web-demo
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
  name: web-demo-svc
spec:
  selector:
    app: web-demo
  type: ClusterIP
  ports:
  - name: http
    port: 80
    targetPort: 80
kubectl apply -f /root/k8s/service-demo.yaml
kubectl get svc web-demo-svc -o wide
kubectl get ep web-demo-svc

预期效果:
- svc 显示 ClusterIP
- endpoints 有两个 Pod IP

1.3 NodePort 访问验证#

kubectl patch svc web-demo-svc -p '{"spec":{"type":"NodePort","ports":[{"port":80,"targetPort":80,"nodePort":30080}]}}'
kubectl get svc web-demo-svc

# 在集群任一节点访问
curl -I http://<NodeIP>:30080

命令解释:
- patch 修改服务类型
- NodePort 直接映射节点端口

二、Ingress 七层路由与流量调度#

2.1 安装 Nginx Ingress Controller(简化版)#

kubectl apply -f https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/cloud/deploy.yaml

kubectl -n ingress-nginx get pods
kubectl -n ingress-nginx get svc

说明:
- ingress-nginx-controller 默认暴露为 LoadBalancer/NodePort
- 生产需结合云 LB 或 MetalLB

2.2 Ingress 规则示例#

/root/k8s/ingress-demo.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-demo-ing
  annotations:
    nginx.ingress.kubernetes.io/rewrite-target: /
spec:
  ingressClassName: nginx
  rules:
  - host: demo.example.com
    http:
      paths:
      - path: /web
        pathType: Prefix
        backend:
          service:
            name: web-demo-svc
            port:
              number: 80
kubectl apply -f /root/k8s/ingress-demo.yaml
kubectl get ingress web-demo-ing

访问验证:

# 将域名解析到 Ingress Controller 对外IP
curl -H "Host: demo.example.com" http://<IngressIP>/web

命令解释:
- ingressClassName 指定控制器
- rewrite-target 重写路径

三、外部负载均衡(MetalLB 示例)#

3.1 安装 MetalLB(裸金属)#

kubectl apply -f https://raw.githubusercontent.com/metallb/metallb/v0.13.12/config/manifests/metallb-native.yaml
kubectl -n metallb-system get pods

3.2 配置地址池#

/root/k8s/metallb-pool.yaml

apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
  name: demo-pool
  namespace: metallb-system
spec:
  addresses:
  - 192.168.10.200-192.168.10.210
---
apiVersion: metallb.io/v1beta1
kind: L2Advertisement
metadata:
  name: demo-l2
  namespace: metallb-system
kubectl apply -f /root/k8s/metallb-pool.yaml
kubectl get svc -A | grep LoadBalancer

预期效果:
LoadBalancer 类型 Service 获得外部 IP

四、流量调度策略示例#

4.1 会话保持(Session Affinity)#

kubectl patch svc web-demo-svc -p '{"spec":{"sessionAffinity":"ClientIP"}}'
kubectl describe svc web-demo-svc | grep -i affinity

说明:
- ClientIP 让同一客户端固定到同一后端

4.2 权重灰度(通过 Ingress 多后端)#

/root/k8s/ingress-canary.yaml

apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
  name: web-demo-canary
  annotations:
    nginx.ingress.kubernetes.io/canary: "true"
    nginx.ingress.kubernetes.io/canary-weight: "20"
spec:
  ingressClassName: nginx
  rules:
  - host: demo.example.com
    http:
      paths:
      - path: /web
        pathType: Prefix
        backend:
          service:
            name: web-demo-svc-canary
            port:
              number: 80

说明:
- 20% 流量进入 canary 服务

4.3 超时与重试(Ingress 注解)#

metadata:
  annotations:
    nginx.ingress.kubernetes.io/proxy-connect-timeout: "3"
    nginx.ingress.kubernetes.io/proxy-read-timeout: "10"
    nginx.ingress.kubernetes.io/proxy-send-timeout: "10"

五、就绪探针与流量控制#

/root/k8s/readiness-demo.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: web-ready
spec:
  replicas: 2
  selector:
    matchLabels:
      app: web-ready
  template:
    metadata:
      labels:
        app: web-ready
    spec:
      containers:
      - name: nginx
        image: nginx:1.25
        ports:
        - containerPort: 80
        readinessProbe:
          httpGet:
            path: /
            port: 80
          initialDelaySeconds: 5
          periodSeconds: 3

命令解释:
- Readiness 未通过时 Pod 不进入 Endpoints
- 防止未就绪实例接收流量

六、排错清单(常见故障)#

6.1 Service 无法访问#

kubectl get svc,ep web-demo-svc
kubectl get pod -l app=web-demo -o wide

排错要点:
- Endpoints 为空:标签选择器不匹配
- Pod Ready=0:探针失败

6.2 Ingress 无法路由#

kubectl describe ingress web-demo-ing
kubectl -n ingress-nginx logs deploy/ingress-nginx-controller | tail -n 50

排错要点:
- 规则未生效:ingressClassName 错误
- 503/404:后端服务名/端口错误

6.3 MetalLB 无法分配 IP#

kubectl -n metallb-system get ipaddresspools,l2advertisements
kubectl -n metallb-system logs deploy/controller | tail -n 50

排错要点:
- 地址池与节点网段冲突
- ARP 被交换机策略阻断

七、练习题(动手验证)#

  1. web-demo-svc 从 ClusterIP 改为 LoadBalancer,并通过 MetalLB 获得外部 IP。
  2. 为同一域名创建两个版本服务,配置 canary 权重 10%,验证流量比例。
  3. 手动制造一个 Pod 探针失败,观察 Endpoints 是否自动剔除。
  4. 切换 kube-proxy 到 IPVS,使用 ipvsadm -Ln 查看规则(需在节点执行)。
# 节点执行:查看 IPVS 规则
sudo ipvsadm -Ln

通过以上示例与排错链路,可以系统理解 Service 与 Ingress 的负载均衡方式,并掌握基础的流量调度与可观测性实践。