GCP-LB 将流量分配到 HAProxy Ingress Controller Pods

GCP-LB unevenly distributing traffic to HAProxy Ingress Controller Pods

如标题所示,GCP-LB 或公开为 LoadBalancer 类型的 HAProxy Ingress Controller 服务正在不均匀地将流量分配给 HAProxy Ingress Controller Pods。

设置:
我是 运行 GCP 中的 GKE 集群,使用 HAProxy 作为入口控制器。
HAProxy 服务公开为具有静态 IP 的负载均衡器类型。

用于 HAProxy 服务的 YAML:

apiVersion: v1
kind: Service
metadata:
  name: haproxy-ingress-static-ip
  namespace: haproxy-controller
  labels:
    run: haproxy-ingress-static-ip
  annotations:
    cloud.google.com/load-balancer-type: "Internal"
    networking.gke.io/internal-load-balancer-allow-global-access: "true"
    cloud.google.com/network-tier: "Premium"
    cloud.google.com/neg: '{"ingress": false}'
spec:
  selector:
    run: haproxy-ingress
  ports:
  - name: http
    port: 80
    protocol: TCP
    targetPort: 80
  - name: https
    port: 443
    protocol: TCP
    targetPort: 443
  - name: stat
    port: 1024
    protocol: TCP
    targetPort: 1024
  type: LoadBalancer
  loadBalancerIP: "10.0.0.76"                                                                                                                                      

用于 HAProxy 部署的 YAML:

---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    run: haproxy-ingress
  name: haproxy-ingress
  namespace: haproxy-controller
spec:
  replicas: 2
  selector:
    matchLabels:
      run: haproxy-ingress
  template:
    metadata:
      labels:
        run: haproxy-ingress 
    spec:
      serviceAccountName: haproxy-ingress-service-account
      containers:
      - name: haproxy-ingress
        image: haproxytech/kubernetes-ingress
        args:
          - --configmap=haproxy-controller/haproxy
          - --default-backend-service=haproxy-controller/ingress-default-backend
        ports:
        - name: http
          containerPort: 80
        - name: https
          containerPort: 443
        - name: stat
          containerPort: 1024
        env:
        - name: POD_NAME
          valueFrom:
            fieldRef:
              fieldPath: metadata.name
        - name: POD_NAMESPACE
          valueFrom:
            fieldRef:
              fieldPath: metadata.namespace
      affinity:
        podAntiAffinity:
          preferredDuringSchedulingIgnoredDuringExecution:
            - weight: 100
              podAffinityTerm:
                labelSelector:
                  matchExpressions:
                    - key: run
                      operator: In
                      values: 
                        - haproxy-ingress
                topologyKey: kubernetes.io/hostname

HAProxy 配置图:

---
apiVersion: v1
kind: ConfigMap
metadata:
  name: haproxy
  namespace: haproxy-controller
data:

问题:
在调试其他问题时,我发现 HAProxy pods 上的流量分布不均。例如一个 Pods 正在接收 540k requests/sec 而另一个 Pod 正在接收 80k requests/sec。

进一步调查还发现,启动的新 Pods 在接下来的 20-30 分钟内不会开始接收流量。即使在那之后,也只有一小部分流量通过它们。

查看下图:

另一种流量分配不均的版本。这似乎根本不是随机的,看起来像是加权流量分布:

流量分布不均的另一种形式。来自一个 Pod 的流量似乎正在转移到另一个 Pod。

是什么原因导致这种流量分布不均并且长时间不向新 pods 发送流量?

Kubernetes 与 GCP 负载均衡器集成。 K8s 为用户提供入口和服务等原语,以通过 L4/L7 负载均衡器公开 pods。在引入 NEG 之前,负载均衡器将流量分配到 VM 实例和“kube-proxy”程序 iptables 以将流量转发到后端 pods。这可能会导致流量分配不均、负载均衡器运行状况检查不可靠以及网络性能受到影响。

我建议您使用 Container native load balancing,它允许负载均衡器直接以 Kubernetes Pods 为目标,并将流量平均分配到 Pods。使用容器原生负载均衡,负载均衡器流量直接分配到应该接收流量的 Pods,从而消除了额外的网络跃点。它还有助于改进健康检查,因为它直接针对 Pods,您可以看到从 HTTP(S) 负载平衡器到 Pods 的延迟。从 HTTP(S) 负载均衡器到每个 Pod 的延迟是可见的,这是与基于节点 IP 的容器原生负载均衡聚合的。这使得在 NEG 级别对您的服务进行故障排除变得更加容易。

容器原生负载均衡器不支持内部 TCP/UDP 负载均衡器或网络负载均衡器,所以如果你想使用这种负载均衡,你必须将服务拆分为 HTTP(80), HTTPS(443) 和 TCP(1024)。要使用它,您的集群必须启用 HTTP 负载平衡。 GKE 集群默认启用 HTTP 负载均衡;你不能禁用它。