本文匯總了使用容器服務ACK Service時的一些常見問題。包括但不限于為什么集群內無法訪問SLB IP、為什么復用已有SLB沒有生效、CCM升級失敗如何處理等問題的解決方案。
索引
SLB相關
使用已有SLB常見問題
其他
SLB相關
ACK集群中SLB實例的具體用途
如果創建Kubernetes集群時安裝了Nginx Ingress組件,那么集群會默認自動創建兩個SLB實例。
兩個SLB實例的用途說明如下:
APIServer SLB:該SLB實例為API Server的訪問入口,訪問集群均需要與該SLB實例通信。監聽端口為6443,監聽協議為TCP。后端節點為APIServer Pod或者Master ECS。
Nginx Ingress Controller SLB:該SLB實例與kube-system命名空間下的
nginx-ingress-controller
服務關聯,虛擬服務器組會動態綁定Nginx Ingress Controller Pod,實現對外部請求的負載均衡和路由轉發。監聽端口為80和443,監聽協議為TCP。
更多信息,請參見ACK集群中SLB實例的具體用途。
創建Service時,Local和Cluster兩種外部流量策略如何選擇?
不同網絡插件,Local和Cluster兩種外部流量策略的功能不同。關于Local和Cluster兩種外部流量策略的詳細區別,請參見外部流量策略Local和Cluster介紹。
為什么看不到Service與LoadBalancer同步過程的事件Event信息?
如果執行命令kubectl -n {your-namespace} describe svc {your-svc-name}
后看不到Event信息的話,請確認您的CCM組件版本。
SLB創建一直處于Pending狀態如何處理?
執行命令
kubectl -n {your-namespace} describe svc {your-svc-name}
查看事件信息。處理事件中的報錯信息。關于事件中不同報錯信息的處理方式,請參見報錯事件及對應處理方式。
如果看不到報錯信息,請參見為什么看不到Service與LoadBalancer同步過程的事件Event信息?。
SLB虛擬服務器組未更新如何處理?
執行命令
kubectl -n {your-namespace} describe svc {your-svc-name}
查看事件信息。處理事件中的報錯信息。關于事件中不同報錯信息的處理方式,請參見報錯事件及對應處理方式。
如果看不到報錯信息,請參見為什么看不到Service與LoadBalancer同步過程的事件Event信息?。
Service注解不生效如何處理?
按照以下步驟查看報錯信息。
執行命令
kubectl -n {your-namespace} describe svc {your-svc-name}
查看事件信息。處理事件中的報錯信息。關于事件中不同報錯信息的處理方式,請參見報錯事件及對應處理方式。
如果沒有報錯信息,分以下三種場景解決:
確認您的CCM版本是否符合對應注解的版本要求。關于注解和CCM的版本對應關系,請參見通過Annotation配置傳統型負載均衡CLB。
登錄容器服務管理控制臺,在服務頁面,單擊目標服務的服務名稱,確認服務Service中是否有對應的注解。如果沒有對應的注解,配置注解信息。
關于如何配置注解,請參見通過Annotation配置傳統型負載均衡CLB。
關于如何查看服務列表,請參見Service快速入門。
確認注解信息是否有誤。
為何SLB的配置被修改?
CCM使用聲明式API,會在一定條件下根據Service的配置自動更新SLB配置。您自行在SLB控制臺上修改的配置均存在被覆蓋的風險。建議您通過注解的方式配置SLB。關于注解配置方式的更多信息,請參見通過Annotation配置傳統型負載均衡CLB。
請勿在SLB控制臺上手動修改Kubernetes創建并維護的SLB的任何配置,否則有配置丟失的風險,造成Service不可訪問。
為什么集群內無法訪問SLB IP?
場景一:設置SLB IP為私網地址,并且沒有通過Service方式創建SLB,那么SLB后端Pod和訪問SLB Pod將在同一個節點,導致在集群內訪問SLB IP失敗。
對于四層負載均衡服務,目前不支持負載均衡后端ECS實例直接為客戶端提供服務的同時,又作為負載均衡的后端服務器。因此在集群內訪問SLB IP會失敗。您可以通過以下方式解決該問題,從而避免訪問端和目的端在同一個節點。
將SLB IP修改為公網地址。
使用Service的方式創建SLB,同時設置外部流量策略為Cluster,這種情況下kube-proxy會劫持集群內訪問SLB流量,繞過SLB本身限制。
場景二:使用Service發布服務時,設置了外部流量策略為Local,導致在集群內訪問SLB IP失敗。
關于該問題的詳細原因和解決方案,請參見如何解決Kubernetes集群中訪問LoadBalancer暴露出去的SLB地址不通?。
如何解決Kubernetes集群中訪問LoadBalancer暴露出去的SLB地址不通?
問題描述
在Kubernetes集群中,有部分節點能夠訪問集群暴露出去的Local類型的SLB,但是也有部分節點不能訪問,且Ingress出現該問題較多。
問題原因
SLB設置了externalTrafficPolicy: Local
類型,這種類型的SLB地址只有在Node中部署了對應的后端Pod,才能被訪問。因為SLB的地址是集群外使用,如果集群的節點和Pod不能直接訪問,請求不會發送到SLB,會被當作Service的擴展IP地址,被kube-proxy的iptables或ipvs轉發。
如果剛好集群節點或者Pod所在的節點上沒有相應的后端服務Pod,就會發生網絡不通的問題,而如果有相應的后端服務Pod,是可以正常訪問的。相關問題的更多信息請參見kube-proxy將external-lb的地址添加到節點本地iptables規則。
解決方案
可以參見以下方法解決問題,推薦您使用第一種方法:
在Kubernetes集群內通過ClusterIP或者服務名訪問內部服務。其中Ingress的服務名為:
nginx-ingress-lb.kube-system
。將LoadBalancer的Service中的externalTrafficPolicy修改為Cluster。這種方式雖然可以確保流量能夠被轉發到所有節點上的Pod,但會導致源IP地址丟失,因為集群會執行SNAT(源網絡地址轉換)。這意味著后端應用無法獲取到客戶端的真實IP地址。Ingress的服務修改命令如下:
kubectl edit svc nginx-ingress-lb -n kube-system
若是Terway的ENI或者ENI多IP的集群,將LoadBalancer的Service中的externalTrafficPolicy修改為Cluster,并且添加ENI直通的Annotation,例如
annotation: service.beta.kubernetes.io/backend-type:"eni"
,具體格式如下,可以保留源IP,并且在集群內訪問也沒有問題。詳細信息,請參見通過Annotation配置傳統型負載均衡CLB。apiVersion: v1 kind: Service metadata: annotations: service.beta.kubernetes.io/backend-type: eni labels: app: nginx-ingress-lb name: nginx-ingress-lb namespace: kube-system spec: externalTrafficPolicy: Cluster
什么情況下會自動刪除SLB?
自動刪除SLB的策略取決于SLB是否由CCM自動創建。刪除策略如下表所示。
Service操作 | CCM自動創建的SLB | 復用的已有SLB |
刪除Service | 刪除SLB | 保留SLB |
修改LoadBalancer型Service為其他類型 | 刪除SLB | 保留SLB |
刪除Service是否會刪除SLB?
如果是復用已有SLB(Service中有service.beta.kubernetes.io/alibaba-cloud-loadbalancer-id: {your-slb-id}
注解),刪除Service時不會刪除SLB;否則刪除Service時會刪除對應的SLB。
如果您更改Service類型(例如從LoadBalancer改為NodePort)也會刪除對應的CCM自動創建的SLB。
誤刪除SLB怎么辦?
場景一:誤刪除API Server SLB如何處理?
無法恢復,您需要重建集群。具體操作,請參見創建ACK Pro版集群。
場景二:誤刪除Ingress SLB如何處理?
按照以下步驟重新創建SLB。
登錄容器服務管理控制臺,在左側導航欄選擇集群。
在集群列表頁面,單擊目標集群名稱,然后在左側導航欄,選擇
。在服務頁面頂部的命名空間下拉列表中,單擊kube-system,然后在服務列表中,找到目標服務nginx-ingress-lb,然后單擊目標服務。
如果沒有nginx-ingress-lb,請在當前頁面右上角單擊使用YAML創建資源,使用以下模板創建名為nginx-ingress-lb的Service。
apiVersion: v1 kind: Service metadata: labels: app: nginx-ingress-lb name: nginx-ingress-lb namespace: kube-system spec: externalTrafficPolicy: Local ports: - name: http port: 80 protocol: TCP targetPort: 80 - name: https port: 443 protocol: TCP targetPort: 443 selector: app: ingress-nginx type: LoadBalancer
在目標服務的操作列,單擊YAML編輯,移除status內容后,然后單擊更新以讓CCM重新構建SLB。
場景三:誤刪除業務相關的SLB如何處理?
如果不需要SLB對應的Service,刪除Service。
如果對應的Service還需要使用,解決方法如下。
登錄容器服務管理控制臺,在左側導航欄選擇集群。
在集群列表頁面,單擊目標集群名稱,然后在左側導航欄,選擇
。在服務頁面頂部的命名空間下拉框中,單擊所有命名空間,然后在服務列表中,找到業務Service。
在目標服務的操作列,單擊YAML編輯,移除status內容后,然后單擊更新以讓CCM重新構建SLB。
舊版本CCM如何支持SLB重命名?
Cloud Controller Manager組件V1.9.3.10后續版本創建的SLB支持自動打TAG從而可以重命名,而V1.9.3.10及之前的版本,您需要手動給該SLB打上一個特定的TAG從而支持SLB重命名。
只有Cloud Controller Manager組件V1.9.3.10及之前版本創建的SLB才需要手動打TAG的方式來支持重命名。
Service類型為LoadBalancer。
登錄到Kubernetes集群Master節點,請參見獲取集群KubeConfig并通過kubectl工具連接集群。
執行
kubectl get svc -n ${namespace} ${service}
命令,查看該Service類型及IP。說明您需要將namespace與service替換為所選集群的命名空間及服務名稱。
執行以下命令,生成該SLB所需要的Tag。
kubectl get svc -n ${namespace} ${service} -o jsonpath="{.metadata.uid}"|awk -F "-" '{print "kubernetes.do.not.delete: "substr("a"$1$2$3$4$5,1,32)}'
登錄負載均衡控制臺根據步驟2中所獲取的IP,在其所在的地域搜索到該SLB。
根據步驟3生成的Key值和Value值(分別對應上圖的1和2),為該SLB打上一個Tag。具體操作,請參見管理標簽。
Local模式下如何自動設置Node權重?
本文以業務Pod(app=nginx)部署在三臺ECS上,通過Service A對外提供服務為例,說明在Local模式下Node權重的計算方式。
V1.9.3.276-g372aa98-aliyun及之后版本
權重計算方式因為計算精度問題,Pod間還會存在輕微的負載不均。在V1.9.3.276-g372aa98-aliyun及之后版本,CCM將Node上部署的Pod數量設置為Node權重,如下圖所示,三臺ECS的權重分別為1、2、3,流量會按照1:2:3的比例分配給三臺ECS,Pod負載會更加均衡。
計算公式如下所示:
V1.9.3.164-g2105d2e-aliyun之后及V1.9.3.276-g372aa98-aliyun之前版本
如圖所示,在V1.9.3.164-g2105d2e-aliyun之后及V1.9.3.276-g372aa98-aliyun之前版本,CCM會根據Node上部署的Pod數量計算Node權重。經計算三臺ECS權重分別為16、33、50,因此流量將大致按照1:2:3的比例分配給三臺ECS,Pod負載更加均衡。
計算公式如下所示:
V1.9.3.164-g2105d2e-aliyun之前版本
如下圖所示,在V1.9.3.164-g2105d2e-aliyun之前的版本中,Local模式的Service其所有后端權重均為100,即所有流量平均分配到這三臺ECS上,造成ECS 1上Pod負載較重而ECS 3上的Pod負載較輕,導致Pod負載不均衡。
如何查詢集群中所有SLB的IP、名稱及類型?
執行如下命令,獲取所有命名空間中每個LoadBalancer類型服務的名稱、IP地址和地址類型信息。
kubectl get services -A -ojson | jq '.items[] | select(.spec.type == "LoadBalancer") | {name: .metadata.name, namespace: .metadata.namespace, ip: .status.loadBalancer.ingress[0].ip, lb_type: .metadata.annotations."service.beta.kubernetes.io/alibaba-cloud-loadbalancer-address-type"}'
預期輸出如下:
{ "name": "test", "namespace": "default", "ip": "192.168.*.*", "lb_type": "intranet" } { "name": "nginx-ingress-lb", "namespace": "kube-system", "ip": "47.97.*.*", "lb_type": "null" }
LoadBalancer類型的Service更替后端時,如何確保LB能夠優雅中斷已有連接?
您可以通過Annotation service.beta.kubernetes.io/alibaba-cloud-loadbalancer-connection-drain和service.beta.kubernetes.io/alibaba-cloud-loadbalancer-connection-drain-timeout配置優雅中斷。從Service移除后端后,LB依然會在drain-timeout期間內保持存量連接的處理。詳細信息,請參見為監聽設置連接優雅中斷。
使用已有SLB常見問題
為什么復用已有SLB沒有生效?
排查CCM版本,低于v1.9.3.105-gfd4e547-aliyun的CCM版本不支持復用。關于如何查看及升級CCM版本的操作,請參見升級CCM組件。
確認復用的SLB是否為集群創建的,不支持復用集群創建的SLB。
確認SLB是否為API Server的SLB,不支持復用API Server的SLB。
如果是私網SLB,請確認SLB是否和集群在同一個VPC中,不支持跨VPC復用SLB。
為什么復用已有SLB時沒有配置監聽?
確認是否在注解中配置了service.beta.kubernetes.io/alibaba-cloud-loadbalancer-force-override-listeners
為"true"
。如果沒有配置,則不會自動創建監聽。
復用已有的負載均衡默認不會覆蓋已有的監聽,有以下兩點原因:
如果已有負載均衡的監聽上綁定了業務,強制覆蓋可能會引發業務中斷。
由于CCM目前支持的后端配置有限,無法處理一些復雜配置。如有復雜的后端配置需求,可以在不覆蓋監聽的情況下,通過控制臺自行配置監聽。
考慮到以上兩種情況,不建議您強制覆蓋監聽。如果已有負載均衡的監聽端口不再使用,則可以強制覆蓋。
其他
CCM升級失敗如何處理?
關于CCM組件升級失敗的解決方案,請參見Cloud Controller Manager(CCM)組件升級檢查失敗。
Service報錯信息及對應處理方式
不同報錯信息的解決方法如下表所示。
報錯信息 | 說明及解決方法 |
| 指CLB的后端服務器配額不足。 解決方案:您可以采取以下方式,優化配額消耗。
|
| 共享型CLB不支持ENI。 解決方案:如果CLB后端使用的是ENI,您需要選擇性能保障型CLB實例。在Service中添加注解 重要 添加注解需要注意是否符合CCM的版本要求。關于注解和CCM的版本對應關系,請參見通過Annotation配置傳統型負載均衡CLB。 |
| CLB無后端服務器,請確認Service是否已關聯Pod且Pod正常運行。 |
| 無法根據Service關聯CLB。 解決方案:登錄負載均衡管理控制臺,根據Service的
|
| 賬號欠費。 |
| 賬號余額少于100元,請充值。 |
| CLB OpenAPI限流。 解決方案:
|
| 無法刪除虛擬服務器組關聯的監聽。 解決方案:
|
| 復用內網CLB時,該CLB和集群不在同一個VPC內。 解決方案:請確保您的CLB和集群在同一個VPC內。 |
| 虛擬交換機不足。 解決方案:通過 |
| 虛擬交換機不存在。 解決方案:
|
| ENI模式不支持String類型的 解決方案:將Service YAML中的 |
| 低版本CCM默認創建共享型CLB,但該類型CLB已停止售賣。 解決方案:升級CCM組件。 |
| CLB資源組一旦創建后不支持修改。 解決方案:移除Service中的注解 |
| 無法在VPC內找到指定的ENI IP。 解決方案:確認Service中是否配置了注解 |
| CLB計費類型不支持從按量付費轉為按規格收費。 解決方案:
|
| 復用了CCM創建的CLB。 解決方案:
|
| CLB的類型一旦創建后不可更改,創建Service后更改了CLB的類型會導致該報錯。 解決方案:刪除重建Service。 |
| Service已經綁定一個CLB,不能再綁定另一個CLB。 解決方案:不支持通過更改 |
當Service類型為NodePort時,如何為Service配置監聽?
CCM僅支持為LoadBalancer的Service配置監聽。您需要將Service類型從NodePort修改為LoadBalancer。
如何訪問NodePort類型的Service?
如果在集群內(集群節點內)訪問,您可以使用ClusterIP+Port,或者節點IP+Service中NodePort端口訪問Service。默認的NodePort端口會大于30000。
如果在集群外(集群節點外)訪問,您可以使用節點IP+Service中NodePort端口訪問Service。默認的NodePort端口會大于30000。
如果在VPC外部(其他VPC或者公網)訪問,您需要發布LoadBalancer類型的Service,然后通過Service的外部端點訪問Service。
說明如果您的Service設置了外部流量轉發策略為本地,請確保被訪問的節點上存在Service后端Pod。關于更多外部流量策略,請參見外部流量策略Local和Cluster介紹。
如何正確配置NodePort范圍?
在Kubernetes中,APIServer提供了ServiceNodePortRange參數(命令行參數 --service-node-port-range
),該參數是用于限制NodePort或LoadBalancer類型的Service在節點上所監聽的NodePort端口范圍,該參數默認值為30000~32767。在ACK Pro集群中,您可以通過自定義Pro集群的管控面參數修改該端口范圍。具體操作,請參見自定義ACK Pro集群的管控面參數。
您在修改NodePort端口范圍時必須十分謹慎。務必保證NodePort端口范圍與集群節點上Linux內核提供的
net.ipv4.ip_local_port_range
參數中的端口范圍不沖突。該內核參數ip_local_port_range
控制了Linux系統上任意應用程序可以使用的本地端口號范圍。ip_local_port_range
的默認值為32768~60999。您所創建的ACK集群在默認配置情況下,ServiceNodePortRange參數和
ip_local_port_range
參數不會產生沖突。如果您此前為了提升端口數量限制調整了這兩個參數中任意一個,導致兩者范圍出現重合,則可能會產生節點上的偶發網絡異常,嚴重時會導致業務健康檢查失敗、集群節點離線等。建議您恢復默認值或同時調整兩個端口范圍到完全不重合。調整端口范圍后,集群中可能存在部分NodePort或LoadBalancer類型的Service仍在使用
ip_local_port_range
參數端口范圍內的端口作為NodePort。此時您需要對這部分Service進行重新配置以避免沖突,可通過kubectl edit <service-name>
的方式直接將spec.ports.nodePort
字段的值更改為未被占用的NodePort。