Pod 和 Container 的資源管理
當您指定 Pod 時,您可以選擇性地指定 Container 需要多少資源。 最常指定的資源是 CPU 和記憶體 (RAM);還有其他資源。
當您為 Pod 中的容器指定資源request時,kube-scheduler 會使用此資訊來決定將 Pod 放置在哪個節點上。當您為容器指定資源limit時,kubelet 會強制執行這些限制,以確保執行中的容器使用的資源不超過您設定的限制。kubelet 也會預留至少 request 量的系統資源,專供該容器使用。
Request 和 Limit
如果 Pod 執行的節點有足夠的可用資源,容器有可能(且被允許)使用超過其資源 request
所指定的量。
例如,如果您為容器設定 256 MiB 的 memory
request,且該容器位於排程到具有 8GiB 記憶體且沒有其他 Pod 的節點的 Pod 中,則該容器可以嘗試使用更多 RAM。
Limit 則情況不同。cpu
和 memory
limit 都由 kubelet(和 容器執行期)套用,並最終由核心強制執行。在 Linux 節點上,Linux 核心使用 cgroups 強制執行限制。cpu
和 memory
limit 強制執行的行為略有不同。
cpu
limit 通過 CPU 節流強制執行。當容器接近其 cpu
limit 時,核心將限制對應於容器 limit 的 CPU 存取。因此,cpu
limit 是核心強制執行的硬性限制。容器使用的 CPU 不得超過其 cpu
limit 中指定的量。
memory
limit 由核心通過記憶體不足 (OOM) 終止強制執行。當容器使用的記憶體超過其 memory
limit 時,核心可能會終止它。但是,終止只會在核心偵測到記憶體壓力時發生。因此,過度分配記憶體的容器可能不會立即被終止。這表示 memory
limit 是被動強制執行的。容器可能使用超過其 memory
limit 的記憶體,但如果這樣做,它可能會被終止。
注意
有一個 Alpha 功能MemoryQoS
嘗試為記憶體新增更主動的限制強制執行(相對於 OOM killer 的被動強制執行)。但是,由於記憶體消耗量大的應用程式可能導致潛在的活鎖情況,因此此工作已停滯。注意
如果您為資源指定了 limit,但未指定任何 request,且沒有準入時間機制已為該資源套用預設 request,則 Kubernetes 會複製您指定的 limit,並將其用作該資源的 request 值。資源類型
CPU 和 memory 各自是一種資源類型。資源類型具有基本單位。CPU 代表運算處理能力,並以 Kubernetes CPU 為單位指定。記憶體以位元組為單位指定。對於 Linux 工作負載,您可以指定 huge page 資源。Huge page 是 Linux 特有的功能,其中節點核心會分配比預設頁面大小大得多的記憶體區塊。
例如,在預設頁面大小為 4KiB 的系統上,您可以指定一個 limit,hugepages-2Mi: 80Mi
。如果容器嘗試分配超過 40 個 2MiB huge page(總共 80 MiB),則該分配將失敗。
注意
您無法過度承諾hugepages-*
資源。這與 memory
和 cpu
資源不同。CPU 和記憶體統稱為運算資源或資源。運算資源是可以請求、分配和消耗的可測量數量。它們與 API 資源 不同。API 資源(例如 Pod 和 服務)是可以通過 Kubernetes API 伺服器讀取和修改的物件。
Pod 和容器的資源 Request 和 Limit
對於每個容器,您可以指定資源 limit 和 request,包括以下內容:
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>
雖然您只能為個別容器指定 request 和 limit,但考慮 Pod 的整體資源 request 和 limit 也很有用。對於特定資源,Pod 資源 request/limit 是 Pod 中每個容器的該類型資源 request/limit 的總和。
Pod 層級資源規格
Kubernetes v1.32 [alpha]
(預設停用:false)從 Kubernetes 1.32 開始,您也可以在 Pod 層級指定資源 request 和 limit。在 Pod 層級,Kubernetes 1.32 僅支援特定資源類型(cpu
和/或 memory
)的資源 request 或 limit。此功能目前處於 Alpha 階段,啟用此功能後,Kubernetes 允許您宣告 Pod 的整體資源預算,這在處理大量容器時特別有用,因為在這種情況下,準確評估個別資源需求可能很困難。此外,它使 Pod 內的容器能夠彼此共享閒置資源,從而提高資源利用率。
對於 Pod,您可以通過包含以下內容來指定 CPU 和記憶體的資源 limit 和 request:
spec.resources.limits.cpu
spec.resources.limits.memory
spec.resources.requests.cpu
spec.resources.requests.memory
Kubernetes 中的資源單位
CPU 資源單位
CPU 資源的 limit 和 request 以 cpu 單位衡量。在 Kubernetes 中,1 個 CPU 單位相當於1 個實體 CPU 核心,或1 個虛擬核心,具體取決於節點是實體主機還是虛擬機器(在實體機器內執行)。
允許小數 request。當您定義一個 spec.containers[].resources.requests.cpu
設定為 0.5
的容器時,您請求的 CPU 時間是請求 1.0
CPU 的一半。對於 CPU 資源單位,數量表示式 0.1
等於表示式 100m
,可以讀作「一百 millicpu」。有些人說「一百 millicore」,這被理解為相同的含義。
CPU 資源始終指定為資源的絕對量,而不是相對量。例如,500m
CPU 代表大致相同的運算能力,無論該容器是在單核心、雙核心還是 48 核心機器上執行。
注意
Kubernetes 不允許您指定 CPU 資源的精度低於 1m
或 0.001
CPU。為了避免意外使用無效的 CPU 數量,當使用小於 1 個 CPU 單位時,使用 milliCPU 形式而不是小數形式來指定 CPU 單位會很有用。
例如,您有一個 Pod 使用 5m
或 0.005
CPU,並且想要減少其 CPU 資源。通過使用小數形式,更難以發現 0.0005
CPU 是無效值,而通過使用 milliCPU 形式,更容易發現 0.5m
是無效值。
記憶體資源單位
memory
的 limit 和 request 以位元組為單位衡量。您可以使用純整數或使用以下 數量 後綴之一來表示記憶體:E、P、T、G、M、k。您也可以使用二的冪等效值:Ei、Pi、Ti、Gi、Mi、Ki。例如,以下表示大致相同的值:
128974848, 129e6, 129M, 128974848000m, 123Mi
請注意後綴的大小寫。如果您請求 400m
的記憶體,則表示請求 0.4 位元組。輸入該值的人可能想要請求 400 mebibytes (400Mi
) 或 400 megabytes (400M
)。
容器資源範例
以下 Pod 有兩個容器。兩個容器都定義了 0.25 CPU 和 64MiB(226 位元組)記憶體的 request。每個容器的 limit 為 0.5 CPU 和 128MiB 記憶體。您可以說 Pod 的 request 為 0.5 CPU 和 128 MiB 記憶體,limit 為 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"
Pod 資源範例
Kubernetes v1.32 [alpha]
(預設停用:false)以下 Pod 具有 1 CPU 和 100 MiB 記憶體的明確 request,以及 1 CPU 和 200 MiB 記憶體的明確 limit。pod-resources-demo-ctr-1
容器已設定明確的 request 和 limit。但是,pod-resources-demo-ctr-2
容器將僅共享 Pod 資源邊界內可用的資源,因為它沒有設定明確的 request 和 limit。
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
具有資源 Request 的 Pod 如何排程
當您建立 Pod 時,Kubernetes 排程器會選取節點以供 Pod 在其上執行。每個節點對於每種資源類型都有最大容量:它可以為 Pod 提供的 CPU 和記憶體量。排程器確保對於每種資源類型,已排程容器的資源 request 總和小於節點的容量。請注意,儘管節點上的實際記憶體或 CPU 資源使用率非常低,但如果容量檢查失敗,排程器仍然會拒絕將 Pod 放置在節點上。這可以防止節點在稍後資源使用量增加時(例如,在每日請求率高峰期間)出現資源短缺。
Kubernetes 如何套用資源 Request 和 Limit
當 kubelet 作為 Pod 的一部分啟動容器時,kubelet 會將該容器的記憶體和 CPU 的 request 和 limit 傳遞給容器執行期。
在 Linux 上,容器執行期通常會配置核心 cgroups,以套用和強制執行您定義的 limit。
- CPU limit 定義了容器可以使用的 CPU 時間的硬性上限。在每個排程間隔(時間片)期間,Linux 核心會檢查是否超過此 limit;如果超過,則核心會等待,然後才允許該 cgroup 恢復執行。
- CPU request 通常定義權重。如果多個不同的容器 (cgroups) 想要在競爭系統上執行,則具有較大 CPU request 的工作負載將比具有較小 request 的工作負載分配到更多的 CPU 時間。
- 記憶體 request 主要在(Kubernetes)Pod 排程期間使用。在使用 cgroups v2 的節點上,容器執行期可能會使用記憶體 request 作為提示來設定
memory.min
和memory.low
。 - 記憶體 limit 定義了該 cgroup 的記憶體 limit。如果容器嘗試分配的記憶體超過此 limit,則 Linux 核心記憶體不足子系統會啟動,並且通常會通過停止容器中嘗試分配記憶體的其中一個進程來介入。如果該進程是容器的 PID 1,並且該容器被標記為可重新啟動,則 Kubernetes 會重新啟動該容器。
- Pod 或容器的記憶體 limit 也可能適用於記憶體支援的卷中的頁面,例如
emptyDir
。kubelet 將tmpfs
emptyDir 卷追蹤為容器記憶體使用量,而不是本機臨時儲存空間。當使用記憶體支援的emptyDir
時,請務必查看下面的注意事項。
如果容器超出其記憶體 request,並且其執行的節點整體記憶體不足,則容器所屬的 Pod 很可能會被驅逐。
容器可能允許或不允許在長時間內超過其 CPU limit。但是,容器執行期不會因為 CPU 使用率過高而終止 Pod 或容器。
要確定容器是否由於資源 limit 而無法排程或被終止,請參閱疑難排解章節。
監控運算和記憶體資源使用量
kubelet 會將 Pod 的資源使用量作為 Pod status
的一部分報告。
如果您的叢集中提供可選的監控工具,則可以從Metrics API 直接或從您的監控工具檢索 Pod 資源使用量。
記憶體支援的 emptyDir
卷的注意事項
注意
如果您未為emptyDir
卷指定 sizeLimit
,則該卷可能會消耗高達該 Pod 的記憶體 limit(Pod.spec.containers[].resources.limits.memory
)。如果您未設定記憶體 limit,則 Pod 的記憶體消耗量沒有上限,並且可能會消耗節點上的所有可用記憶體。Kubernetes 會根據資源 request (Pod.spec.containers[].resources.requests
) 排程 Pod,並且在決定另一個 Pod 是否可以容納在給定節點上時,不會考慮高於 request 的記憶體使用量。這可能會導致阻斷服務,並導致作業系統執行記憶體不足 (OOM) 處理。可以建立任意數量的 emptyDir
,它們可能會消耗節點上的所有可用記憶體,從而使 OOM 更容易發生。從記憶體管理的角度來看,當進程將記憶體用作工作區和使用記憶體支援的 emptyDir
時,它們之間存在一些相似之處。但是,當將記憶體用作卷(如記憶體支援的 emptyDir
)時,您應注意以下其他要點:
- 儲存在記憶體支援的卷上的檔案幾乎完全由使用者應用程式管理。與用作進程的工作區不同,您不能依賴語言層級的垃圾收集等功能。
- 將檔案寫入卷的目的是儲存資料或在應用程式之間傳遞資料。Kubernetes 和作業系統都不會自動從卷中刪除檔案,因此當系統或 Pod 處於記憶體壓力下時,這些檔案使用的記憶體無法回收。
- 記憶體支援的
emptyDir
因其效能而有用,但記憶體的尺寸通常比其他儲存媒體(如磁碟或 SSD)小得多,且成本高得多。為emptyDir
卷使用大量記憶體可能會影響您的 Pod 或整個節點的正常運作,因此應謹慎使用。
如果您正在管理叢集或命名空間,您還可以設定 ResourceQuota,以限制記憶體使用量;您可能還想定義 LimitRange 以進行額外強制執行。如果您為每個 Pod 指定 spec.containers[].resources.limits.memory
,則 emptyDir
卷的最大大小將為 Pod 的記憶體 limit。
作為替代方案,叢集管理員可以使用原則機制(例如 ValidationAdmissionPolicy)強制執行新 Pod 中 emptyDir
卷的大小 limit。
本機臨時儲存空間
Kubernetes v1.25 [stable]
節點具有本機臨時儲存空間,由本機連接的可寫入裝置或有時由 RAM 支援。「臨時」表示對於持久性沒有長期保證。
Pod 使用臨時本機儲存空間作為暫存空間、快取和日誌。kubelet 可以使用本機臨時儲存空間為 Pod 提供暫存空間,以將 emptyDir
卷掛載到容器中。
kubelet 也使用此類型的儲存空間來保存節點層級容器日誌、容器映像和執行中容器的可寫入層。
注意
如果節點發生故障,則其臨時儲存空間中的資料可能會遺失。您的應用程式不能期望從本機臨時儲存空間獲得任何效能 SLA(例如磁碟 IOPS)。注意
為了使資源配額在本機臨時儲存空間上運作,需要完成兩件事:
- 管理員在命名空間中設定臨時儲存空間的資源配額。
- 使用者需要在 Pod spec 中指定臨時儲存空間資源的 limit。
如果使用者未在 Pod spec 中指定臨時儲存空間資源 limit,則資源配額不會在本機臨時儲存空間上強制執行。
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 才能執行此操作。
如果您有不同的配置,則 kubelet 不會對臨時本機儲存空間套用資源 limit。
注意
kubelet 將tmpfs
emptyDir 卷追蹤為容器記憶體使用量,而不是本機臨時儲存空間。注意
kubelet 將僅追蹤根檔案系統以獲取臨時儲存空間。將單獨磁碟掛載到/var/lib/kubelet
或 /var/lib/containers
的作業系統佈局將無法正確報告臨時儲存空間。設定本機臨時儲存空間的 Request 和 Limit
您可以指定 ephemeral-storage
以管理本機臨時儲存空間。Pod 的每個容器都可以指定以下一項或兩項:
spec.containers[].resources.limits.ephemeral-storage
spec.containers[].resources.requests.ephemeral-storage
ephemeral-storage
的 limit 和 request 以位元組數量衡量。您可以使用純整數或使用以下後綴之一以定點數表示儲存空間:E、P、T、G、M、k。您也可以使用二的冪等效值:Ei、Pi、Ti、Gi、Mi、Ki。例如,以下數量都表示大致相同的值:
128974848
129e6
129M
123Mi
請注意後綴的大小寫。如果您請求 400m
的臨時儲存空間,則表示請求 0.4 位元組。輸入該值的人可能想要請求 400 mebibytes (400Mi
) 或 400 megabytes (400M
)。
在以下範例中,Pod 有兩個容器。每個容器都具有 2GiB 本機臨時儲存空間的 request。每個容器的 limit 為 4GiB 本機臨時儲存空間。因此,Pod 的 request 為 4GiB 本機臨時儲存空間,limit 為 8GiB 本機臨時儲存空間。該 limit 中的 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
具有臨時儲存空間 Request 的 Pod 如何排程
當您建立 Pod 時,Kubernetes 排程器會選取節點以供 Pod 在其上執行。每個節點都有它可以為 Pod 提供的最大本機臨時儲存空間量。如需更多資訊,請參閱節點可分配資源。
排程器確保已排程容器的資源 request 總和小於節點的容量。
臨時儲存空間消耗管理
如果 kubelet 正在將本機臨時儲存空間作為資源進行管理,則 kubelet 會測量以下項目的儲存空間使用量:
emptyDir
卷,tmpfsemptyDir
卷除外- 保存節點層級日誌的目錄
- 可寫入容器層
如果 Pod 使用的臨時儲存空間超過您允許的量,則 kubelet 會設定驅逐訊號,觸發 Pod 驅逐。
對於容器層級隔離,如果容器的可寫入層和日誌使用量超過其儲存空間 limit,則 kubelet 會將 Pod 標記為驅逐。
對於 Pod 層級隔離,kubelet 會通過將該 Pod 中容器的 limit 相加來計算 Pod 的整體儲存空間 limit。在這種情況下,如果所有容器的本機臨時儲存空間使用量總和以及 Pod 的 emptyDir
卷超過 Pod 的整體儲存空間 limit,則 kubelet 也會將 Pod 標記為驅逐。
注意
如果 kubelet 未測量本機臨時儲存空間,則超出其本機儲存空間 limit 的 Pod 將不會因違反本機儲存空間資源 limit 而被驅逐。
但是,如果可寫入容器層、節點層級日誌或 emptyDir
卷的檔案系統空間不足,則節點會將自身染污為本機儲存空間不足,並且此染污會觸發驅逐任何不特別容忍該染污的 Pod。
請參閱受支援的配置以獲取臨時本機儲存空間。
kubelet 支援不同的方式來測量 Pod 儲存空間使用量:
kubelet 執行定期、排定的檢查,掃描每個 emptyDir
卷、容器日誌目錄和可寫入容器層。
掃描測量已使用的空間量。
注意
在此模式下,kubelet 不會追蹤已刪除檔案的開啟檔案描述符。
如果您(或容器)在 emptyDir
卷中建立檔案,然後某些東西開啟該檔案,並且您在檔案仍處於開啟狀態時刪除該檔案,則已刪除檔案的 inode 會保留到您關閉該檔案為止,但 kubelet 不會將該空間分類為正在使用。
Kubernetes v1.31 [beta]
(預設停用:false)專案配額是一種作業系統層級功能,用於管理檔案系統上的儲存空間使用量。借助 Kubernetes,您可以啟用專案配額來監控儲存空間使用量。請確保支援 emptyDir
卷的檔案系統(在節點上)提供專案配額支援。例如,XFS 和 ext4fs 提供專案配額。
注意
專案配額可讓您監控儲存空間使用量;它們不強制執行 limit。Kubernetes 使用從 1048576
開始的專案 ID。正在使用的 ID 註冊在 /etc/projects
和 /etc/projid
中。如果此範圍內的專案 ID 用於系統上的其他用途,則必須在 /etc/projects
和 /etc/projid
中註冊這些專案 ID,以便 Kubernetes 不會使用它們。
配額比目錄掃描更快、更準確。當目錄被指派給專案時,在目錄下建立的所有檔案都會在該專案中建立,並且核心只需追蹤該專案中檔案使用的區塊數量。如果建立並刪除檔案,但具有開啟的檔案描述符,它仍會繼續消耗空間。配額追蹤可以準確記錄該空間,而目錄掃描會忽略已刪除檔案使用的儲存空間。
要使用配額來追蹤 Pod 的資源使用量,Pod 必須位於使用者命名空間中。在使用者命名空間中,核心會限制對檔案系統上專案 ID 的變更,從而確保配額計算的儲存空間指標的可靠性。
如果您想要使用專案配額,您應該:
使用 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
。
如果您不想使用專案配額,您應該:
- 使用 kubelet 配置中的
featureGates
欄位,停用LocalStorageCapacityIsolationFSQuotaMonitoring
功能閘道。
擴充資源
擴充資源是 kubernetes.io
網域之外的完全限定資源名稱。它們允許叢集運營商宣告和使用者使用非 Kubernetes 內建資源。
使用擴充資源需要兩個步驟。首先,叢集運營商必須宣告擴充資源。其次,使用者必須在 Pod 中請求擴充資源。
管理擴充資源
節點層級擴充資源
節點層級擴充資源與節點相關聯。
裝置外掛程式管理的資源
有關如何在每個節點上宣告裝置外掛程式管理的資源,請參閱裝置外掛程式。
其他資源
要宣告新的節點層級擴充資源,叢集運營商可以向 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
叢集層級擴充資源
叢集層級擴充資源與節點無關。它們通常由排程器擴充程式管理,這些擴充程式處理資源消耗和資源配額。
您可以在 排程器配置中指定由排程器擴充程式處理的擴充資源。
範例
排程器策略的以下配置指示叢集層級擴充資源 "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
}
]
}
]
}
消耗擴充資源
使用者可以在 Pod spec 中像 CPU 和記憶體一樣消耗擴充資源。排程器負責資源計費,以便同時分配給 Pod 的數量不超過可用數量。
API 伺服器將擴充資源的數量限制為整數。有效數量的範例為 3
、3000m
和 3Ki
。無效數量的範例為 0.5
和 1500m
(因為 1500m
將導致 1.5
)。
注意
擴充資源取代了不透明整數資源。使用者可以使用kubernetes.io
以外的任何網域名稱前綴,該前綴是保留的。若要在 Pod 中使用擴充資源,請在容器規格的 spec.containers[].resources.limits
映射中加入資源名稱作為鍵值。
注意
擴充資源無法過度配置,因此若容器規格中同時存在 request 和 limit,則兩者必須相等。只有在所有資源請求(包括 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 限制 以取得相關資訊。
疑難排解
我的 Pod 處於 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 處於 pending 狀態並顯示此類訊息,您可以嘗試以下幾種方法
- 將更多節點新增到叢集。
- 終止不需要的 Pod,為 pending 中的 Pod 騰出空間。
- 檢查 Pod 是否大於所有節點。例如,如果所有節點的容量為
cpu: 1
,則請求為cpu: 1.1
的 Pod 永遠不會被排程。 - 檢查節點污點。如果大多數節點都已污損,且新的 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 中,每個節點都有一個 .status.allocatable
欄位(詳情請參閱 NodeStatus)。
.status.allocatable
欄位描述了該節點上 Pod 可用的資源量(例如:15 個虛擬 CPU 和 7538 MiB 的記憶體)。如需 Kubernetes 中節點可分配資源的更多資訊,請參閱 為系統守護進程保留運算資源。
您可以設定 資源配額,以限制命名空間可以消耗的資源總量。當命名空間中存在 ResourceQuota 時,Kubernetes 會對特定命名空間中的物件強制執行配額。例如,如果您將特定命名空間分配給不同的團隊,則可以在這些命名空間中新增 ResourceQuota。設定資源配額有助於防止一個團隊過度使用任何資源,進而影響其他團隊。
您也應該考慮您授予該命名空間的存取權限:完全寫入命名空間的權限允許具有該權限的任何人移除任何資源,包括已設定的 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
原因表示容器嘗試使用的記憶體超過了其限制。
您的下一步可能是檢查應用程式程式碼中是否存在記憶體洩漏。如果您發現應用程式的行為符合您的預期,請考慮為該容器設定更高的記憶體限制(以及可能的請求)。
下一步是什麼
- 取得 為容器和 Pod 分配記憶體資源 的實務經驗。
- 取得 為容器和 Pod 分配 CPU 資源 的實務經驗。
- 閱讀 API 參考資料如何定義 容器 及其 資源需求
- 閱讀有關 XFS 中的 專案配額
- 閱讀更多關於 kube-scheduler 設定參考資料 (v1)
- 閱讀更多關於 Pod 的服務品質類別