Pod 和容器的資源管理

當你指定一個Pod時,你可以選擇性地指定每個容器所需的資源量。最常見的資源是 CPU 和記憶體(RAM),還有其他資源。

當你指定 Pod 中容器的資源**請求**時,kube-scheduler 會使用此資訊來決定將 Pod 放置在哪個節點上。當你為容器指定資源**限制**時,kubelet 會強制執行這些限制,以確保正在執行的容器不允許使用超過你設定的限制的資源。kubelet 還會專門為該容器保留至少**請求**的系統資源量以供使用。

請求和限制

如果 Pod 正在執行的節點有足夠的可用資源,容器可以使用超過其針對該資源指定的`request`(這是允許的)。

例如,如果你為容器設定了 256 MiB 的 `memory` 請求,並且該容器所在的 Pod 被排程到一個具有 8 GiB 記憶體且沒有其他 Pod 的節點上,那麼該容器可以嘗試使用更多的 RAM。

限制則不同。`cpu` 和 `memory` 限制都由 kubelet(和容器執行時)應用,並最終由核心強制執行。在 Linux 節點上,Linux 核心使用cgroups強制執行限制。`cpu` 和 `memory` 限制的強制執行行為略有不同。

CPU 限制透過 CPU 節流來強制執行。當容器接近其 CPU 限制時,核心將根據容器的限制來限制對 CPU 的訪問。因此,CPU 限制是核心強制執行的硬限制。容器不能使用超過其 CPU 限制中指定的 CPU 量。

記憶體限制由核心透過記憶體不足(OOM)終止來強制執行。當容器使用超過其記憶體限制時,核心可能會終止它。但是,終止只發生在核心檢測到記憶體壓力時。因此,過度分配記憶體的容器可能不會立即被終止。這意味著記憶體限制是反應性強制執行的。容器可以使用超過其記憶體限制的記憶體,但如果這樣做,它可能會被終止。

資源型別

**CPU** 和 **記憶體** 都是一種**資源型別**。資源型別有一個基本單位。CPU 代表計算處理能力,以Kubernetes CPU 單位指定。記憶體以位元組為單位指定。對於 Linux 工作負載,你可以指定**大頁**(huge page)資源。大頁是 Linux 特有的功能,其中節點核心分配的記憶體塊比預設頁大小大得多。

例如,在一個預設頁大小為 4KiB 的系統上,你可以指定一個限制,`hugepages-2Mi: 80Mi`。如果容器嘗試分配超過 40 個 2MiB 大頁(總計 80 MiB),則該分配會失敗。

CPU 和記憶體統稱為**計算資源**或**資源**。計算資源是可度量的量,可以請求、分配和消耗。它們與API 資源不同。API 資源,例如 Pod 和服務是可以透過 Kubernetes API 伺服器讀取和修改的物件。

Pod 和容器的資源請求和限制

對於每個容器,您可以指定資源限制和請求,包括以下內容:

  • spec.containers[].resources.limits.cpu
  • spec.containers[].resources.limits.memory
  • spec.containers[].resources.limits.hugepages-<size>
  • spec.containers[].resources.requests.cpu
  • spec.containers[].resources.requests.memory
  • spec.containers[].resources.requests.hugepages-<size>

儘管您只能為單個容器指定請求和限制,但考慮 Pod 的總體資源請求和限制也很有用。對於特定資源,**Pod 資源請求/限制**是 Pod 中每個容器對該型別資源的請求/限制的總和。

Pod 級別資源規範

特性狀態: Kubernetes v1.34 [beta] (預設啟用:true)

如果你的叢集啟用了 `PodLevelResources` 功能門控,你可以在 Pod 級別指定資源請求和限制。在 Pod 級別,Kubernetes 1.34 僅支援特定資源型別(CPU、記憶體和/或 HugePages)的資源請求或限制。透過此功能,Kubernetes 允許你為 Pod 宣告一個總體資源預算,這在處理大量容器時特別有用,因為很難準確評估單個容器的資源需求。此外,它還允許 Pod 中的容器相互共享空閒資源,從而提高資源利用率。

