如何解决Kubernetes集群中的Pod无法访问入口网关的CLB地址的问题?

更新时间:
复制 MD 格式

当入口网关服务使用externalTrafficPolicy: Local时,部分节点上的Pod能访问CLB地址,而其他节点上的Pod无法访问。本文介绍该问题的原因和解决方案。

问题现象

服务网格ASM已添加Kubernetes集群,并且使用Local类型的负载均衡CLB部署入口网关。当应用Pod访问入口网关暴露的CLB地址时,出现以下问题:

  • 部分节点上的Pod能访问入口网关暴露的CLB地址。

  • 部分节点上的Pod不能访问入口网关暴露的CLB地址。

问题诊断

在修复问题前,请先确认问题由externalTrafficPolicy: Local配置引起。

  1. 查看入口网关服务的externalTrafficPolicy设置。如果输出为Local,说明属于本文场景。

    kubectl get svc istio-ingressgateway -n istio-system -o jsonpath='{.spec.externalTrafficPolicy}'
  2. 列出运行入口网关Pod的节点,记录输出中的NODE列。

    kubectl get pods -n istio-system -l app=istio-ingressgateway -o wide
  3. 确认异常Pod所在的节点。如果异常Pod运行在步骤2输出中不存在的节点上,即可确认问题原因。

    kubectl get pod  -n  -o wide

问题原因

externalTrafficPolicy设置为Local时,kube-proxy会添加iptables(或IPVS)规则,这些规则仅将流量路由到本地节点上的端点(Endpoint)。以下流程展示kube-proxy如何处理集群内发起的、访问CLB地址的请求:

  1. PodCLB的外部IP地址发送请求。

  2. kube-proxy识别出该CLB地址是入口网关服务的外部IP地址,因此拦截该请求,而不是将其转发到CLB。

  3. kube-proxy在与发起请求的Pod相同的节点上查找入口网关端点。

  4. 如果该节点上存在入口网关Pod,kube-proxy会将请求转发给该Pod,请求成功。

  5. 如果该节点上不存在入口网关Pod,kube-proxy找不到本地端点,请求失败。

这是Kubernetes针对externalTrafficPolicy: Local的预期行为。更多信息,请参见iptables规则

解决方案

根据是否需要保留源IP地址以及集群使用的CNI插件,选择合适的解决方案。

解决方案

保留源IP地址

前提条件

配置变更

通过服务DNS名称访问

是(外部流量)

修改externalTrafficPolicyCluster

修改IstioGateway CRD

使用ENI直通

Terway CNIENI模式

修改IstioGateway CRD并添加Annotation

通过服务DNS名称访问(推荐)

在集群内部访问入口网关时,无需使用CLB的外部IP地址,可通过其ClusterIP或服务DNS名称访问。ClusterIP流量使用独立的kube-proxy转发路径,会转发到集群内所有端点,从而绕过externalTrafficPolicy: Local的限制。

集群内访问时使用以下服务DNS名称:

istio-ingressgateway.istio-system

例如,从Pod中发送请求:

curl http://istio-ingressgateway.istio-system
说明

该方法无需修改配置,适用于任何CNI插件,并且能够为通过CLB进入的外部流量保留源IP地址。

修改externalTrafficPolicyCluster

如果不需要保留源IP地址,可以将externalTrafficPolicy修改为Cluster。修改后,kube-proxy会将流量转发到任意节点上的入口网关Pod,而不仅限于本节点。

更新IstioGateway CRD(Custom Resource Definition,自定义资源定义):

apiVersion: istio.alibabacloud.com/v1beta1
kind: IstioGateway
metadata:
  name: ingressgateway
  namespace: istio-system
  ....
spec:
  externalTrafficPolicy: Cluster
....

关于CRD字段的更多信息,请参见ASM网关CRD说明

说明

使用externalTrafficPolicy: Cluster后,入站请求会经过源网络地址转换(SNAT),客户端源IP会被替换为节点的内部IP。如果应用依赖客户端源IP地址,请使用其他解决方案。

使用ENI直通

如果集群使用Terway的弹性网卡(ENI)或运行在ENIIP模式,可以将externalTrafficPolicy修改为Cluster,同时通过ENI直通保留源IP地址。

更新IstioGateway CRD,将externalTrafficPolicy设置为Cluster,并添加service.beta.kubernetes.io/backend-type: eniAnnotation:

apiVersion: istio.alibabacloud.com/v1beta1
kind: IstioGateway
metadata:
  name: ingressgateway
  namespace: istio-system
  ....
spec:
  externalTrafficPolicy: Cluster
  maxReplicas: 5
  minReplicas: 2
  ports:
    - name: status-port
      port: 15020
      targetPort: 15020
    - name: http2
      port: 80
      targetPort: 80
    - name: https
      port: 443
      targetPort: 443
    - name: tls
      port: 15443
      targetPort: 15443
  replicaCount: 2
  resources:
    limits:
      cpu: '2'
      memory: 2G
    requests:
      cpu: 200m
      memory: 256Mi
  runAsRoot: false
  serviceAnnotations:
    service.beta.kubernetes.io/backend-type: eni
  serviceType: LoadBalancer

关于CRD字段的更多信息,请参见ASM网关CRD说明

验证结果

应用所选解决方案后,验证此前无法访问的Pod是否能够访问入口网关:

kubectl exec  -n  -- curl -s -o /dev/null -w "%{http_code}" http://istio-ingressgateway.istio-system

返回200响应码(或其他有效的HTTP响应),说明Pod已能够访问入口网关。