為容器和 Pod 指派記憶體資源

此頁面說明如何為容器指派記憶體請求和記憶體限制。容器保證擁有其請求的記憶體量,但不允許使用超過其限制的記憶體。

開始之前

您需要有一個 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 的組態檔,該 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

輸出顯示 Container 反覆啟動又失敗

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

檢視關於您的叢集節點的詳細資訊

kubectl describe nodes

輸出包含 Container 因為記憶體不足而被終止的記錄

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

指定一個對您的節點來說過大的記憶體請求

記憶體請求和限制與 Container 相關聯,但將 Pod 視為具有記憶體請求和限制會很有幫助。Pod 的記憶體請求是 Pod 中所有 Container 的記憶體請求總和。同樣地,Pod 的記憶體限制是 Pod 中所有 Container 的限制總和。

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

在本練習中,您將建立一個 Pod,其記憶體請求非常大,以至於超出叢集中任何節點的容量。以下是一個 Pod 的組態檔,該 Pod 有一個 Container,請求 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

輸出顯示因為節點上的記憶體不足,Container 無法被排程

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

如果您未指定記憶體限制

如果您未為 Container 指定記憶體限制,則適用以下情況之一

  • Container 對其使用的記憶體量沒有上限。Container 可能會使用在其運行的節點上可用的所有記憶體,這反過來可能會調用 OOM Killer。此外,在發生 OOM Kill 的情況下,沒有資源限制的 Container 將更有可能被終止。

  • Container 正在具有預設記憶體限制的命名空間中運行,並且 Container 會自動被分配預設限制。叢集管理員可以使用 LimitRange 來指定記憶體限制的預設值。

記憶體請求和限制的動機

透過為在您的叢集中運行的 Container 配置記憶體請求和限制,您可以有效利用叢集節點上可用的記憶體資源。透過保持 Pod 的記憶體請求較低,您可以讓 Pod 有很好的排程機會。透過設定大於記憶體請求的記憶體限制,您可以達成兩件事

  • Pod 可以有活動爆發期,在此期間它可以利用碰巧可用的記憶體。
  • Pod 在爆發期間可以使用的記憶體量被限制在合理的範圍內。

清理

刪除您的命名空間。這會刪除您為此任務建立的所有 Pod

kubectl delete namespace mem-example

接下來是什麼

給應用程式開發人員

給叢集管理員

最後修改時間:2024 年 10 月 30 日下午 5:17 PST:KEP 2837: Pod Level Resources Alpha (0374213f57)