當您指定一個 Pod 時,您可以選擇性地指定一個 容器 需要多少的資源。最常指定的資源是 CPU 和記憶體 (RAM);還有其他資源類型。
當您為 Pod 中的容器指定資源「請求 (request)」時,kube-scheduler 會利用此資訊來決定將 Pod 放在哪個節點上。當您為容器指定資源「限制 (limit)」時,kubelet 會強制執行這些限制,以確保執行中的容器不會使用超過您設定的資源限制。kubelet 也會為該容器專門保留至少「請求 (request)」量的系統資源以供使用。
如果 Pod 執行所在的節點有足夠的可用資源,容器可以使用超過其針對該資源所指定之 `request` 量的資源,這是可能且允許的。
例如,如果您為容器設定 256 MiB 的 `memory` 請求,且該容器位於排程到一個具有 8GiB 記憶體且沒有其他 Pod 的節點上,那麼該容器可以嘗試使用更多的 RAM。
限制則不同。`cpu` 和 `memory` 限制都由 kubelet(和 容器執行時期)應用,並最終由核心強制執行。在 Linux 節點上,Linux 核心透過 cgroups 強制執行限制。`cpu` 和 `memory` 限制的強制執行行為略有不同。
`cpu` 限制透過 CPU 節流來強制執行。當容器接近其 `cpu` 限制時,核心將根據容器的限制來限制其對 CPU 的存取。因此,`cpu` 限制是核心強制執行的硬性限制。容器不得使用超過其 `cpu` 限制中指定的 CPU 量。
`memory` 限制透過核心的記憶體不足 (OOM) 終止機制來強制執行。當容器使用超過其 `memory` 限制時,核心可能會終止它。然而,終止只會在核心偵測到記憶體壓力時發生。因此,過度分配記憶體的容器可能不會立即被終止。這表示 `memory` 限制是反應性地強制執行的。容器可能會使用超過其 `memory` 限制的記憶體,但如果這樣做,它可能會被終止。
「資源類型 (resource type)」具有一個基本單位,可以被請求、限制或兩者兼有。Kubernetes 具有以下內建資源類型
| 資源類型 | 描述 | 基本單位 |
|---|---|---|
cpu | 計算處理 | cpu (核心) |
memory | RAM | 位元組 (Bytes) |
ephemeral-storage | 本地臨時儲存 | 位元組 (Bytes) |
hugepages-<size> | 大頁面 (僅限 Linux) | 位元組 (Bytes) |
叢集還可以提供擴充資源 (帶有自訂名稱的資源,通常由裝置外掛程式公開)。
對於 Linux 工作負載,您可以指定「大頁面 (huge page)」資源。大頁面是 Linux 特有的功能,其中節點核心分配的記憶體區塊遠大於預設頁面大小。
例如,在預設頁面大小為 4KiB 的系統上,您可以指定一個限制,`hugepages-2Mi: 80Mi`。如果容器嘗試分配超過 40 個 2MiB 的大頁面 (總計 80 MiB),該分配將會失敗。
CPU 和記憶體統稱為「計算資源 (compute resources)」或「資源 (resources)」。計算資源是可測量的數量,可以被請求、分配和使用。它們不同於 API 資源。API 資源,例如 Pods 和 Services,是透過 Kubernetes API 伺服器讀取和修改的物件。
對於每個容器,您可以指定資源限制和請求,包括以下內容
spec.containers[].resources.limits.cpuspec.containers[].resources.limits.memoryspec.containers[].resources.limits.ephemeral-storagespec.containers[].resources.limits.hugepages-<size>spec.containers[].resources.requests.cpuspec.containers[].resources.requests.memoryspec.containers[].resources.requests.ephemeral-storagespec.containers[].resources.requests.hugepages-<size>儘管您只能為單個容器指定請求和限制,但考量 Pod 的整體資源請求和限制也很有用。對於特定資源,「Pod 資源請求/限制」是 Pod 中每個容器該類型資源請求/限制的總和。
Kubernetes v1.34 [beta] (預設啟用)如果您的叢集已啟用 `PodLevelResources` 功能閘門,您可以在 Pod 層級指定資源請求和限制。在 Pod 層級,Kubernetes 1.36 僅支援特定資源類型的請求或限制:`cpu` 和/或 `memory` 和/或 `hugepages`。透過此功能,Kubernetes 允許您為 Pod 宣告一個整體資源預算,這在處理大量容器時特別有用,因為很難精確評估每個容器的個別資源需求。此外,它還能讓 Pod 中的容器彼此共用閒置資源,從而提高資源利用率。
對於 Pod,您可以透過包含以下內容來指定 CPU 和記憶體的資源限制和請求
spec.resources.limits.cpuspec.resources.limits.memoryspec.resources.limits.hugepages-<size>spec.resources.requests.cpuspec.resources.requests.memoryspec.resources.requests.hugepages-<size>CPU 資源的限制和請求以「cpu」單位測量。在 Kubernetes 中,1 個 CPU 單位相當於 **1 個實體 CPU 核心**,或 **1 個虛擬核心**,這取決於節點是實體主機還是運行在實體機器內的虛擬機器。
允許使用分數請求。當您定義一個 `spec.containers[].resources.requests.cpu` 設定為 `0.5` 的容器時,您所請求的 CPU 時間是請求 `1.0` CPU 時的一半。對於 CPU 資源單位,數量表達式 `0.1` 等同於表達式 `100m`,可讀作「一百毫核 (one hundred millicpu)」。有些人會說「一百毫核心 (one hundred millicores)」,兩者意思相同。
CPU 資源始終以絕對量指定,而非相對量。例如,無論容器是在單核、雙核還是 48 核機器上運行,`500m` CPU 都表示大致相同的計算能力。
Kubernetes 不允許您以小於 `1m` 或 `0.001` CPU 的精度指定 CPU 資源。為了避免意外使用無效的 CPU 數量,當使用的 CPU 單位小於 1 時,使用毫核 (milliCPU) 形式而非十進位形式來指定 CPU 單位會很有幫助。
例如,您有一個使用 `5m` 或 `0.005` CPU 的 Pod,並希望減少其 CPU 資源。透過使用十進位形式,很難察覺 `0.0005` CPU 是一個無效值,而透過使用毫核 (milliCPU) 形式,則更容易察覺 `0.5m` 是一個無效值。
`memory` 的限制和請求以位元組 (bytes) 為單位測量。您可以使用這些數量後綴之一來表示記憶體為純整數或定點數:E、P、T、G、M、k。您也可以使用二的冪次等效單位:Ei、Pi、Ti、Gi、Mi、Ki。Kubernetes API 也允許 `m` 作為後綴 (代表毫位元組:1/1000 位元組),但這在指定時並不實用:您必須始終分配整數位元組,或有時是更大的區塊,例如 1 gibibyte 的倍數。
以下是一些表示大致相同值的記憶體數量範例
128974848, 129e6, 129M, 128974848000m, 123Mi
請注意後綴的大小寫。「M」表示 megabytes (百萬位元組),而「m」表示 millibytes (毫位元組)。如果您請求 `400m` 記憶體,這表示請求 0.4 位元組。輸入此內容的人可能原本是想請求 400 mebibytes (`400Mi`) 或 400 megabytes (`400M`)。
下列 Pod 有兩個容器。這兩個容器都定義了 0.25 CPU 和 64MiB (226 位元組) 記憶體的請求。每個容器的限制為 0.5 CPU 和 128MiB 記憶體。可以說此 Pod 的請求為 0.5 CPU 和 128 MiB 記憶體,限制為 1 CPU 和 256MiB 記憶體。
---
apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: app
image: images.my-company.example/app:v4
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: log-aggregator
image: images.my-company.example/log-aggregator:v6
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
Kubernetes v1.34 [beta] (預設啟用)此功能可透過設定 `PodLevelResources` 功能閘門來啟用。下列 Pod 有一個明確的 1 CPU 和 100 MiB 記憶體的請求,以及一個明確的 1 CPU 和 200 MiB 記憶體的限制。`pod-resources-demo-ctr-1` 容器已設定明確的請求和限制。然而,`pod-resources-demo-ctr-2` 容器將僅共用 Pod 資源範圍內可用的資源,因為它沒有設定明確的請求和限制。
apiVersion: v1
kind: Pod
metadata:
name: pod-resources-demo
namespace: pod-resources-example
spec:
resources:
limits:
cpu: "1"
memory: "200Mi"
requests:
cpu: "1"
memory: "100Mi"
containers:
- name: pod-resources-demo-ctr-1
image: nginx
resources:
limits:
cpu: "0.5"
memory: "100Mi"
requests:
cpu: "0.5"
memory: "50Mi"
- name: pod-resources-demo-ctr-2
image: fedora
command:
- sleep
- inf
當您建立一個 Pod 時,Kubernetes 排程器會為該 Pod 選擇一個節點來運行。每個節點對於每種資源類型都有最大容量:它可以為 Pod 提供多少 CPU 和記憶體。排程器確保對於每種資源類型,所有已排程容器的資源請求總和小於該節點的容量。請注意,儘管節點上實際的記憶體或 CPU 資源使用量可能非常低,如果容量檢查失敗,排程器仍會拒絕將 Pod 放置在該節點上。這可以防止在資源使用量稍後增加時 (例如,在每日請求高峰期間) 節點上出現資源短缺。
當 kubelet 啟動 Pod 中的一個容器時,kubelet 會將該容器的記憶體和 CPU 請求與限制傳遞給容器執行時期。
在 Linux 上,容器執行時期通常會配置核心 cgroups,以應用和強制執行您定義的限制。
如果容器超出其記憶體請求,並且它運行的節點整體記憶體不足,則該容器所屬的 Pod 很可能會被驅逐。
容器可能允許或不允許長時間超過其 CPU 限制。然而,容器執行時期不會因為過度使用 CPU 而終止 Pods 或容器。
要判斷容器是否因資源限制而無法排程或被終止,請參閱疑難排解章節。
建立 Pod 後,您可能需要根據實際使用模式調整其 CPU 或記憶體資源。Kubernetes 提供兩種方法來調整 Pod 資源大小
Kubernetes v1.35 [stable](預設啟用)您可以在不重新建立的情況下,修改執行中 Pod 中容器的 CPU 和記憶體「請求 (requests)」和「限制 (limits)」。這稱為「原地 Pod 垂直擴展 (in-place Pod vertical scaling)」或「原地 Pod 調整大小 (in-place Pod resize)」。要執行原地調整大小,請使用 Pod 的 `/resize` 子資源更新容器的資源規範。您可以透過在容器規範中設定 `resizePolicy` 欄位來控制是否需要容器重新啟動。
改變 Pod 資源的雲原生方法是更新工作負載物件 (例如 Deployment 或 StatefulSet) 中的 Pod 模板,並讓工作負載的控制器以具有更新資源的新 Pod 替換舊 Pod。此方法適用於任何 Kubernetes 版本,並且可以更改任何 Pod 規範。
有關 Pod 調整大小的更多詳細資訊,請參閱調整 Pod 大小。有關原地調整大小的詳細說明,請參閱調整分配給容器的 CPU 和記憶體資源。您也可以使用垂直 Pod 自動縮放器來自動管理 Pod 資源建議。
kubelet 會將 Pod 的資源使用情況作為 Pod `status` 的一部分進行報告。
如果您的叢集中提供了可選的監控工具,則 Pod 資源使用量可以直接從指標 API 取得,或從您的監控工具中取得。
從記憶體管理的角度來看,程序使用記憶體作為工作區與使用記憶體支援的 `emptyDir` 之間存在一些相似之處。但當記憶體被用作磁碟區時,例如記憶體支援的 `emptyDir`,您應該注意以下額外事項
如果您是叢集或命名空間的管理員,您也可以設定資源配額 (ResourceQuota) 來限制記憶體使用;您可能還希望定義一個限制範圍 (LimitRange) 以進行額外強制執行。如果您為每個 Pod 指定 `spec.containers[].resources.limits.memory`,那麼 `emptyDir` 磁碟區的最大大小將會是該 Pod 的記憶體限制。
作為替代方案,叢集管理員可以使用政策機制 (例如ValidationAdmissionPolicy) 來強制執行新 Pods 中 `emptyDir` 磁碟區的大小限制。
有關本機暫時儲存的一般概念,以及關於為容器配置暫時儲存的請求和/或限制的提示,請查閱本機暫時儲存頁面。
kubelet 可以測量正在使用多少本機暫時儲存。只要您已啟用本機暫時儲存容量隔離,它就會這樣做。
Kubernetes 追蹤 Pod 從以下來源使用的暫時儲存量
擴充資源是 `kubernetes.io` 網域之外的完整資源名稱。它們允許叢集操作員宣傳非 Kubernetes 內建資源,並供使用者使用。
使用擴充資源需要兩個步驟。首先,叢集操作員必須宣傳一個擴充資源。其次,使用者必須在 Pods 中請求擴充資源。
節點層級擴充資源與節點綁定。
有關如何在每個節點上宣傳裝置外掛程式管理的資源,請參閱裝置外掛程式。
要宣傳新的節點層級擴充資源,叢集操作員可以向 API 伺服器提交 `PATCH` HTTP 請求,以指定叢集中節點 `status.capacity` 中的可用數量。在此操作之後,節點的 `status.capacity` 將包含一個新資源。`status.allocatable` 欄位將由 kubelet 自動且非同步地使用新資源進行更新。
因為排程器在評估 Pod 適配性時使用節點的 `status.allocatable` 值,排程器只會在該非同步更新後才考慮新值。將新資源修補到節點容量與第一個請求該資源的 Pod 可以在該節點上排程之間可能會有一小段延遲。
範例:
這是一個範例,展示如何使用 `curl` 構成一個 HTTP 請求,用於在主節點為 `k8s-master` 的節點 `k8s-node-1` 上宣傳五個 "example.com/foo" 資源。
curl --header "Content-Type: application/json-patch+json" \
--request PATCH \
--data '[{"op": "add", "path": "/status/capacity/example.com~1foo", "value": "5"}]' \
http://k8s-master:8080/api/v1/nodes/k8s-node-1/status
叢集層級擴充資源不與節點綁定。它們通常由排程器擴充器 (scheduler extenders) 管理,這些擴充器負責處理資源消耗和資源配額。
您可以在排程器設定中指定由排程器擴充器處理的擴充資源
範例:
下列排程器政策設定表示叢集層級擴充資源 "example.com/foo" 由排程器擴充器處理。
{
"kind": "Policy",
"apiVersion": "v1",
"extenders": [
{
"urlPrefix":"<extender-endpoint>",
"bindVerb": "bind",
"managedResources": [
{
"name": "example.com/foo",
"ignoredByScheduler": true
}
]
}
]
}
透過 DRA 分配擴充資源允許叢集管理員在 DeviceClass 中指定 `extendedResourceName`,然後可以從 Pod 的擴充資源請求中請求與 DeviceClass 匹配的裝置。閱讀更多關於透過 DRA 分配擴充資源。
使用者可以在 Pod 規範中像 CPU 和記憶體一樣使用擴充資源。排程器會處理資源會計,以確保同時分配給 Pods 的資源不會超過可用數量。
API 伺服器將擴充資源的數量限制為整數。「有效」數量的範例為 `3`、`3000m` 和 `3Ki`。「無效」數量的範例為 `0.5` 和 `1500m` (因為 `1500m` 將導致 `1.5`)。
要在 Pod 中使用擴充資源,請將資源名稱作為鍵包含在容器規範中的 `spec.containers[].resources.limits` 映射中。
僅當所有資源請求 (包括 CPU、記憶體和任何擴充資源) 都滿足時,Pod 才會被排程。只要資源請求無法滿足,Pod 就會保持在 `PENDING` 狀態。
範例:
下面的 Pod 請求 2 個 CPU 和 1 個 "example.com/foo" (一個擴充資源)。
apiVersion: v1
kind: Pod
metadata:
name: my-pod
spec:
containers:
- name: my-container
image: myimage
resources:
requests:
cpu: 2
example.com/foo: 1
limits:
example.com/foo: 1
程序 ID (PID) 限制允許設定 kubelet 來限制給定 Pod 可以消耗的 PID 數量。詳情請參閱PID 限制。
如果排程器找不到任何可以容納 Pod 的節點,該 Pod 將保持未排程狀態,直到找到一個位置為止。每當排程器未能為 Pod 找到位置時,就會產生一個事件 (Event)。您可以使用 `kubectl` 查看 Pod 的事件;例如
kubectl describe pod frontend | grep -A 9999999999 Events
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 23s default-scheduler 0/42 nodes available: insufficient cpu
在前述範例中,名為 "frontend" 的 Pod 因任何節點上的 CPU 資源不足而無法排程。類似的錯誤訊息也可能表示因記憶體不足 (`PodExceedsFreeMemory`) 導致的失敗。一般來說,如果 Pod 處於 Pending 狀態並顯示此類訊息,有幾種解決方法可以嘗試
您可以使用 `kubectl describe nodes` 指令檢查節點容量和已分配的數量。例如
kubectl describe nodes e2e-test-node-pool-4lw4
Name: e2e-test-node-pool-4lw4
[ ... lines removed for clarity ...]
Capacity:
cpu: 2
memory: 7679792Ki
pods: 110
Allocatable:
cpu: 1800m
memory: 7474992Ki
pods: 110
[ ... lines removed for clarity ...]
Non-terminated Pods: (5 in total)
Namespace Name CPU Requests CPU Limits Memory Requests Memory Limits
--------- ---- ------------ ---------- --------------- -------------
kube-system fluentd-gcp-v1.38-28bv1 100m (5%) 0 (0%) 200Mi (2%) 200Mi (2%)
kube-system kube-dns-3297075139-61lj3 260m (13%) 0 (0%) 100Mi (1%) 170Mi (2%)
kube-system kube-proxy-e2e-test-... 100m (5%) 0 (0%) 0 (0%) 0 (0%)
kube-system monitoring-influxdb-grafana-v4-z1m12 200m (10%) 200m (10%) 600Mi (8%) 600Mi (8%)
kube-system node-problem-detector-v0.1-fj7m3 20m (1%) 200m (10%) 20Mi (0%) 100Mi (1%)
Allocated resources:
(Total limits may be over 100 percent, i.e., overcommitted.)
CPU Requests CPU Limits Memory Requests Memory Limits
------------ ---------- --------------- -------------
680m (34%) 400m (20%) 920Mi (11%) 1070Mi (13%)
在前述輸出中,您可以看到,如果 Pod 請求超過 1.120 CPU 或超過 6.23Gi 的記憶體,該 Pod 將無法放入節點。
透過查看「Pods」區段,您可以看到哪些 Pods 正在佔用節點上的空間。
可供 Pods 使用的資源量少於節點容量,因為系統守護程序會使用一部分可用資源。在 Kubernetes API 中,每個節點都有一個 `.status.allocatable` 欄位 (詳情請參閱NodeStatus)。
`.status.allocatable` 欄位描述了該節點上可供 Pods 使用的資源量 (例如:15 個虛擬 CPU 和 7538 MiB 記憶體)。有關 Kubernetes 中節點可分配資源的更多資訊,請參閱為系統守護程序保留計算資源。
您可以設定資源配額 (resource quotas) 來限制命名空間可以消耗的總資源量。當特定命名空間中存在 ResourceQuota 時,Kubernetes 會對該命名空間中的物件強制執行配額。例如,如果您將特定的命名空間分配給不同的團隊,您可以在這些命名空間中新增 ResourceQuotas。設定資源配額有助於防止一個團隊使用過多的任何資源,以致於這種過度使用影響到其他團隊。
您還應該考慮您授予該命名空間的存取權限:對命名空間的完全寫入存取權限允許擁有該存取權限的人移除任何資源,包括已配置的 ResourceQuota。
您的容器可能會因為資源不足而被終止。要檢查容器是否因為達到資源限制而被終止,請在相關 Pod 上執行 `kubectl describe pod`。
kubectl describe pod simmemleak-hra99
輸出類似於
Name: simmemleak-hra99
Namespace: default
Image(s): saadali/simmemleak
Node: kubernetes-node-tf0f/10.240.216.66
Labels: name=simmemleak
Status: Running
Reason:
Message:
IP: 10.244.2.75
Containers:
simmemleak:
Image: saadali/simmemleak:latest
Limits:
cpu: 100m
memory: 50Mi
State: Running
Started: Tue, 07 Jul 2019 12:54:41 -0700
Last State: Terminated
Reason: OOMKilled
Exit Code: 137
Started: Fri, 07 Jul 2019 12:54:30 -0700
Finished: Fri, 07 Jul 2019 12:54:33 -0700
Ready: False
Restart Count: 5
Conditions:
Type Status
Ready False
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled 42s default-scheduler Successfully assigned simmemleak-hra99 to kubernetes-node-tf0f
Normal Pulled 41s kubelet Container image "saadali/simmemleak:latest" already present on machine
Normal Created 41s kubelet Created container simmemleak
Normal Started 40s kubelet Started container simmemleak
Normal Killing 32s kubelet Killing container with id ead3fb35-5cf5-44ed-9ae1-488115be66c6: Need to kill Pod
在前述範例中,`Restart Count: 5` 表示 Pod 中的 `simmemleak` 容器已被終止並重新啟動了五次 (截至目前為止)。`OOMKilled` 原因顯示該容器試圖使用的記憶體超過了其限制。
您的下一步可能是檢查應用程式程式碼是否存在記憶體洩漏。如果您發現應用程式的行為符合預期,請考慮為該容器設定更高的記憶體限制 (以及可能的請求)。