十個常見的 Kubernetes 陷阱和挑戰(zhàn)

Kubernetes 是最流行的容器編排和部署平臺。它的強大功能特性,可以保障在生產(chǎn)中可靠地運行容器化應(yīng)用程序。
然而,有靈活性的同時也帶來了復(fù)雜性,在本文中,我們將探討許多團隊遇到的 10個常見 Kubernetes 陷阱。能夠識別并避免這些挑戰(zhàn)將提高應(yīng)用程序的可擴展性、可靠性和安全性,同時讓你更好地控制集群及其部署。
1.使用 latest Tag 部署容器
可以說,Kubernetes 最常被違反的最佳實踐之一就是在部署容器時使用latest標簽。這將使我們面臨無意中接受重大變更的風(fēng)險,而這些變更可能影響系統(tǒng)穩(wěn)定性。
每個人使用 latest 標簽的方式各不相同,但大多數(shù)人都會將 latest 指向其項目的最新版本。例如,今天使用 helm:latest 將提供 Helm v3,但在v4版本發(fā)布后,重啟就會更新到v4,但是我們可能還認為系統(tǒng)運行的是 v3 版本,從而引發(fā)不可預(yù)知的風(fēng)險。
2.不使用Liveness和Readiness 探針
探針可以使我們的應(yīng)用程序更具彈性。它們會告知 Kubernetes Pod 的健康狀況。
當(dāng)容器出現(xiàn)問題時,比如內(nèi)存溢出,Liveness探針請求超時,那么Liveness探針會通知 Kubernetes 重啟容器。
有時候應(yīng)用會暫時性地?zé)o法為請求提供服務(wù)。例如,應(yīng)用在啟動時可能需要加載大量的數(shù)據(jù)或配置文件,或是啟動后要依賴等待外部服務(wù)。在這種情況下,既不想殺死應(yīng)用,也不想給它發(fā)送請求。Kubernetes 提供了Readiness探針來發(fā)現(xiàn)并緩解這些情況,容器所在 Pod 上報還未就緒的信息,并且不接受通過 Kubernetes Service 的流量。
下面是一個包含有效性和就緒性探針的簡單 Pod:
apiVersion: v1
kind: Pod
metadata:
name: probes-demo
spec:
containers:
- name: probes-demo
image: nginx:latest
livenessProbe:
httpGet:
path: /
port: 80
readinessProbe:
httpGet:
path: /
port: 80 3. 缺少節(jié)點選擇器導(dǎo)致調(diào)度效率低下
集群的整體性能取決于 Pod 是否被正確調(diào)度到合適的節(jié)點上。許多集群包含多種類型的節(jié)點,例如用于標準應(yīng)用程序的小型 2 CPU/4 GB節(jié)點和用于密集后端服務(wù)的較大8 CPU/16GB節(jié)點。
如果Pod無法可靠地調(diào)度到我們想要的節(jié)點池,那么集群利用率將會很低。例如即使有未充分利用的較小節(jié)點,也會強制創(chuàng)建不必要的新的較大節(jié)點,從而增加集群的成本。通過在節(jié)點上設(shè)置標簽,然后使用節(jié)點選擇器將每個 Pod 分配給兼容的節(jié)點來避免此問題:
apiVersion: v1
kind: Pod
metadata:
name: pod-node-selector-demo
spec:
containers:
- name: nginx
image: nginx:latest
nodeSelector:
node-class: 2c4g此 Pod 只會調(diào)度到設(shè)置了標簽的節(jié)點node-class: 2c4g
使用命令在匹配的節(jié)點上設(shè)置標簽:kubectl label

