在現代的微服務架構中,我們經常使用容器技術來封裝和運行應用程序。這種方法雖然使部署變得更加便捷和一致,但也帶來了資源管理的挑戰:如何有效地控制和分配執行應用程序所需的計算資源?這是一個需要仔細權衡的問題,因為資源分配不足可能導致服務性能下降或無法正常運行,而過度分配則會造成資源浪費和成本增加。
在 Kubernetes (K8s) 中,Resources
是用於管理和分配叢集資源的核心概念。這些資源主要包括 CPU 和記憶體(RAM),但也可能涉及其他計算資源如 GPU 或存儲空間。Kubernetes 提供了一套完整的機制來配置、監控和自動調整這些資源,以確保應用程序能夠高效穩定地運行。
當我們定義 Pod 時,可以為每個容器設定所需要的資源數量。最常見的資源是 CPU 和記憶體(RAM),也有其他類型的資源。
當你為 Pod 中的容器指定了 request(請求) 時,kube-scheduler 會根據這些資訊決定將 Pod 調度到哪個節點上。當你指定了 limit(限制) 時,kubelet 會確保容器不會使用超過這個限制的資源。kubelet 也會為容器預留 request(請求) 的資源,讓容器使用。
如果 Pod 運行的節點有足夠的可用資源,容器可以使用超過 request
設定的資源量,但不能使用超過 limit
設定的資源量。
例如:如果容器的 memory
請求是 256 MiB,且節點有足夠的記憶體(比如 8 GiB),那麼容器可以使用更多的記憶體。
如果我們將容器的 memory
限制設為 4 GiB,kubelet
和 Container Runtimes
會確保容器不會使用超過這個限制。如果容器中的程序嘗試使用超過允許的記憶體,系統核心會終止這些程序並引發記憶體不足(OOM)錯誤。
總結來說: request <= Pod/Container 實際使用的資源量 <= limit
CPU 資源用 millicpu 來表示,1000m 代表 1 個 CPU 核心。
範例:
cpu: "500m"
表示使用 0.5 個 CPU 核心。cpu: "1"
表示使用 1 個 CPU 核心。cpu: "2"
表示使用 2 個 CPU 核心。記憶體資源使用基於 2 的次方的單位,包括:
範例:
memory: "512Mi"
表示 512 兆字節(MiB)的記憶體。memory: "1Gi"
表示 1 千兆字節(GiB)的記憶體。memory: "2Gi"
表示 2 千兆字節(GiB)的記憶體。Kubernetes 會對每個 Pod 進行分類,並分配到特定的 QoS 類。這些分類影響 Pod 的處理方式,並基於容器的資源請求和資源限制來決定。這些分類稱為服務質量(QoS)類,Kubernetes 使用 QoS 類來決定當節點資源不足時,哪些 Pod 會被驅逐。
QoS 類型可以幫助決定 Pod 在節點資源不足時的優先級。QoS 類型有 Guaranteed
、Burstable
和 BestEffort
。當一個節點資源不足時,Kubernetes 會首先驅逐 BestEffort
類型的 Pod,接著是 Burstable
類型,最後才是 Guaranteed
類型。當驅逐是因為資源壓力時,只有超出資源請求的 Pod 才會被驅逐。
簡單來說,Pod 被驅逐的順序是: Guaranteed
< Burstable
< BestEffort
Guaranteed
的條件。Guaranteed
和 Burstable
的條件。BestEffort
類型。建立一個名字空間,以便將本練習所建立的資源與叢集的其餘資源相隔離。
kubectl create namespace qos-example
組態檔案: qos.yaml
apiVersion: v1
kind: Pod
metadata:
name: qos-demo
namespace: qos-example
spec:
containers:
- name: qos-demo-ctr
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "700m"
requests:
memory: "200Mi"
cpu: "700m"
---
apiVersion: v1
kind: Pod
metadata:
name: qos-demo-2
namespace: qos-example
spec:
containers:
- name: qos-demo-2-ctr
image: nginx
resources:
limits:
memory: "200Mi"
requests:
memory: "100Mi"
---
apiVersion: v1
kind: Pod
metadata:
name: qos-demo-3
namespace: qos-example
spec:
containers:
- name: qos-demo-3-ctr
image: nginx
---
apiVersion: v1
kind: Pod
metadata:
name: qos-demo-4
namespace: qos-example
spec:
containers:
- name: qos-demo-4-ctr-1
image: nginx
resources:
limits:
memory: "200Mi"
cpu: "700m"
requests:
memory: "200Mi"
cpu: "700m"
- name: qos-demo-4-ctr-2
image: redis
這個組態檔案裡,包含四個 Pod:
依照之前學過的內容,我們期望 Pod QoS 的結果是:
qos-demo=Guaranteed
qos-demo-2=Burstable
qos-demo-3=BestEffort
qos-demo-4=Burstable
驗證 qos 資訊
kubectl get pods --namespace=qos-example -o jsonpath='{range .items[*]}{.metadata.name}{"\t"}{.status.qosClass}{"\n"}{end}'
---
qos-demo Guaranteed
qos-demo-2 Burstable
qos-demo-3 BestEffort
qos-demo-4 Burstable
kubectl delete namespace qos-example
在本練習中,你將建立一個 Pod,該 Pod 的 CPU 請求對於叢集中任何節點的容量而言都會過大。 下面是 Pod 的組態檔案,其中有一個容器。容器請求 100 個 CPU,這可能會超出叢集中任何節點的容量。
建立一個名字空間,以便將本練習所建立的資源與叢集的其餘資源相隔離。
kubectl create namespace cpu-example
組態檔案: example.yaml
apiVersion: v1
kind: Pod
metadata:
name: cpu-demo-2
namespace: cpu-example
spec:
containers:
- name: cpu-demo-ctr-2
image: vish/stress
resources:
limits:
cpu: "100"
requests:
cpu: "100"
args:
- -cpus
- "2"
kubectl apply -f examply.yaml
kubectl -n cpu-example get pod cpu-demo
---
NAME READY STATUS RESTARTS AGE
cpu-demo 0/1 Pending 0 19s
輸出顯示 Pod 狀態為 Pending。也就是說,Pod 未被調度到任何節點上運行, 並且 Pod 將無限期地處於 Pending 狀態。
kubectl -n cpu-example describe pod cpu-demo
---
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 10s default-scheduler 0/3 nodes are available: 1 node(s) had untolerated taint {node-role.kubernetes.io/control-plane: }, 2 Insufficient cpu. preemption: 0/3 nodes are available: 1 Preemption is not helpful for scheduling, 2 No preemption victims found for incoming pod.
輸出顯示由於節點上的 CPU 資源不足,無法調度容器。
kubectl delete namespace cpu-example
Kubernetes 的資源管理機制為微服務架構提供了強大的支持。通過合理設置資源請求和限制,結合 QoS 類別,我們可以有效控制應用程序的資源使用,確保系統穩定性和資源利用效率。
然而,有效的資源管理不僅依賴於 Kubernetes 的機制,還需要深入理解應用程序的需求和行為。持續監控、分析和優化是確保資源管理效果的關鍵。