當入口網關服務使用externalTrafficPolicy: Local時,部分節點上的Pod能訪問CLB地址,而其他節點上的Pod無法訪問。本文介紹該問題的原因和解決方案。
問題現象
Service MeshASM已添加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已能夠訪問入口網關。