設(shè)置適當(dāng)?shù)恼{(diào)度規(guī)則將最大限度地提高節(jié)點利用率并保持穩(wěn)定的集群性能。
4.破壞 Pod 親和性/反親和性規(guī)則
Pod 親和性和反親和性規(guī)則允許指示 Kubernetes 哪個節(jié)點最適合部署Pod。規(guī)則可以以節(jié)點級特征(例如標簽)或已在節(jié)點上運行的其他 Pod 的特征為條件。
親和性規(guī)則將Pod吸引到 Node,使得 Pod 更有可能調(diào)度到特定Node上,而反親和性則具有排斥作用,降低了調(diào)度的概率。Kubernetes 會評估每個可用于調(diào)度的可能節(jié)點的 Pod 親和性規(guī)則,然后選擇最合適的一個。
親和力系統(tǒng)能夠支持復(fù)雜的調(diào)度行為,但也很容易錯誤配置親和力規(guī)則,Pod會意外地調(diào)度到不正確的節(jié)點,或者拒絕調(diào)度。
比如一個服務(wù)的兩個副本,應(yīng)該調(diào)度在兩個Node上,這樣如果一個 Node 節(jié)點發(fā)生故障時,可以保證服務(wù)的另一個副本可用,如果規(guī)則設(shè)置不正確都調(diào)度到一個Node 上那么會導(dǎo)致服務(wù)不可用。
5. 沒有監(jiān)控/記錄
當(dāng)在Kubernetes 中擴容應(yīng)用程序時,了解集群資源利用率、應(yīng)用程序錯誤和實時性能數(shù)據(jù)至關(guān)重要。內(nèi)存消耗激增、Pod 驅(qū)逐和容器崩潰都是我們應(yīng)該了解的問題,但標準 Kubernetes不具備任何可觀測性功能,以便在故障發(fā)生時發(fā)出告警。
要啟用對集群的監(jiān)控,我們應(yīng)該部署可觀測性平臺,例如 Prometheus、夜鶯。這會從 Kubernetes 收集指標,同時在Grafana查看相關(guān)數(shù)據(jù)指標。同時也有告警機制。
6. 標簽選擇器不匹配
部署和服務(wù)等對象依賴正確的標簽選擇器來識別 Pod 及其管理的其他對象。選擇器與實際分配給對象的標簽之間的不匹配將導(dǎo)致部署失敗。
示例:
apiVersion: apps/v1
kind: Deployment
metadata:
name: demo-deployment
spec:
replicas: 2
selector:
matchLabels:
app: nginx-demo-app
template:
metadata:
labels:
# Label does not match the deployment's selector!
app: nginx-demo-application
spec:
containers:
name: nginx-demo-app
image: nginx:latest以上文件部署會拋出selector does not match template labelsspec.selector.matchLabelsspec.template.metadata.labels要解決此問題,請調(diào)整清單的 和 字段,使它們具有相同的鍵值對
7. 服務(wù)端口不匹配
同樣,確保Service將流量路由到Pod上的正確端口也很重要。不正確的端口定義可能會使 Pod 看起來像是發(fā)生了故障,而實際上流量根本沒有到達該 Pod。
以下清單包含此問題的示例。該Service監(jiān)聽9000端口并將流量轉(zhuǎn)發(fā)到其 Pod上的8080端口 ,但容器實際上端口是80,所以流量無法到達。
apiVersion: v1
kind: Pod
metadata:
name: demo-pod
labels:
app: demo-app
spec:
image: nginx:latest
ports:
- containerPort: 80
---
apiVersion: v1
kind: Service
metadata:
name: demo-service
spec:
ports:
- port: 9000
protocol: TCP
targetPort: 8080
selector:
app: demo-app8. 意外部署到錯誤的命名空間
Kubernetes命名空間將一組服務(wù)邏輯分組在一起,在集群中提供一定程度的隔離。為每個團隊、應(yīng)用和環(huán)境創(chuàng)建命名空間可以防止名稱沖突并簡化管理體驗。
使用命名空間時,請記住為每個服務(wù)和Kubectl命令指定目標命名空間。否則,將使用默認命名空間default。如果服務(wù)沒有部署在合適的命名空間下,會導(dǎo)致相關(guān)服務(wù)器請求不可達。
以下清單為Istio Ingress轉(zhuǎn)發(fā)配置,此文件部署在seg空間下,然后根據(jù)/dp-manager請求,轉(zhuǎn)發(fā)到seg空間下的dp-manager-backend服務(wù),如果dp-manager-backend不在 seg空間下,那么會導(dǎo)致請求異常。
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: dp-manager-vs
namespace: seg
spec:
gateways:
- dp-manager-gateway
hosts:
- control-dpmanager.test.com
http:
- match:
- uri:
prefix: /dp-manager
route:
- destination:
host: dp-manager-backend
port:
number: 80
9. 沒有資源請求和限制的 Pod
正確的資源管理對于保持集群的穩(wěn)定性至關(guān)重要。Pod默認沒有任何資源限制,除非我們對其進行配置,因此這可能會導(dǎo)致Node節(jié)點CPU 和內(nèi)存耗盡。
在所有 Pod 上設(shè)置適當(dāng)?shù)馁Y源請求和限制以減少資源爭用。請求Kubernetes為我們的 Pod 預(yù)留特定數(shù)量的資源,防止其調(diào)度到無法提供足夠容量的節(jié)點上。Limits設(shè)置Pod可以使用的最大資源量;超過 CPU 限制的 Pod 將受到限制,而達到內(nèi)存限制則會提示內(nèi)存不足 (OOM) 從而終止 Pod 允許。
請求和限制在 Pod 清單的 字段中定義:spec.container.resources
apiVersion: v1
kind: Pod
metadata:
name: demo-pod
spec:
containers:
- name: demo-container
image: nginx:latest
resources:
requests:
cpu: 100m
memory: 1Gi
limits:
memory: 2Gi以上Pod 請求100m(1000m等于1核)CPU 時間和 1Gi 內(nèi)存。它只會調(diào)度到可以提供足夠資源的節(jié)點上。Pod 還設(shè)置了內(nèi)存限制,最大可以申請2Gi 內(nèi)存。最佳實踐是將 Pod 的內(nèi)存限制設(shè)置為等于其請求。通常不需要 CPU 限制,因為 Kubernetes 會按比例限制超出其請求的 Pod。
10. 集群自動擴容錯誤
選擇Kubernetes原因之一就是它的彈性擴容。正確配置可以使Kubernetes在需求高峰時自動添加新的 Pod 和節(jié)點,從而動態(tài)的水平和垂直擴容。但是不幸的是,很多團隊它們的自動擴容是不可預(yù)測的。
因此定期檢查集群的利用率,以檢查它是否仍然適合您的工作負載。使用負載測試工具(例如Locust)測試自動擴縮規(guī)則,將多余的流量引導(dǎo)至集群。這可以使我們更早地發(fā)現(xiàn)問題,確保Pod 在實際流量到達時能夠無縫擴容。

