對於 Pod,您可以透過包含以下內容來指定 CPU 和記憶體的資源限制和請求:

  • spec.resources.limits.cpu
  • spec.resources.limits.memory
  • spec.resources.limits.hugepages-<size>
  • spec.resources.requests.cpu
  • spec.resources.requests.memory
  • spec.resources.requests.hugepages-<size>

Kubernetes 中的資源單位

CPU 資源單位

CPU 資源的限制和請求以**CPU**單位測量。在 Kubernetes 中,1 CPU 單位相當於**1 個物理 CPU 核心**或**1 個虛擬核心**,具體取決於節點是物理主機還是在物理機內執行的虛擬機器。

允許分數請求。當您將容器的 `spec.containers[].resources.requests.cpu` 設定為 `0.5` 時,您請求的 CPU 時間是請求 `1.0` CPU 的一半。對於 CPU 資源單位,數量表示式 `0.1` 等同於表示式 `100m`,可以讀作“一百毫核”。有些人說“一百毫核”,這被理解為相同的意思。

CPU 資源始終以資源的絕對量指定,從不以相對量指定。例如,`500m` CPU 代表的計算能力大致相同,無論該容器執行在單核、雙核還是 48 核機器上。

記憶體資源單位

`memory` 的限制和請求以位元組為單位測量。您可以使用以下數量字尾之一,將記憶體表示為純整數或定點數:E、P、T、G、M、k。您還可以使用二進位制等效項:Ei、Pi、Ti、Gi、Mi、Ki。例如,以下值大致相同:

128974848, 129e6, 129M,  128974848000m, 123Mi

請注意字尾的大小寫。如果您請求 `400m` 的記憶體,這表示請求 0.4 位元組。輸入此值的人可能原本想請求 400 MiB (400Mi) 或 400 MB (400M)。

容器資源示例

以下 Pod 有兩個容器。這兩個容器都定義了 0.25 CPU 和 64 MiB (226 位元組) 記憶體的請求。每個容器的限制為 0.5 CPU 和 128 MiB 記憶體。可以說該 Pod 請求 0.5 CPU 和 128 MiB 記憶體,限制為 1 CPU 和 256 MiB 記憶體。

---
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"

Pod 資源示例

特性狀態: Kubernetes v1.34 [beta] (預設啟用:true)

