為容器和 Pod 分配記憶體資源

本頁面演示瞭如何為容器分配記憶體**請求(request)**和記憶體**限制(limit)**。 容器被保證擁有其請求的記憶體量,但不允許使用超過其限制的記憶體。

準備工作

你必須擁有一個 Kubernetes 叢集,並且 kubectl 命令列工具必須配置為與你的叢集通訊。建議在至少有兩個不作為控制平面主機的節點的叢集上執行本教程。如果你還沒有叢集,可以使用 minikube 建立一個,或者使用這些 Kubernetes 遊樂場之一。

要檢查版本,請輸入 kubectl version

你的叢集中的每個節點必須至少有 300 MiB 記憶體。

本頁面上的幾個步驟需要你在叢集中執行 metrics-server 服務。如果你已經運行了 metrics-server,可以跳過這些步驟。

如果你正在執行 Minikube,請執行以下命令啟用 metrics-server:

minikube addons enable metrics-server

要檢視 metrics-server 或其他資源指標 API (metrics.k8s.io) 提供程式是否正在執行,請執行以下命令:

kubectl get apiservices

如果資源指標 API 可用,輸出中將包含對 metrics.k8s.io 的引用。

NAME
v1beta1.metrics.k8s.io

建立名稱空間

建立一個名稱空間,以便你在本練習中建立的資源與叢集的其餘部分隔離。

kubectl create namespace mem-example

指定記憶體請求和記憶體限制

要為容器指定記憶體請求,請在容器的資源清單中包含 resources:requests 欄位。要指定記憶體限制,請包含 resources:limits

在這個練習中,你將建立一個包含一個容器的 Pod。該容器的記憶體請求為 100 MiB,記憶體限制為 200 MiB。以下是 Pod 的配置檔案:

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo
  namespace: mem-example
spec:
  containers:
  - name: memory-demo-ctr
    image: polinux/stress
    resources:
      requests:
        memory: "100Mi"
      limits:
        memory: "200Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]

配置檔案的 args 部分為容器啟動時提供引數。 "--vm-bytes", "150M" 引數告訴容器嘗試分配 150 MiB 記憶體。

建立 Pod

kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit.yaml --namespace=mem-example

驗證 Pod 容器是否正在執行

kubectl get pod memory-demo --namespace=mem-example

檢視 Pod 的詳細資訊

kubectl get pod memory-demo --output=yaml --namespace=mem-example

輸出顯示 Pod 中的一個容器的記憶體請求為 100 MiB,記憶體限制為 200 MiB。

...
resources:
  requests:
    memory: 100Mi
  limits:
    memory: 200Mi
...

執行 kubectl top 來獲取 Pod 的指標。

kubectl top pod memory-demo --namespace=mem-example

輸出顯示 Pod 正在使用大約 162,900,000 位元組的記憶體,大約是 150 MiB。 這超出了 Pod 的 100 MiB 請求,但在 Pod 的 200 MiB 限制之內。

NAME                        CPU(cores)   MEMORY(bytes)
memory-demo                 <something>  162856960

刪除你的 Pod

kubectl delete pod memory-demo --namespace=mem-example

超出容器的記憶體限制

如果節點有可用記憶體,容器可以使用超過其記憶體請求的記憶體。但容器不允許使用超過其記憶體限制的記憶體。如果容器分配的記憶體超過其限制,該容器將成為終止的候選物件。如果容器繼續消耗記憶體超出其限制,該容器將被終止。如果已終止的容器可以重新啟動,kubelet 會像處理任何其他型別的執行時故障一樣重新啟動它。

在此練習中,你將建立一個 Pod,它嘗試分配超出其記憶體限制的記憶體。以下是包含一個容器的 Pod 的配置檔案,該容器的記憶體請求為 50 MiB,記憶體限制為 100 MiB:

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo-2
  namespace: mem-example
spec:
  containers:
  - name: memory-demo-2-ctr
    image: polinux/stress
    resources:
      requests:
        memory: "50Mi"
      limits:
        memory: "100Mi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "250M", "--vm-hang", "1"]

在配置檔案的 args 部分,你可以看到容器將嘗試分配 250 MiB 的記憶體,這遠高於 100 MiB 的限制。

建立 Pod

kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-2.yaml --namespace=mem-example

檢視 Pod 的詳細資訊

kubectl get pod memory-demo-2 --namespace=mem-example

此時,容器可能正在執行或已被殺死。重複執行前面的命令,直到容器被殺死。

NAME            READY     STATUS      RESTARTS   AGE
memory-demo-2   0/1       OOMKilled   1          24s

獲取容器狀態的更詳細檢視

kubectl get pod memory-demo-2 --output=yaml --namespace=mem-example

輸出顯示容器因記憶體不足 (OOM) 而被殺死。

lastState:
   terminated:
     containerID: 65183c1877aaec2e8427bc95609cc52677a454b56fcb24340dbd22917c23b10f
     exitCode: 137
     finishedAt: 2017-06-20T20:52:19Z
     reason: OOMKilled
     startedAt: null

此練習中的容器可以重新啟動,因此 kubelet 會重新啟動它。多次重複此命令,可以看到容器被反覆殺死和重新啟動。

