1. 程式人生 > 其它 >【K8s概念】為容器管理資源

【K8s概念】為容器管理資源

參考:https://kubernetes.io/zh/docs/concepts/configuration/manage-resources-containers/

下面是個例子

以下 Pod 有兩個 Container。每個 Container 的請求為 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
    env:
    - name: MYSQL_ROOT_PASSWORD
      value: "password"
    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 如何排程

當你建立一個 Pod 時,Kubernetes 排程程式將為 Pod 選擇一個節點。 每個節點對每種資源型別都有一個容量上限:可為 Pod 提供的 CPU 和記憶體量。 排程程式確保對於每種資源型別,所排程的容器的資源請求的總和小於節點的容量。 請注意,儘管節點上的實際記憶體或 CPU 資源使用量非常低,如果容量檢查失敗, 排程程式仍會拒絕在該節點上放置 Pod。 當稍後節點上資源用量增加,例如到達請求率的每日峰值區間時,節點上也不會出現資源不足的問題。

帶資源約束的 Pod 如何執行

當 kubelet 啟動 Pod 中的 Container 時,它會將 CPU 和記憶體約束資訊傳遞給容器執行時。

當使用 Docker 時:

  • spec.containers[].resources.requests.cpu 先被轉換為可能是小數的基礎值,再乘以 1024。 這個數值和 2 的較大者用作 docker run 命令中的 --cpu-shares 標誌的值。

  • spec.containers[].resources.limits.cpu 先被轉換為 millicore 值,再乘以 100。 其結果就是每 100 毫秒內容器可以使用的 CPU 時間總量。在此期間(100ms),容器所使用的 CPU 時間不會超過它被分配的時間。

說明: 預設的配額(Quota)週期為 100 毫秒。CPU 配額的最小精度為 1 毫秒。

  • spec.containers[].resources.limits.memory 被轉換為整數值,作為 docker run 命令中的 --memory 引數值。

如果 Container 超過其記憶體限制,則可能會被終止。如果容器可重新啟動,則與所有其他型別的 執行時失效一樣,kubelet 將重新啟動容器。

如果一個 Container 記憶體用量超過其記憶體請求值,那麼當節點記憶體不足時,容器所處的 Pod 可能被逐出。

每個 Container 可能被允許也可能不被允許使用超過其 CPU 約束的處理時間。 但是,容器不會由於 CPU 使用率過高而被殺死。

要確定 Container 是否會由於資源約束而無法排程或被殺死,請參閱疑難解答 部分。

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

Pod 的資源使用情況是作為 Pod 狀態的一部分來報告的。

如果為叢集配置了可選的 監控工具, 則可以直接從 指標 API 或者監控工具獲得 Pod 的資源使用情況。

為本地臨時性儲存設定請求和約束值

你可以使用 ephemeral-storage 來管理本地臨時性儲存。 Pod 中的每個 Container 可以設定以下屬性:

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

ephemeral-storage 的請求和約束值是按位元組計量的。你可以使用一般整數或者定點數字 加上下面的字尾來表達儲存量:E、P、T、G、M、K。 你也可以使用對應的 2 的冪級數來表達:Ei、Pi、Ti、Gi、Mi、Ki。 例如,下面的表示式所表達的大致是同一個值:

128974848, 129e6, 129M, 123Mi

在下面的例子中,Pod 包含兩個 Container。每個 Container 請求 2 GiB 大小的本地臨時性儲存。 每個 Container 都設定了 4 GiB 作為其本地臨時性儲存的約束值。 因此,整個 Pod 的本地臨時性儲存請求是 4 GiB,且其本地臨時性儲存的約束為 8 GiB。

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"
  - name: log-aggregator
    image: images.my-company.example/log-aggregator:v6
    resources:
      requests:
        ephemeral-storage: "2Gi"
      limits:
        ephemeral-storage: "4Gi"

帶臨時性儲存的 Pods 的排程行為

當你建立一個 Pod 時,Kubernetes 排程器會為 Pod 選擇一個節點來執行之。 每個節點都有一個本地臨時性儲存的上限,是其可提供給 Pods 使用的總量。 欲瞭解更多資訊,可參考 節點可分配資源 節。

排程器會確保所排程的 Containers 的資源請求總和不會超出節點的資源容量。

臨時性儲存消耗的管理

如果 kubelet 將本地臨時性儲存作為資源來管理,則 kubelet 會度量以下各處的儲存用量:

emptyDir 卷,除了 tmpfs emptyDir 卷
儲存節點層面日誌的目錄
可寫入的容器映象層

如果某 Pod 的臨時儲存用量超出了你所允許的範圍,kubelet 會向其發出逐出(eviction)訊號,觸發該 Pod 被逐出所在節點。

就容器層面的隔離而言,如果某容器的可寫入映象層和日誌用量超出其儲存約束, kubelet 也會將所在的 Pod 標記為逐出候選。

就 Pod 層面的隔離而言,kubelet 會將 Pod 中所有容器的約束值相加,得到 Pod 儲存約束的總值。如果所有容器的本地臨時性儲存用量總和加上 Pod 的 emptyDir 卷的用量超出 Pod 儲存約束值,kubelet 也會將該 Pod 標記為逐出候選。

注意:
如果 kubelet 沒有度量本地臨時性儲存的用量,即使 Pod 的本地儲存用量超出其約束值也不會被逐出。
不過,如果用於可寫入容器映象層、節點層面日誌或者 emptyDir 卷的檔案系統中可用空間太少, 節點會為自身設定本地儲存不足的汙點 標籤。 這一汙點會觸發對那些無法容忍該汙點的 Pods 的逐出操作。
關於臨時性本地儲存的配置資訊,請參考這裡

PID 限制

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

疑難解答