此功能可透過設定 `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 如何被排程

當你建立 Pod 時,Kubernetes 排程器會為 Pod 選擇一個執行節點。每個節點對每種資源型別都有一個最大容量:它可以為 Pods 提供的 CPU 和記憶體量。排程器會確保,對於每種資源型別,已排程容器的資源請求總和小於節點的容量。請注意,儘管節點上的實際記憶體或 CPU 資源使用率非常低,但如果容量檢查失敗,排程器仍會拒絕將 Pod 放置在該節點上。這可以防止在資源使用量增加時(例如,在每日請求峰值期間)節點上出現資源短缺。

Kubernetes 如何應用資源請求和限制

當 kubelet 啟動作為 Pod 一部分的容器時,kubelet 將該容器的記憶體和 CPU 請求和限制傳遞給容器執行時。

在 Linux 上,容器執行時通常配置核心 cgroups 來應用和強制執行你定義的限制。

  • CPU 限制定義了容器可以使用多少 CPU 時間的硬上限。在每個排程間隔(時間片)期間,Linux 核心會檢查是否超出了此限制;如果超出,核心會等待,然後再允許該 cgroup 恢復執行。
  • CPU 請求通常定義一個權重。如果幾個不同的容器 (cgroups) 想要在一個資源爭用的系統上執行,那麼具有較大 CPU 請求的工作負載將獲得比具有較小請求的工作負載更多的 CPU 時間。
  • 記憶體請求主要用於(Kubernetes)Pod 排程期間。在支援 cgroups v2 的節點上,容器執行時可能會將記憶體請求用作設定 `memory.min` 和 `memory.low` 的提示。
  • 記憶體限制為該 cgroup 定義了一個記憶體上限。如果容器試圖分配超出此限制的記憶體,Linux 核心的記憶體不足子系統將啟用,並通常透過停止容器中試圖分配記憶體的程序之一進行干預。如果該程序是容器的 PID 1,並且容器被標記為可重啟,則 Kubernetes 將重新啟動該容器。
  • Pod 或容器的記憶體限制也可應用於記憶體支援卷中的頁面,例如 `emptyDir`。kubelet 將 `tmpfs` emptyDir 卷視為容器記憶體使用,而不是本地臨時儲存。 使用記憶體支援的 `emptyDir` 時,請務必檢視下面的注意事項。

如果容器超出了其記憶體請求,並且它所執行的節點總體記憶體不足,那麼該容器所屬的 Pod 很可能會被驅逐

容器可能會或可能不會被允許長時間超出其 CPU 限制。但是,容器執行時不會因 CPU 使用過度而終止 Pod 或容器。

要確定容器是否無法排程或因資源限制而被終止,請參閱故障排除部分。

監控計算和記憶體資源使用

kubelet 將 Pod 的資源使用情況作為 Pod `status` 的一部分進行報告。

如果叢集中提供了可選的監控工具,則可以透過Metrics API直接或從您的監控工具中檢索 Pod 資源使用情況。

記憶體支援的 `emptyDir` 卷的注意事項

從記憶體管理的角度來看,程序使用記憶體作為工作區和使用記憶體支援的 `emptyDir` 有一些相似之處。但是,當使用記憶體作為卷(如記憶體支援的 `emptyDir`)時,您還需要注意以下幾點:

  • 儲存在記憶體支援捲上的檔案幾乎完全由使用者應用程式管理。與用作程序工作區不同,您不能依賴諸如語言級垃圾回收之類的東西。
  • 將檔案寫入卷的目的是儲存資料或在應用程式之間傳遞資料。Kubernetes 和作業系統都不能自動從卷中刪除檔案,因此當系統或 Pod 記憶體不足時,這些檔案所使用的記憶體無法回收。
  • 記憶體支援的 `emptyDir` 因其效能而有用,但記憶體通常比其他儲存介質(如磁碟或 SSD)的尺寸小得多,成本也高得多。將大量記憶體用於 `emptyDir` 卷可能會影響 Pod 或整個節點的正常執行,因此應謹慎使用。

如果您是叢集或名稱空間的管理員,您還可以設定ResourceQuota來限制記憶體使用;您可能還需要定義LimitRange以進行額外強制執行。如果您為每個 Pod 指定了 `spec.containers[].resources.limits.memory`,那麼 `emptyDir` 卷的最大大小將是 Pod 的記憶體限制。

作為替代方案,叢集管理員可以使用策略機制(例如ValidationAdmissionPolicy)強制執行新 Pod 中 `emptyDir` 卷的大小限制。

本地臨時儲存

特性狀態: Kubernetes v1.25 [穩定]

節點具有本地臨時儲存,由本地連線的可寫裝置或有時由 RAM 提供支援。“臨時”意味著對永續性沒有長期保證。

Pod 使用臨時本地儲存作為暫存空間、快取和日誌。kubelet 可以使用本地臨時儲存透過將`emptyDir`掛載到容器中,為 Pod 提供暫存空間。

kubelet 還使用這種儲存來儲存節點級容器日誌、容器映象以及執行中容器的可寫層。

Kubernetes 允許你跟蹤、保留和限制 Pod 可以消耗的本地臨時儲存量。

本地臨時儲存的配置

Kubernetes 支援兩種配置節點本地臨時儲存的方式:

在此配置中,所有不同型別的臨時本地資料(`emptyDir` 卷、可寫層、容器映象、日誌)都放置在一個檔案系統中。配置 kubelet 最有效的方法是將此檔案系統專用於 Kubernetes (kubelet) 資料。

kubelet 還會寫入節點級容器日誌,並將其與臨時本地儲存類似處理。

kubelet 將日誌寫入其配置的日誌目錄(預設為 `/var/log`)內的檔案;並有一個用於其他本地儲存資料的基礎目錄(預設為 `/var/lib/kubelet`)。

通常,`/var/lib/kubelet` 和 `/var/log` 都位於系統根檔案系統上,kubelet 的設計考慮了這種佈局。

您的節點可以擁有任意數量的其他不用於 Kubernetes 的檔案系統。

節點上有一個檔案系統,您將其用於來自執行中 Pod 的臨時資料:日誌和 `emptyDir` 卷。您可以將此檔案系統用於其他資料(例如:與 Kubernetes 無關的系統日誌);它甚至可以是根檔案系統。

kubelet 還會將節點級容器日誌寫入第一個檔案系統,並將其與臨時本地儲存類似處理。

您還使用由不同邏輯儲存裝置支援的單獨檔案系統。在此配置中,您告知 kubelet 放置容器映象層和可寫層的目錄位於第二個檔案系統上。

第一個檔案系統不包含任何映象層或可寫層。

您的節點可以擁有任意數量的其他不用於 Kubernetes 的檔案系統。

kubelet 可以測量它使用了多少本地儲存。它這樣做,前提是您使用本地臨時儲存的一種支援配置設定了節點。

如果您有不同的配置,則 kubelet 不會對臨時本地儲存應用資源限制。

設定本地臨時儲存的請求和限制

您可以指定 `ephemeral-storage` 來管理本地臨時儲存。Pod 的每個容器可以指定以下一個或兩個:

  • spec.containers[].resources.limits.ephemeral-storage
  • spec.containers[].resources.requests.ephemeral-storage

`ephemeral-storage` 的限制和請求以位元組數量表示。您可以將儲存表示為純整數或使用以下字尾之一的定點數:E、P、T、G、M、k。您還可以使用二進位制等效項:Ei、Pi、Ti、Gi、Mi、Ki。例如,以下數量都大致表示相同的值:

  • 128974848
  • 129e6
  • 129M
  • 123Mi

請注意字尾的大小寫。如果您請求 `400m` 的臨時儲存,這表示請求 0.4 位元組。輸入此值的人可能原本想請求 400 MiB (400Mi) 或 400 MB (400M)。

在以下示例中,Pod 有兩個容器。每個容器都請求 2GiB 的本地臨時儲存。每個容器的限制為 4GiB 的本地臨時儲存。因此,該 Pod 請求 4GiB 的本地臨時儲存,限制為 8GiB 的本地臨時儲存。其中 500Mi 的限制可由 `emptyDir` 卷消耗。

apiVersion: v1
kind: Pod
metadata:
  name: frontend
spec:
  containers:
  - name: app
    image: images.my-company.example/app:v4
    resources:
      requests:
        ephemeral-storage: "2Gi"
      limits:
        ephemeral-storage: "4Gi"
    volumeMounts:
    - name: ephemeral
      mountPath: "/tmp"
  - name: log-aggregator
    image: images.my-company.example/log-aggregator:v6
    resources:
      requests:
        ephemeral-storage: "2Gi"
      limits:
        ephemeral-storage: "4Gi"
    volumeMounts:
    - name: ephemeral
      mountPath: "/tmp"
  volumes:
    - name: ephemeral
      emptyDir:
        sizeLimit: 500Mi

帶有 ephemeral-storage 請求的 Pod 如何被排程

當您建立一個 Pod 時,Kubernetes 排程器會為該 Pod 選擇一個執行節點。每個節點都可以為 Pods 提供最大量的本地臨時儲存。有關更多資訊,請參閱節點可分配資源

排程器確保已排程容器的資源請求總和小於節點的容量。

臨時儲存消耗管理

如果 kubelet 將本地臨時儲存作為資源進行管理,則 kubelet 會測量儲存使用情況:

  • `emptyDir` 卷,除了 *tmpfs* `emptyDir` 卷
  • 儲存節點級別日誌的目錄
  • 可寫容器層

如果 Pod 使用的臨時儲存超過您允許的量,kubelet 會設定一個驅逐訊號,觸發 Pod 驅逐。

對於容器級隔離,如果容器的可寫層和日誌使用量超出其儲存限制,kubelet 會將 Pod 標記為驅逐。

對於 Pod 級隔離,kubelet 透過彙總該 Pod 中所有容器的儲存限制來計算 Pod 的總體儲存限制。在這種情況下,如果所有容器的本地臨時儲存使用量以及 Pod 的 `emptyDir` 卷的總和超出了 Pod 的總體儲存限制,則 kubelet 也會將該 Pod 標記為驅逐。

kubelet 支援不同的方式來測量 Pod 儲存使用情況:

kubelet 執行定期、計劃的檢查,掃描每個 `emptyDir` 卷、容器日誌目錄和可寫容器層。

掃描測量使用了多少空間。

特性狀態: Kubernetes v1.31 [beta] (預設停用)

專案配額是用於管理檔案系統儲存使用的作業系統級別功能。透過 Kubernetes,您可以啟用專案配額來監控儲存使用情況。確保節點上支援 `emptyDir` 卷的檔案系統提供專案配額支援。例如,XFS 和 ext4fs 提供專案配額。

Kubernetes 使用從 `1048576` 開始的專案 ID。正在使用的 ID 註冊在 `/etc/projects` 和 `/etc/projid` 中。如果此範圍內的專案 ID 用於系統上的其他目的,則這些專案 ID 必須註冊在 `/etc/projects` 和 `/etc/projid` 中,以便 Kubernetes 不會使用它們。

配額比目錄掃描更快、更準確。當一個目錄被分配到一個專案時,該目錄下建立的所有檔案都在該專案中建立,核心只需跟蹤該專案中檔案使用了多少塊。如果一個檔案被建立和刪除,但有一個開啟的檔案描述符,它會繼續佔用空間。配額跟蹤準確地記錄了該空間,而目錄掃描則會忽略被刪除檔案佔用的儲存空間。

要使用配額來跟蹤 Pod 的資源使用情況,Pod 必須位於使用者名稱空間中。在使用者名稱空間中,核心限制對檔案系統上 projectID 的更改,確保配額計算的儲存指標的可靠性。

如果要使用專案配額,您應該:

  • 使用 kubelet 配置中的 `featureGates` 欄位啟用 `LocalStorageCapacityIsolationFSQuotaMonitoring=true` 功能門控

  • 確保 `UserNamespacesSupport` 功能門控已啟用,並且核心、CRI 實現和 OCI 執行時支援使用者名稱空間。

  • 確保根檔案系統(或可選的執行時檔案系統)已啟用專案配額。所有 XFS 檔案系統都支援專案配額。對於 ext4 檔案系統,您需要在檔案系統未掛載時啟用專案配額跟蹤功能。

    # For ext4, with /dev/block-device not mounted
    sudo tune2fs -O project -Q prjquota /dev/block-device
    
  • 確保根檔案系統(或可選的執行時檔案系統)已掛載並啟用了專案配額。對於 XFS 和 ext4fs,掛載選項都命名為 `prjquota`。

如果您不想使用專案配額,您應該:

擴充套件資源

擴充套件資源是 `kubernetes.io` 域之外的完全限定資源名稱。它們允許叢集操作員通告非 Kubernetes 內建資源,並允許使用者使用這些資源。

使用擴充套件資源需要兩個步驟。首先,叢集操作員必須通告擴充套件資源。其次,使用者必須在 Pod 中請求擴充套件資源。

管理擴充套件資源

節點級擴充套件資源

節點級擴充套件資源與節點繫結。

裝置外掛管理資源

有關如何在每個節點上通告裝置外掛管理資源的資訊,請參見裝置外掛

其他資源

要通告新的節點級擴充套件資源,叢集操作員可以向 API 伺服器提交 `PATCH` HTTP 請求,以指定叢集中節點 `status.capacity` 中的可用數量。此操作後,節點的 `status.capacity` 將包含新的資源。kubelet 會非同步自動使用新資源更新 `status.allocatable` 欄位。

由於排程器在評估 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

叢集級擴充套件資源

叢集級擴充套件資源不與節點繫結。它們通常由排程器擴充套件器管理,排程器擴充套件器處理資源消耗和資源配額。

您可以在排程器配置中指定由排程器擴充套件器處理的擴充套件資源。

示例

以下排程器策略配置表明叢集級擴充套件資源“example.com/foo”由排程器擴充套件器處理。

  • 只有當 Pod 請求 "example.com/foo" 時,排程器才將 Pod 傳送到排程器擴充套件器。
  • `ignoredByScheduler` 欄位指定排程器在其 `PodFitsResources` 謂詞中不檢查 "example.com/foo" 資源。
{
  "kind": "Policy",
  "apiVersion": "v1",
  "extenders": [
    {
      "urlPrefix":"<extender-endpoint>",
      "bindVerb": "bind",
      "managedResources": [
        {
          "name": "example.com/foo",
          "ignoredByScheduler": true
        }
      ]
    }
  ]
}

透過 DRA 進行擴充套件資源分配

透過 DRA 進行擴充套件資源分配允許叢集管理員在 DeviceClass 中指定 `extendedResourceName`,然後可以從 Pod 的擴充套件資源請求中請求與 DeviceClass 匹配的裝置。閱讀有關透過 DRA 進行擴充套件資源分配的更多資訊。

使用擴充套件資源

使用者可以在 Pod 規格中像 CPU 和記憶體一樣使用擴充套件資源。排程器負責資源記賬,以便同時分配給 Pod 的資源量不超過可用量。

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

PID 限制

程序 ID (PID) 限制允許配置 kubelet 來限制給定 Pod 可以消耗的 PID 數量。有關資訊,請參閱PID 限制

故障排除

我的 Pods 處於 Pending 狀態,並顯示事件訊息 `FailedScheduling`

如果排程器找不到任何 Pod 可以適應的節點,Pod 將保持未排程狀態,直到找到一個位置。每次排程器未能為 Pod 找到位置時,都會生成一個事件。您可以使用 `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 處於掛起狀態並帶有此型別的訊息,可以嘗試以下幾件事:

  • 向叢集新增更多節點。
  • 終止不需要的 Pods,為待處理的 Pods 騰出空間。
  • 檢查 Pod 是否沒有比所有節點都大。例如,如果所有節點的容量都是 `cpu: 1`,那麼請求 `cpu: 1.1` 的 Pod 將永遠不會被排程。
  • 檢查節點汙點。如果大多數節點都被汙染,並且新 Pod 不容忍該汙點,則排程器只會考慮將其放置在沒有該汙點的其餘節點上。

您可以使用 `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”部分,您可以檢視哪些 Pod 正在佔用節點上的空間。

可用 Pod 的資源量小於節點容量,因為系統守護程序佔用了一部分可用資源。在 Kubernetes API 中,每個 Node 都有一個 `status.allocatable` 欄位(有關詳細資訊,請參見NodeStatus)。

`status.allocatable` 欄位描述了該節點上可供 Pod 使用的資源量(例如:15 個虛擬 CPU 和 7538 MiB 記憶體)。有關 Kubernetes 中節點可分配資源的更多資訊,請參見為系統守護程序保留計算資源

您可以配置資源配額來限制名稱空間可以消耗的資源總量。當名稱空間中有 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` 原因表明容器嘗試使用的記憶體超出了其限制。

您的下一步可能是檢查應用程式程式碼是否存在記憶體洩漏。如果您發現應用程式的行為符合預期,請考慮為該容器設定更高的記憶體限制(也可能是請求)。

下一步

上次修改時間:2025 年 8 月 6 日下午 3:40 PST:移除了 DeviceClass 周圍的反引號 (3a894e1291)