kubectl get pod memory-demo-2 --namespace=mem-example

輸出顯示容器被殺死、重新啟動、再次被殺死、再次重新啟動等等。

kubectl get pod memory-demo-2 --namespace=mem-example
NAME            READY     STATUS      RESTARTS   AGE
memory-demo-2   0/1       OOMKilled   1          37s

kubectl get pod memory-demo-2 --namespace=mem-example
NAME            READY     STATUS    RESTARTS   AGE
memory-demo-2   1/1       Running   2          40s

檢視 Pod 歷史記錄的詳細資訊

kubectl describe pod memory-demo-2 --namespace=mem-example

輸出顯示容器反覆啟動和失敗。

... Normal  Created   Created container with id 66a3a20aa7980e61be4922780bf9d24d1a1d8b7395c09861225b0eba1b1f8511
... Warning BackOff   Back-off restarting failed container

檢視叢集節點詳細資訊

kubectl describe nodes

輸出包含容器因記憶體不足而被殺死的記錄。

Warning OOMKilling Memory cgroup out of memory: Kill process 4481 (stress) score 1994 or sacrifice child

刪除你的 Pod

kubectl delete pod memory-demo-2 --namespace=mem-example

指定一個對於你的節點來說太大的記憶體請求

記憶體請求和限制與容器關聯,但將 Pod 視為具有記憶體請求和限制是有用的。 Pod 的記憶體請求是 Pod 中所有容器的記憶體請求之和。同樣,Pod 的記憶體限制是 Pod 中所有容器的限制之和。

Pod 排程基於請求。Pod 只有在節點有足夠的可用記憶體來滿足 Pod 的記憶體請求時才會被排程到該節點上執行。

在此練習中,你將建立一個 Pod,其記憶體請求量過大,超出了叢集中任何節點的容量。以下是包含一個容器的 Pod 的配置檔案,該容器請求 1000 GiB 的記憶體,這可能超出了叢集中任何節點的容量。

apiVersion: v1
kind: Pod
metadata:
  name: memory-demo-3
  namespace: mem-example
spec:
  containers:
  - name: memory-demo-3-ctr
    image: polinux/stress
    resources:
      requests:
        memory: "1000Gi"
      limits:
        memory: "1000Gi"
    command: ["stress"]
    args: ["--vm", "1", "--vm-bytes", "150M", "--vm-hang", "1"]

建立 Pod

kubectl apply -f https://k8s.io/examples/pods/resource/memory-request-limit-3.yaml --namespace=mem-example

檢視 Pod 狀態

kubectl get pod memory-demo-3 --namespace=mem-example

輸出顯示 Pod 狀態為 PENDING。也就是說,Pod 未被排程到任何節點上執行,並且它將無限期地保持 PENDING 狀態。

kubectl get pod memory-demo-3 --namespace=mem-example
NAME            READY     STATUS    RESTARTS   AGE
memory-demo-3   0/1       Pending   0          25s

檢視 Pod 的詳細資訊,包括事件

kubectl describe pod memory-demo-3 --namespace=mem-example

輸出顯示由於節點記憶體不足,容器無法被排程。

Events:
  ...  Reason            Message
       ------            -------
  ...  FailedScheduling  No nodes are available that match all of the following predicates:: Insufficient memory (3).

記憶體單位

記憶體資源以位元組為單位進行測量。你可以將記憶體表示為純整數或帶有以下字尾之一的定點整數:E、P、T、G、M、K、Ei、Pi、Ti、Gi、Mi、Ki。例如,以下表示大約相同的值:

128974848, 129e6, 129M, 123Mi

刪除你的 Pod

kubectl delete pod memory-demo-3 --namespace=mem-example

如果你未指定記憶體限制

如果你未為容器指定記憶體限制,則適用以下情況之一:

  • 容器使用的記憶體量沒有上限。容器可以使用它正在執行的節點上所有可用的記憶體,這反過來可能會觸發 OOM Killer。此外,在 OOM Killer 的情況下,沒有資源限制的容器被殺死的機率更大。

  • 容器執行在一個具有預設記憶體限制的名稱空間中,容器會自動被分配預設限制。叢集管理員可以使用 LimitRange 來指定記憶體限制的預設值。

記憶體請求和限制的動機

透過為叢集中執行的容器配置記憶體請求和限制,你可以高效利用叢集節點上可用的記憶體資源。透過將 Pod 的記憶體請求設定得較低,可以提高 Pod 被排程的機會。透過將記憶體限制設定為大於記憶體請求,你可以實現兩個目的:

  • Pod 可以突發活動,利用恰好可用的記憶體。
  • Pod 在突發期間可以使用的記憶體量被限制在合理的範圍內。

清理

刪除你的名稱空間。這將刪除你為該任務建立的所有 Pod。

kubectl delete namespace mem-example

下一步

致應用開發者

致叢集管理員

上次修改時間:2025 年 4 月 7 日上午 9:46 (PST):更新 v1.33 beta 的 InPlacePodVerticalScaling 文件 (#50290) (c014f72fbb)