我的 Pod 處於懸決狀態且事件資訊顯示 failedScheduling

如果排程器找不到該 Pod 可以匹配的任何節點,則該 Pod 將保持未被排程狀態, 直到找到一個可以被排程到的位置。每當排程器找不到 Pod 可以排程的地方時, 會產生一個事件,如下所示:

kubectl describe pod frontend | grep -A 3 Events
Events:
  FirstSeen LastSeen   Count  From          Subobject        PathReason        Message
  36s       5s         6      {scheduler}  FailedScheduling  Failed for reason PodExceedsFreeCPU and possibly others

在上述示例中,由於節點上的 CPU 資源不足,名為 “frontend” 的 Pod 無法被排程。 由於記憶體不足(PodExceedsFreeMemory)而導致失敗時,也有類似的錯誤訊息。 一般來說,如果 Pod 處於懸決狀態且有這種型別的訊息時,你可以嘗試如下幾件事情:

向叢集新增更多節點。
終止不需要的 Pod,為懸決的 Pod 騰出空間。
檢查 Pod 所需的資源是否超出所有節點的資源容量。例如,如果所有節點的容量都是cpu:1, 那麼一個請求為 cpu: 1.1 的 Pod 永遠不會被排程。

你可以使用 kubectl describe nodes 命令檢查節點容量和已分配的資源數量。 例如:

kubectl describe nodes e2e-test-node-pool-4lw4
Name:            e2e-test-node-pool-4lw4
[ ... 這裡忽略了若干行以便閱讀 ...]
Capacity:
 cpu:                               2
 memory:                            7679792Ki
 pods:                              110
Allocatable:
 cpu:                               1800m
 memory:                            7474992Ki
 pods:                              110
[ ... 這裡忽略了若干行以便閱讀 ...]
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 (12%)        1070Mi (14%)

在上面的輸出中,你可以看到如果 Pod 請求超過 1120m CPU 或者 6.23Gi 記憶體,節點將無法滿足。

通過檢視 Pods 部分,你將看到哪些 Pod 佔用了節點上的資源。

可供 Pod 使用的資源量小於節點容量,因為系統守護程式也會使用一部分可用資源。 NodeStatus 的 allocatable 欄位給出了可用於 Pod 的資源量。 有關更多資訊,請參閱 節點可分配資源。

可以配置 資源配額 功能特性 以限制可以使用的資源總量。 如果與名字空間配合一起使用,就可以防止一個團隊佔用所有資源。

我的容器被終止了

你的容器可能因為資源緊張而被終止。要檢視容器是否因為遇到資源限制而被殺死, 請針對相關的 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
Replication Controllers:        simmemleak (1/1 replicas created)
Containers:
  simmemleak:
    Image:  saadali/simmemleak
    Limits:
      cpu:                      100m
      memory:                   50Mi
    State:                      Running
      Started:                  Tue, 07 Jul 2015 12:54:41 -0700
    Last Termination State:     Terminated
      Exit Code:                1
      Started:                  Fri, 07 Jul 2015 12:54:30 -0700
      Finished:                 Fri, 07 Jul 2015 12:54:33 -0700
    Ready:                      False
    Restart Count:              5
Conditions:
  Type      Status
  Ready     False
Events:
  FirstSeen                         LastSeen                         Count  From                              SubobjectPath                       Reason      Message
  Tue, 07 Jul 2015 12:53:51 -0700   Tue, 07 Jul 2015 12:53:51 -0700  1      {scheduler }                                                          scheduled   Successfully assigned simmemleak-hra99 to kubernetes-node-tf0f
  Tue, 07 Jul 2015 12:53:51 -0700   Tue, 07 Jul 2015 12:53:51 -0700  1      {kubelet kubernetes-node-tf0f}    implicitly required container POD   pulled      Pod container image "k8s.gcr.io/pause:0.8.0" already present on machine
  Tue, 07 Jul 2015 12:53:51 -0700   Tue, 07 Jul 2015 12:53:51 -0700  1      {kubelet kubernetes-node-tf0f}    implicitly required container POD   created     Created with docker id 6a41280f516d
  Tue, 07 Jul 2015 12:53:51 -0700   Tue, 07 Jul 2015 12:53:51 -0700  1      {kubelet kubernetes-node-tf0f}    implicitly required container POD   started     Started with docker id 6a41280f516d
  Tue, 07 Jul 2015 12:53:51 -0700   Tue, 07 Jul 2015 12:53:51 -0700  1      {kubelet kubernetes-node-tf0f}    spec.containers{simmemleak}         created     Created with docker id 87348f12526a

在上面的例子中,Restart Count: 5 意味著 Pod 中的 simmemleak 容器被終止並重啟了五次。

你可以使用 kubectl get pod 命令加上 -o go-template=... 選項來獲取之前終止容器的狀態。

kubectl get pod -o go-template='{{range.status.containerStatuses}}{{"Container Name: "}}{{.name}}{{"\r\nLastState: "}}{{.lastState}}{{end}}'  simmemleak-hra99
Container Name: simmemleak
LastState: map[terminated:map[exitCode:137 reason:OOM Killed startedAt:2015-07-07T20:58:43Z finishedAt:2015-07-07T20:58:43Z containerID:docker://0e4095bba1feccdfe7ef9fb6ebffe972b4b14285d5acdec6f0d3ae8a22fad8b2]]

你可以看到容器因為 reason:OOM killed 而被終止,OOM 表示記憶體不足(Out Of Memory)。

作者:Varden 出處:http://www.cnblogs.com/varden/ 本文內容如有雷同,請聯絡作者! 本文版權歸作者和部落格園共有,歡迎轉載,但未經作者同意必須保留此段宣告,且在文章頁面明顯位置給出原文連線,否則保留追究法律責任的權利。