当入口网关服务使用externalTrafficPolicy: Local时,部分节点上的Pod能访问CLB地址,而其他节点上的Pod无法访问。本文介绍该问题的原因和解决方案。
问题现象
服务网格ASM已添加Kubernetes集群,并且使用Local类型的负载均衡CLB部署入口网关。当应用Pod访问入口网关暴露的CLB地址时,出现以下问题:
-
部分节点上的Pod能访问入口网关暴露的CLB地址。
-
部分节点上的Pod不能访问入口网关暴露的CLB地址。
问题诊断
在修复问题前,请先确认问题由externalTrafficPolicy: Local配置引起。
-
查看入口网关服务的
externalTrafficPolicy设置。如果输出为Local,说明属于本文场景。kubectl get svc istio-ingressgateway -n istio-system -o jsonpath='{.spec.externalTrafficPolicy}' -
列出运行入口网关Pod的节点,记录输出中的
NODE列。kubectl get pods -n istio-system -l app=istio-ingressgateway -o wide -
确认异常Pod所在的节点。如果异常Pod运行在步骤2输出中不存在的节点上,即可确认问题原因。
kubectl get pod-n -o wide
问题原因
当externalTrafficPolicy设置为Local时,kube-proxy会添加iptables(或IPVS)规则,这些规则仅将流量路由到本地节点上的端点(Endpoint)。以下流程展示kube-proxy如何处理集群内发起的、访问CLB地址的请求:
-
Pod向CLB的外部IP地址发送请求。
-
kube-proxy识别出该CLB地址是入口网关服务的外部IP地址,因此拦截该请求,而不是将其转发到CLB。
-
kube-proxy在与发起请求的Pod相同的节点上查找入口网关端点。
-
如果该节点上存在入口网关Pod,kube-proxy会将请求转发给该Pod,请求成功。
-
如果该节点上不存在入口网关Pod,kube-proxy找不到本地端点,请求失败。
这是Kubernetes针对externalTrafficPolicy: Local的预期行为。更多信息,请参见iptables规则。
解决方案
根据是否需要保留源IP地址以及集群使用的CNI插件,选择合适的解决方案。
|
解决方案 |
保留源IP地址 |
前提条件 |
配置变更 |
|
通过服务DNS名称访问 |
是(外部流量) |
无 |
无 |
|
修改externalTrafficPolicy为Cluster |
否 |
无 |
修改IstioGateway CRD |
|
使用ENI直通 |
是 |
Terway CNI的ENI模式 |
修改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地址。
修改externalTrafficPolicy为Cluster
如果不需要保留源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)或运行在ENI多IP模式,可以将externalTrafficPolicy修改为Cluster,同时通过ENI直通保留源IP地址。
更新IstioGateway CRD,将externalTrafficPolicy设置为Cluster,并添加service.beta.kubernetes.io/backend-type: eni的Annotation:
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已能够访问入口网关。