Degraded LB with K8S

1. Tổng Quan Vấn Đề

Khi Cloud Controller Manager (CCM) tích hợp giữa Kubernetes và nhà cung cấp dịch vụ đám mây, quá trình tạo một dịch vụ (Service) với kiểu LoadBalancer sẽ thực hiện việc thêm tất cả các worker (node) vào thành phần listener của LoadBalancer. Sau đó, LoadBalancer tiến hành kiểm tra tình trạng (health check) trên các endpoint được expose ra.

Tuy nhiên, việc chọn lựa node cũng như cấu hình thuộc tính externalTrafficPolicy của Service có ảnh hưởng đáng kể đến trạng thái của LoadBalancer. Cụ thể:

  • externalTrafficPolicy: Local:
    • Chỉ expose port trên các node đang chạy pod tương ứng.
    • Khi LoadBalancer thêm tất cả các node nhưng pod không được schedule trên tất cả các node, chỉ có một số ít node thực sự nhận được traffic và thực hiện health check thành công. Điều này dẫn đến tình trạng một số node được đánh dấu là unhealthy, làm cho trạng thái tổng thể của LoadBalancer trở nên “Degraded”.
  • externalTrafficPolicy: Cluster:
    • Expose port trên toàn bộ các node trong cluster.
    • Do đó, tất cả các node đều có thể tiếp nhận health check, dẫn đến việc toàn bộ các node đều được đánh dấu là healthy và trạng thái LoadBalancer được duy trì ổn định.

2. Ví Dụ Cấu Hình Dịch Vụ

Để minh họa rõ ràng hơn, dưới đây là ví dụ về hai dịch vụ với cấu hình khác nhau:

a) Dịch vụ nginx-service với externalTrafficPolicy là Local

apiVersion: v1
kind: Service
metadata:
  annotations:
    kubectl.kubernetes.io/last-applied-configuration: |
            {"apiVersion":"v1","kind":"Service","metadata":{"annotations":{},"labels":{"app":"nginx"},"name":"nginx-service","namespace":"default"},"spec":{"ports":[{"port":80,"protocol":"TCP","targetPort":80}],"selector":{"app":"nginx"},"type":"LoadBalancer"}}
  name: nginx-service
  namespace: default
spec:
  allocateLoadBalancerNodePorts: true
  clusterIP: 10.93.70.107
  **externalTrafficPolicy: Local**
  healthCheckNodePort: 32483
  internalTrafficPolicy: Cluster
  ports:
  - nodePort: 30860
    port: 80
    protocol: TCP
    targetPort: 80
  selector:
    app: nginx
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 123.31.39.43
      ipMode: VIP
      
    

Với cấu hình này, do chỉ những node chứa pod của nginx mới nhận được traffic, nên nếu các pod chỉ được schedule trên một vài node thay vì tất cả các node, các node không có pod sẽ không đáp ứng health check, dẫn đến trạng thái LoadBalancer bị đánh giá là “Degraded”.

b) Dịch vụ ingress-nginx-controller với externalTrafficPolicy là Cluster

apiVersion: v1
kind: Service
metadata:
  annotations:
    meta.helm.sh/release-name: ingress-nginx
    meta.helm.sh/release-namespace: ingress-nginx
  name: ingress-nginx-controller
  namespace: ingress-nginx
spec:
  allocateLoadBalancerNodePorts: true
  clusterIP: 10.93.161.16
  **externalTrafficPolicy: Cluster**
  internalTrafficPolicy: Cluster
  ports:
  - appProtocol: http
    name: http
    nodePort: 30351
    port: 80
    protocol: TCP
    targetPort: http
  - appProtocol: https
    name: https
    nodePort: 30141
    port: 443
    protocol: TCP
    targetPort: https
  selector:
    app.kubernetes.io/component: controller
    app.kubernetes.io/instance: ingress-nginx
    app.kubernetes.io/name: ingress-nginx
  sessionAffinity: None
  type: LoadBalancer
status:
  loadBalancer:
    ingress:
    - ip: 123.31.39.189
      ipMode: VIP

Với cấu hình này, do port được expose trên tất cả các node, các node đều có khả năng tiếp nhận health check, từ đó trạng thái của LoadBalancer luôn được đánh giá là “Healthy”.

3. Các Giải Pháp Để Duy Trì Trạng Thái Healthy Khi Sử Dụng externalTrafficPolicy: Local

Để có thể sử dụng externalTrafficPolicy: Local mà vẫn đảm bảo trạng thái LoadBalancer hiển thị “Healthy”, có thể áp dụng một trong các giải pháp sau:

  • Mở rộng số lượng node chứa pod:

    Đảm bảo rằng các pod của dịch vụ được schedule trên tất cả các node trong cluster. Tuy nhiên, phương án này có thể dẫn đến việc tiêu thụ tài nguyên không cần thiết khi phải scale cluster ra toàn bộ node.

  • Sử dụng annotation kubernetes.bizflycloud.vn/target-node-labels cho Service:

    Cấu hình thêm annotation này theo hướng dẫn tại tài liệu BizflyCloud để yêu cầu CCM chỉ lựa chọn những node có nhãn (label) được chỉ định khi thêm vào LoadBalancer. Đồng thời, điều chỉnh cấu hình scheduler để đảm bảo các pod được phân phối đều trên các node tương ứng với nhãn đã định, từ đó giúp duy trì trạng thái “Healthy” cho LoadBalancer.

Hình ảnh minh hoạ

image

image

image