Kubernetes - Resources Limit

概述

哈囉! 本篇來介紹 Kubernetes 中的 Compute Resource。 接下來要介紹的可不是一般的 Resource, 像是元件那些, 而是可計算資源。
簡單來說, 我們在定義 Pod 的時候, 可以定義啟動這個 Pod 需要多少資源, 以及這個 Pod 最多可以使用多少資源, 這樣夠淺顯易懂吧! 下面就是詳細介紹了。

當你指定一個 Pod, 你可以選擇性的指定每個容器需要多少 CPU 以及 memory (RAM), 當你有指定 資源要求 (resource request) 給容器, scheduler 可以更加的分配 Pods 到 nodes 上。 而當你有指定容器的 資源限制 (resource limits), 在 node 上的資源競爭將以指定的方式來處理。 更多 requests 以及 limits 的不同之處可以參考 Resource QoS




資源類型

CPU 以及 memory 為 資源類型 (resource type), 資源類型有其基本單位。 CPU 以 cores 為單位, 而 memory 以 bytes 為單位。 如果你使用的是 Kubernetes v1.14 或更新的版本, 你可以指定 巨頁 (huge page) 資源。 Huge pages 是 Linux 上特定的功能, node 的 kernel 可以分配比預設 page 更大的 memory。
比如說, 在預設 page 大小為 4KiB 的系統, 你可以指定一個限制, hugepages-2Mi: 80Mi。 如果容器試圖分配超過 40 2MiB huge pages (總共 80MiB), 則分配將失敗。
Ray 第一次聽到 Huge Page 的概念時也是 一臉矇逼, 不過本著學習者的心態 Google 了幾下之後, 就不再那麼矇了。
簡單來說, memory 有過被管理的單位叫做 頁 (page), 在很多系統中預設是 4Ki, 所以 1Mi 的 memory 就有 256 pages, 沒問題吧? 而有個硬體叫做 TLB (Translation Lookaside Buffer), 它是個大小固定的緩存硬體, 而虛擬記憶體對應實體記憶體的 mapping 會緩存 TLB 上。簡單來說, 如果是使用 4Ki 為 page 為單位的話, 那就要有很多 page, 而越多 page 記憶體的位置就需要越大的緩存去管理, 偏偏 TLB 這東西又是固定大小, 所以能怎麼做? 那自然就是加大 page 的大小, 讓總 page 的數量下降, 這樣緩存就不需要那麼大的空間來記住那麼多的記憶體位置了。 這便是 huge page 的簡單概念, 更詳細一點的資料可以參考 這篇文章

注意: 跟 memory 以及 cpu 資源不同, 你無法過量使用 hugepages-* 資源

CPU 以及 memory 都被歸類在 compute resources, 或 resources。 Compute resources 為可被要求, 分配, 以及消耗的可量測數量。 他們與 [API resources] 不同。 API resources, 像是 Pod 以及 Services 為可通過 Kubernetes API server 讀取以及修改的物件。




Pod 以及 Container 的資源要求以及資源限制

每個 Container 或 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>

儘管 requests 以及 limits 只可被指定再單獨的 Container 上, 但要計算出 Pod 的 request 以及 limits 也很方便。 Pod 對某項特定資源的 request/limit 就等於該 Pod 裡的所有容器的 request/limit 總和。




CPU 解釋

CPU 資源的 limits 以及 requests 都以 cpu 為單位衡量。 1 cpu, 在 Kubernetes 中, 相當於以下單位:

  • 1 AWS vCPU
  • 1 GCP Core
  • 1 Azure vCore
  • 1 IBM vCPU
  • 1 Hyperthread, Hyperthreading 的 Intel bare-metal 處理器

小數的資源請求是容許的。 spec.container[].resources.requests.cpu 如果設為 0.5, 那相當於要求 1 CPU 的一半。 0.1 相等於 100m, 100m 也可讀為 “100 millicpu”。 有些人說 “100 millicores”, 都可理解為同樣的東西。 有小數點的請求, 像是 0.1, 會被 API 轉換到 100m, 而精度最小為 1m, 所以設定 100m 會是比較理想的

CPU 都是絕對數字, 不會是相對數字; 舉例來說, 0.1 在 1-core, 2-core, 或 48-core 的機器中代表的量都是一樣的。




Memory 解釋

Memory 中的 limits 以及 requests 資源管理以 bytes 為單位。 記憶體可被表示為簡單的 integer, 或固定位數的 integer, 可使用以下後綴: E, P, T, G, M, K 。 你也可以使用: Ei, Pi, Ti, Gi, Mi, Ki, 舉例來說, 下面都代表大約相同的值:

128974848, 129e6, 129M, 123Mi

這邊有個範例, 下面的 Pod 含有兩個容器。 每個容器都有 resource requests, 0.25 cpu 以及 64MiB 記憶體。 每個容器都有 resource limits 0.5 cpu 以及 128 MiB 記憶體。 可以說, 這個 Pod 有 resource requests 0.5 cpu 以及 128 MiB 記憶體, resource limits 1 cpu 以及 256 MiB 記憶體

apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: db
image: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "password"
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"
- name: wp
image: wordpress
resources:
requests:
memory: "64Mi"
cpu: "250m"
limits:
memory: "128Mi"
cpu: "500m"




有 resource requests 的 Pod 是被如何調度的?

當你建立 Pod, Kubernetes scheduler 會挑選一個 node 來運行該 Pod。 每個 node 針對每種資源類型都有最大容量: 也就是說, 有多少 CPU 以及 memory 可以分配給 Pods。 Scheduler 會確保被調度的容器的各類型資源總和會小於該 Node 的資源總量。 注意到, 就算 node 上的資源使用量非常低, 如果容量確認沒過的話, Scheduler 還是不會分配 Pod 到這個 node 上。 這確保在 node 上資源短缺, 比如說, 在每日的資源用量高峰。




有 resource limits 的 Pod 是如何被調度?

當 Kubelet 啟動 Pod 中的一個 Container, 它會將 CPU 以及 memory limits 帶入到該 container runtime。
當使用 Docker:

  • spec.containers[].resources.requests.cpu 會被轉換成 core 值, 它可能會是有小數點的, 以及會被乘以 1024。 在 docker run 指令中使用 --cpu-shares, 可以設定比這更高的數字或 2
  • spec.containers[].resources.limits.cpu 會被轉換成 millicore 值以及乘以 100。 結果值為容器在每 100ms (也就是十分之一秒)的 CPU time 中可使用的總量, 容器無法使用超過被分到的 CPU 配額, 這個部分如果看不是很懂, 有興趣的話最下面會有補充說明。
    注意: 預設的 quota period 為 100ms, 最小為 1ms
  • spec.containers[].resources.limits.memory 會被轉換成 integer, 如同 docker run 指令的 [--memory] flag 的效果

如果容器超出了其 memory limits 限制, 它會被終止。 如果它設置為可重啟, 跟其他的 runtime failure 一樣, kubelet 將會重啟它。
如果容器超出了其 memory request 限制, 當 node memory 耗光了之後, 就會把該 Pod 砍了, Ray 看到這一段的時候也有點矇逼, 下面會再補充解釋!
容器可能會或者可能不會被允許超出其 CPU limit 限制, 然而, 超出了也不會被砍了。
要得知容器是否無法被分配, 或者因為資源限制被殺掉了, 可以參考 Troubleshooting 區塊




監控資源使用量

資源使用率會以 Pod 狀態的部分回報




Troubleshooting

容器顯示 pending 以及事件訊息 failedScheduling

如果 Scheduler 在 node 上無法找到足夠的資源來置放 Pod, 這個 Pod 將會持續處於未分配的狀態, 直到 Scheduler 找到足夠的資源。 每次 Scheduler 找不到足夠資源而分配失敗的話, 都會產生一個事件, 就像這樣:

  • 取得事件:

    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

在上面的例子中, 因為 node 的 CPU 資源不足, 所以 Scheduler 無法分配名為 “frontend” 的 Pod。 類似的錯誤訊息也會出現在 memory 不足時 (PodExceedsFreeMemory)。 另外, 如果 Pod 顯示這類型的錯誤訊息, 並卡住, 你可以試試下面的操作:

  • 增加更多的 nodes 到叢集
  • 終止不必要的 Pods, 騰出空間給 pending Pods
  • 確認 Pod 沒有比所有的 nodes 大, 比方說, 如果所有的 Nodes 都有 cpu: 1 的容量, 然後 Pod 的 requests 限制為 cpu: 1.1, 那這個 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 (12%) 1070Mi (14%)

從上面的輸出可以看到, Allocatable 就是可分配的資源, 而 Allocated resources 就是已經分配出去的資源, 所以如果 Pod 被定義 requests 限制超過 1120m CPUs, 或 6.23Gi memory, 那這個 Pod 將無法被分配在這個 node, 因為資源不足啊!

Pods 區塊中可以看到每個 Pod 各使用了這個 node 多少的資源。

Pod 可用的資源總量小於該 node 的 capacity, 因為系統 daemons 使用了一部分的可用資源。 allocatable 欄位 NodeStatus 提供了可分配給 Pods 的資源。 更多資訊, 可參考 Node Allocatable Resources

resource quota 功能可用來設置資源可被消耗的最大限制。 如果使用在 namespaces 上, 那可以有效防止一個團隊佔據了所有的資源。


容器被終止

容器可能會因為資源耗盡而被終止。 若要確認容器是否有因為達到資源限制而被殺掉, 使用 kubectl describe pod PodName

  • 執行指令

    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

上面的 example 中, Restart Count: 5 顯示容器 simmemleak 容器已被終止並重啟五次

你可以呼叫 kubectl get pod 以及 option -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




Local ephemeral storage

FEATURE STATE: kubernetes v1.17
kubernetes 版本 1.8 介紹了一個新的資源, 用來管理本地臨時儲存空間的 ephemeral-storage。 在每一個 node 中, kubelet 的 root 資料夾 (預設 /var/lib/kubelet) 以及 log 資料夾 (預設 /var/log) 都被儲存在 root 分區。 這個分區同時也經由 emptyDir volumes, container logs, image layers 以及 container writable layers 被 Pods 共享

本地臨時儲存區的 Requests 以及 Limits 資源限制設定

每個 Pod 中的容器都可以指定一個或多個以下的限制:

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

ephemeral-storage 的 limits 以及 requests 資源管理以 bytes 為單位。 儲存區可被表示為簡單的 integer, 或固定位數的 integer, 可使用以下後綴: E, P, T, G, M, K 。 你也可以使用: Ei, Pi, Ti, Gi, Mi, Ki, 舉例來說, 下面都代表大約相同的值:

128974848, 129e6, 129M, 123Mi

舉例來說, 以下的 Pod 有兩個容器。 每個容器都有 2 GiB 的 本地臨時儲存區 request 限制, 而每個容器都有 4GiB 的本地臨時儲存區 limit 限制。 因此, 這個 Pod 有 4GiB 的本地臨時儲存 request 限制以及 8GiB 的 limit 限制

apiVersion: v1
kind: Pod
metadata:
name: frontend
spec:
containers:
- name: db
image: mysql
env:
- name: MYSQL_ROOT_PASSWORD
value: "password"
resources:
requests:
ephemeral-storage: "2Gi"
limits:
ephemeral-storage: "4Gi"
- name: wp
image: wordpress
resources:
requests:
ephemeral-storage: "2Gi"
limits:
ephemeral-storage: "4Gi"


有 ephemeral-storage request 限制的 Pod 是如何被分配的?

當建立一個 Pod 時, Kubernetes scheduler 會挑選 node 來運行該 Pod。 每個 node 都有 local ephemeral storage 可提供給 Pods 的最大值。 更多資訊可參考 Node Allocatable

Scheduler 會確保被分配的容器的 request 限制小於 node 的容量


有 ephemeral-storage limit 限制的 Pod 是如何被分配的?

從容器等級隔離層面來說, 如果容器的可寫層 (writable layer) 以及 logs 使用量超過了儲存限制, 那們 Pod 會被殺掉。 從 Pod 等級隔離層面來說, 如果該 Pod 內的容器 ephemeral storage 使用量超過了限制, 以及該 Pods 的 emptyDir volumes 超過了限制, 該 Pod 也會被殺掉。

官方文件就先到這裡, 以下為針對 Memory 以及 CPU 的進一步分析




頗析 (Memory)

首先, 先針對 memory 的部分來頗析 limits 跟 requests 的詳細運作

建立一個沒有資源限制的 pod

  • 輸入

    kubectl run limit-test --image=busybox --command -- /bin/sh -c "while true; do     sleep 2; done"
  • 輸出

    deployment.apps "limit-test" created

使用 Kubectl 來驗證看看 Kubernetes 是否建立沒有資源限制的 pod

  • 輸入

    kubectl get pods limit-test-7cff9996fc-zpjps -o=jsonpath='{.spec.containers[0]    .resources}'
  • 輸出

    map[]

現在我們 ssh 到該 node, 然後使用以下指令看看 docker 是如何運行這個容器

  • 輸入以下指令取得容器名稱

    docker ps | grep busy | cut -d' ' -f1
  • 得到容器名稱

    5c3af3101afb
  • 輸入指令取得容器限制的 memory value

    docker inspect 5c3af3101afb -f "{{.HostConfig.Memory}}"
  • 得到輸出

    0
  • .HostConfig.Memory 代表的意思是?
    對應到 docker run–memory 參數

讓我們繼續往下追, 追到最終的 cgroup

  • 取得容器 pid

    ps ax | grep /bin/sh
  • 輸出

    9513 ?        Ss     0:00 /bin/sh -c while true; do sleep 2; done
  • 取得該 pid cgroup

    sudo cat /proc/9513/cgroup
  • 輸出

    ...
    6:memory:/kubepods/burstable/podfbc202d3-da21-11e8-ab5e-42010a80014b/0a1b22ec1361a97c3511db37a4bae932d41b22264e5b97611748f8b662312574
    • (1)kubepods: 程序將會繼承所有這個 group 中的屬性
    • (2)burstable: 可參考burstable QOS class
  • 取得細節, 將上面的路徑 append 到 /sys/fs/cgroups/memory

    ls -l /sys/fs/cgroup/memory/kubepods/burstable/podfbc202d3-da21-11e8-ab5e-42010a80014b/0a1b22ec1361a97c3511db37a4bae932d41b22264e5b97611748f8b662312574
  • 輸出

    ...
    -rw-r--r-- 1 root root 0 Oct 27 19:53 memory.limit_in_bytes
    -rw-r--r-- 1 root root 0 Oct 27 19:53 memory.soft_limit_in_bytes

先來看 memory.limit_in_bytes, 這是設定 memory limit 的 cgroup, 他等同於 docker 裡頭的 --memory, 以及 Kubernetes 限制的 memory limit

  • 輸入以下指令取得數值

    sudo cat /sys/fs/cgroup/memory/kubepods/burstable/podfbc202d3-da21-11e8-ab5e-42010a80014b/0a1b22ec1361a97c3511db37a4bae932d41b22264e5b97611748f8b662312574/memory.limit_in_bytes
  • 輸出

    9223372036854771712

這個數據代表沒有限制 memory, 可參考 Stackoverflow
我們一開始在 Kubernetes 沒有設定 memory 限制, 導致 docker 建立一個 HostConfig.Memory 設定為 0 的容器, 最終導致這個容器的程序被放到 memory.limit_in_bytes 屬性設為 “no limit” 的 memory cgroup

現在讓我們來建立另外一個 pod, 限制 memory limit 為 100Mi

  • 執行以下指令

    kubectl run limit-test --image=busybox --limits "memory=100Mi" --command -- /bin/sh -c "while true; do sleep 2; done"
  • 輸出

    deployment.apps "limit-test" created

驗證這個 pod 有被設置特定的 limit

  • 執行以下指令

    kubectl get pods limit-test-5f5c7dc87d-8qtdx -o=jsonpath='{.spec.containers[0].resources}'
  • 輸出

    map[limits:map[memory:100Mi] requests:map[memory:100Mi]]

這邊可以看到, 如果我們有設置 limits resource, 但是沒設置 requests resource 的時候, Kubernetes 預設將 requests 設為 limits

取得容器 id

  • 執行以下指令

    docker ps | grep busy | cut -d' ' -f1
  • 輸出

    8fec6c7b6119

取得容器 pid

  • 輸入以下指令

    ps ax | grep /bin/sh
  • 輸出

    29532 ?      Ss     0:00 /bin/sh -c while true; do sleep 2; done

取得該容器的 memory cgroup

  • 輸入以下指令

    sudo cat /proc/29532/cgroup
  • 輸出

    ...
    6:memory:/kubepods/burstable/pod88f89108-daf7-11e8-b1e1-42010a800070/8fec6c7b61190e74cd9f88286181dd5fa3bbf9cf33c947574eb61462bc254d11

印出 memory cgroup 中的 memory.limit_in_bytes 數值

  • 輸入以下指令

    sudo cat /sys/fs/cgroup/memory/kubepods/burstable/pod88f89108-daf7-11e8-b1e1-42010a800070/8fec6c7b61190e74cd9f88286181dd5fa3bbf9cf33c947574eb61462bc254d11/memory.limit_in_bytes
  • 輸出

    104857600

最後, 讓我們來看看前面跳過的, 位於 memory cgroup 當中的 momery.soft_limit_in_bytes

  • 輸入以下指令

    sudo cat /sys/fs/cgroup/memory/kubepods/burstable/pod88f89108-daf7-11e8-b1e1-42010a800070/8fec6c7b61190e74cd9f88286181dd5fa3bbf9cf33c947574eb61462bc254d11/memory.soft_limit_in_bytes
  • 輸出

    9223372036854771712

從上面的值可以得知, 就算我們有設定 requests 的限制, kubernetes 也不會命令 docker 去做這件事, 儘管 docker run 的參數 --memory-reservation 是可以做到這件事的




頗析 (CPU)

CPU 的頗析模式大致上與 memory 相同, 但還是有不一樣的地方, 讓我們繼續看下去。

建立一個有 request CPU 限制的 pod

  • 輸入以下指令建立 pod

    kubectl run limit-test --image=busybox --requests "cpu=50m" --command -- /bin/sh -c "while true; do sleep 2; done"
  • 輸出

    deployment.apps "limit-test" created

使用 kubectl 來檢視 pod 的資源限制資訊

  • 輸入以下指令

    kubectl get pods limit-test-5b4c495556-p2xkr -o=jsonpath='{.spec.containers[0].resources}'
  • 輸出

    map[requests:map[cpu:50m]]

從輸出可看到 kubernetes 有確實的設定 request 資源限制

取得容器 id

  • 輸入以下指令

    docker ps | grep busy | cut -d' ' -f1
  • 輸出

    f2321226620e

查看 Docker 是否確實設定資源限制

  • 輸入以下指令

    docker inspect f2321226620e --format '{{.HostConfig.CpuShares}}'
  • 輸出

    51

為什麼不是 50? 那是因為 Docker 以及 cgroup 都將 core 分成 1024 份, 而 Kubernetes 則是分成 1000 份

取得容器 pid

  • 輸入以下指令

    ps ax | grep /bin/sh
  • 輸出

    60554 ?      Ss     0:00 /bin/sh -c while true; do sleep 2; done

取得容器的 CPU cgroup

  • 輸入以下指令

    sudo cat /proc/60554/cgroup
  • 輸出

    ...
    4:cpu,cpuacct:/kubepods/burstable/pode12b33b1-db07-11e8-b1e1-42010a800070/3be263e7a8372b12d2f8f8f9b4251f110b79c2a3bb9e6857b2f1473e640e8e75

取得 cgroup 屬性

  • 輸入以下指令

    ls -l /sys/fs/cgroup/cpu,cpuacct/kubepods/burstable/pode12b33b1-db07-11e8-b1e1-42010a800070/3be263e7a8372b12d2f8f8f9b4251f110b79c2a3bb9e6857b2f1473e640e8e75
  • 輸出

    total 0
    drwxr-xr-x 2 root root 0 Oct 28 23:19 .
    drwxr-xr-x 4 root root 0 Oct 28 23:19 ..
    ...
    -rw-r--r-- 1 root root 0 Oct 28 23:19 cpu.shares

以上輸出可知, Docker 的 HostConfig.CpuShares 屬性映射到 cgroup 的 cpu.shares 屬性

取得 cpu.shares 的值

  • 輸入以下指令

    /sys/fs/cgroup/cpu,cpuacct/kubepods/burstable/podb5c03ddf-db10-11e8-b1e1-42010a800070/64b5f1b636dafe6635ddd321c5b36854a8add51931c7117025a694281fb11444/cpu.shares
  • 輸出

    51

咦, 以上的行為跟 memory 不太一樣對吧? 限制 memory 的 resource limit 是不會作用到 cgroup 的 soft limits 的

接下來, 建立一個有著 limit resource 的 pod

  • 輸入以下指令

    kubectl run limit-test --image=busybox --requests "cpu=50m" --limits "cpu=100m" --command -- /bin/sh -c "while true; do
    sleep 2; done"
  • 輸出

    deployment.apps "limit-test" created

使用 kubectl 來檢視第二個 pod 的資源限制資訊

  • 輸入以下指令

    kubectl get pods limit-test-5b4fb64549-qpd4n -o=jsonpath='{.spec.containers[0].resources}'
  • 輸出

    map[limits:map[cpu:100m] requests:map[cpu:50m]]

從輸出可看到 kubernetes 有確實的設定 request 資源限制

取得第二個容器 id

  • 輸入以下指令

    docker ps | grep busy | cut -d' ' -f1
  • 輸出

    f2321226620e

查看 Docker 是否確實設定資源限制

  • 輸入以下指令

    docker inspect 472abbce32a5 --format '{{.HostConfig.CpuShares}} {{.HostConfig.CpuQuota}} {{.HostConfig.CpuPeriod}}'
  • 輸出

    51 10000 100000

Dokcer 使用了兩個值來代表 memory resource limit, HostConfig.CpuPeriodHostConfig.CpuQuota, 而這兩個值又分別映射到 cgroup 的兩個屬性 cpu.cfs_period_uscpu.cfs_quota_us

取得 cpu.cfs_period_uscpu.cfs_quota_us 的值

  • 輸入以下指令

    sudo cat /sys/fs/cgroup/cpu,cpuacct/kubepods/burstable/pod2f1b50b6-db13-11e8-b1e1-42010a800070/f0845c65c3073e0b7b0b95ce0c1eb27f69d12b1fe2382b50096c4b59e78cdf71/cpu.cfs_period_us
  • 輸出

    100000
  • 輸入以下指令

    sudo cat /sys/fs/cgroup/cpu,cpuacct/kubepods/burstable/pod2f1b50b6-db13-11e8-b1e1-42010a800070/f0845c65c3073e0b7b0b95ce0c1eb27f69d12b1fe2382b50096c4b59e78cdf71/cpu.cfs_quota_us
  • 輸出

    10000

CPU 頗析的總結

  • period 為百萬分之一秒
  • quota 為程序容許在 period 中可調動的 CPU
  • 100 m 就剛好是 1/10 core, 也是 10000/100000 百萬分之一秒
  • CPU 的資源限制中, request 是會作用到 cgroup 的, 該種類在 memory 是不會作用到 cgroup 的




以下是幫助釐清觀念的 Q&A

以下的 Kubernetes 範例輸出中, 為什麼 node 的可用資源比 node 的 capacity 少?
  • Example:

    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 (12%) 1070Mi (14%)
  • Answer:
    因為系統 daemons 使用了一部分的資源

以下的 Kubernetes 範例輸出中, requests CPU 限制還有多少 quota 可分配?
  • Example:

    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 (12%) 1070Mi (14%)
  • Answer:
    1800m - 680m = 1120m

Kubernetes 中, 每次當 Scheduler 無法在 node 上找到足夠的資源來置放 Pod 時, 都會產生一個什麼事件?
Events:
FirstSeen LastSeen Count From Subobject PathReason Message
36s 5s 6 {scheduler } FailedScheduling Failed for reason PodExceedsFreeCPU and possibly others
Kubernetes 的可計算資源管理中, 所指定的資源配額是絕對數字還是相對數字?

絕對數字

Kubernetes compute resource management 中, 如果我 CPU 設為 0.1, 在單核, 雙核, 甚至 48核的機器中, 代表的量會有所不同嗎?

不會哦

什麼是 TLB?

Translation lookaside buffer, 緩存虛擬記憶體到實體記憶體的 mapping

在 Linux 系統中, 虛擬記憶體管理系統中, 最小的 memory 單位是什麼?

page

Kubernetes resource limit management 中, huge page 是什麼?

size 較大的 page

Kubernetes 中, 如果一個 Pod 卡在 pending status, 那很有可能是甚麼原因?

沒有 Node 有足夠的資源來運行這個 Pod

Kubernetes 中, Resource 的限制可分為 CPU 以及 Memory, 限制類型主要分成哪兩種?
  • Request
  • Limit
Kubernetes Resource 的限制又可分為 requests 以及 limits 兩大類, request 主要代表的是?

這個 Pod 正常需要多少的資源可以正常運行

Kubernetes Resource 的限制又可分為 requests 以及 limits 兩大類, 在 Kubernetes 各元件當中, request resource 對哪一個元件格外重要?

scheduler

Kubernetes Resource 的限制又可分為 requests 以及 limits 兩大類, 在 Kubernetes 各元件當中, limit resource 對哪一個元件格外重要?

kubelet

Kubernetes Resource 的限制又可分為 requests 以及 limits 兩大類, 當 Scheduler 在選擇要在哪一個 Node 上面運行 Pod 時, 主要會考量哪一種類?

request

Kubernetes Resource 的限制又可分為 requests 以及 limits 兩大類, 當 Scheduler 跟 request 的關係是?

Scheduler 會選擇有足夠資源 (request 要求的資源) 的 node 來運行該 pod

以下的 Kubernetes yaml 檔所代表的意思是?
  • yaml 檔:

    resources:
    requests:
    cpu: 50m
    memory: 50Mi
    limits:
    cpu: 100m
    memory: 100Mi
  • Answer:

    # 定義資源限制
    resources:
    # 定義 requests 種類限制, scheduler 會選擇有足夠 request 資源的 Node 來運行該 Pod
    requests:
    cpu: 50m
    memory: 50Mi
    # 定義 limits 種類限制, Kubelet 會根據 limits 資源來決定是否重啟該 Pod
    limits:
    cpu: 100m
    memory: 100Mi
Kubernetes 中, 1 MiB 等於多少?

1 MiB = 1024 KiB = 1024 * 1024 = 1048576 Bytes

Kubernetes 中, 1 MB 等於多少?

1 MB = 1000 KB = 1000 * 1000 = 1000000 Bytes

Kubernetes 中, 一個 Pod 的資源總限制是 什麼 的總和?

該 Pod 內所有容器的資源限制加總

Cgroup 的全寫是?

Control Group

Cgroup 簡單解釋?

有著一系列相關屬性的容器, 控制 kernel 如何運行程序

Kubernetes resource limit 中, 當我們只設置 limits, 但沒設置 requests 時, 會發生什麼事?

Kubernetes 會將 requests 設為 limits 的值

當宿主機面臨記憶體壓力時, 會做什麼事?

會殺掉程序

當一個程序使用了超過在 cgroup 中規定的 memory 時, 會發生什麼事?

該程序會被列入要殺掉的優先名單中

Server 中的 OOM 的全寫是??

Out Of Memory

Kubernetes resource limit 當中, 當我設定了 requests 的限制, Kubernetes 會否要求 docker 去設定 memory cgroup 中的 soft_limit?

不會

Kubernetes resource limit 當中, requests 若設得太高會發生什麼事?

可能會出現沒有 node 可以運行這個 pod, 明明這個 pod 正常不會需要這麼高的 memory

Kubernetes resource limit 當中, requests 若設得太低會發生什麼事?

如果一個 node 的剩餘空間已經沒有很多了, 因為 request 設得低, 所以依然會被分派到這個 node, 但該 pod 實際需要的資源遠高於 request 值, 所以該 node 面臨記憶體壓力時就會優先砍掉這個 pod

Kubernetes 中, 一個 core 為幾 m?

1000 m

Kubernetes 將一個 core 分成幾份?

1000

Docker 將一個 core 分成幾份?

1024

CGroup 將一個 core 分成幾份?

1024

Kubernetes 中, 當設定 memory 的 request limit 後, 會作用到 cgroup 嗎?

不會

Kubernetes 中, 當設定 CPU 的 request limit 後, 會作用到 cgroup 嗎?

Kubernetes resource limit 中, request resource 是由哪一個 cgroup 系統所管理的?

cpu shares system

cgroup cpu.cfs_period_us 中的 period 代表幾秒?

1/10 秒 或 100000 microseconds (百萬分之一秒)

cgroup cpu.cfs_quota_us 中的 quota 代表什麼?

一個程序在 period 中容許可調用的最大值

假如我的 CPU request limit 是 200m, 那我的 cpu.cfs_period_us 以及 cpu.cfs_quota_us 分別是多少?
  • cpu.cfs_period_us: 100000
  • cpu.cfs_quota_us: 20000
cpu.cfs_period_uscpu.cfs_quota_us 是屬於哪一個 cgroup?

cpu,cpuacct

cpu.cfs_period_uscpu.cfs_quota_us 中的 cfs 的意思是?

Completely Fair Scheduler

Linux 的預設 CPU scheduler 是哪一個?

CFS (Completely Fair Scheduler)

Kubernetes 中, 當設定 CPU 的 request resource 限制, 會作用到 cgroup 嗎?

會哦

Kubernetes 中, 程序可以超出 CPU request resource 限制 規定的用量嗎?

不行

Kubernetes 中, 當程序使用了超過 CPU request resource 限制 規定的用量的話, 會發生什麼事?

不會有這種情況, 因為 CPU request resource 限制 規定的用量不允許超出

Kubernetes resource limit 中, 如果我只設定了 limits, 但沒設定 requests, 會發生什麼事?

requests 的預設值會被設為跟 limits 一樣

Kubernetes resource limit 中, 如果我只設定了 requests, 但沒設定 limits, 會發生什麼事?

scheduler 會正常根據 requests 的資源數據啟動 pod, 但該 process 的資源使用量將無法被限制

以下的 Kubernetes yaml 設定檔的意思是?
  • yaml 檔:

    apiVersion: v1
    kind: LimitRange
    metadata:
    name: default-limit
    spec:
    limits:
    - default:
    memory: 100Mi
    cpu: 100m
    defaultRequest:
    memory: 50Mi
    cpu: 50m
    - max:
    memory: 512Mi
    cpu: 500m
    - min:
    memory: 50Mi
    cpu: 50m
    type: Container
  • Answer:

    # API 版本
    apiVersion: v1
    # 種類為 LimitRange
    kind: LimitRange
    # 該 LimitRange 的 metadata
    metadata:
    # 該 LimitRange 的 name
    name: default-limit
    # 該 LimitRange 運行的規格
    spec:
    # 定義 limits
    limits:
    # 預設的 resource limits, 若該 namespace 下的 pod 在建立時沒有指定資源限制, 將套用此預設設定
    - default:
    memory: 100Mi
    cpu: 100m
    # 預設的 resource requested, 若該 namespace 下的 pod 在建立時沒有指定資源限制, 將套用此預設設定
    defaultRequest:
    memory: 50Mi
    cpu: 50m
    # 若欲在此 namespace 下建立 pod, 而該 pod 若指定資源限制高於此設定, 將不允許建立
    - max:
    memory: 512Mi
    cpu: 500m
    # 若欲在此 namespace 下建立 pod, 而該 pod 若指定資源限制低於此設定, 將不允許建立
    - min:
    memory: 50Mi
    cpu: 50m
    # 限制的類型為 container
    type: Container
Kubernetes request resource 限制中, 1 core = 1000 m, 那允許的最小設定值是多少?

1m

Kubernetes 中, 要如何查看 node 有多少可用資源?
kubectl describe nodes nodeName
Kubernetes 中, 如何知道容器有沒有因為資源達到限制而被砍掉?
  • 取得 pod 資訊

    kube describe pod podName
  • 取得前一個 pod 被砍掉的原因

    kubectl get pod -o go-template='{{range.status.containerStatuses}}{{"Container Name: "}}{{.name}}{{"\r\nLastState: "}}{{.lastState}}{{end}}'  simmemleak-hra99
Kubernetes 中, local ephemeral storage 指的是什麼地方?

root partition

Kubernetes 中, emptyDir volumes, container logs, image layers, container writable layers, 這些都是使用哪一塊空間?

root partition

以下的 Kubernetes yaml 檔是什麼意思呢?
  • yaml 檔

    apiVersion: v1
    kind: Pod
    metadata:
    name: frontend
    spec:
    containers:
    - name: db
    image: mysql
    env:
    - name: MYSQL_ROOT_PASSWORD
    value: "password"
    resources:
    requests:
    ephemeral-storage: "2Gi"
    limits:
    ephemeral-storage: "4Gi"
    - name: wp
    image: wordpress
    resources:
    requests:
    ephemeral-storage: "2Gi"
    limits:
    ephemeral-storage: "4Gi"
  • Answer:

    # API 版本
    apiVersion: v1
    # 種類為 Pod
    kind: Pod
    # 該 Pod 的 metadata
    metadata:
    # 該 Pod 的 name
    name: frontend
    # 該 pod 運行的規格
    spec:
    # 定義容器規格
    containers:
    # 容器名稱
    - name: db
    # 鏡像名稱
    image: mysql
    # 定義變數
    env:
    # 變數名稱
    - name: MYSQL_ROOT_PASSWORD
    # 變數值
    value: "password"
    # 定義資源限制
    resources:
    # 定義 requests 資源限制
    requests:
    # 限制 ephemeral-storage
    ephemeral-storage: "2Gi"
    # 定義 limits 資源限制
    limits:
    # 限制 ephemeral-storage
    ephemeral-storage: "4Gi"
    # 容器名稱
    - name: wp
    # 鏡像名稱
    image: wordpress
    # 定義資源限制
    resources:
    # 定義 requests 資源限制
    requests:
    # 限制 ephemeral-storage
    ephemeral-storage: "2Gi"
    # 定義 limits 資源限制
    limits:
    # 限制 ephemeral-storage
    ephemeral-storage: "4Gi"
Kubernetes, 哪一個元件依據 ephemeral-storage 資源分配 pod 到適當的 node?

scheduler

Kubernetes, 如果一個 pod 裡頭的某個容器的 writable layer 以及 logs 使用量超過的 ephemeral-storage 的資源限制, 會發生什麼事?

該 pod 會被砍了

Kubernetes, 如果一個 pod 裡頭的所有容器使用的 ephemeral-storage 用量以及 emptyDir volumes 超過了資院限制, 會發生什麼事?

該 pod 會被砍了

參考資源

Kubernetes - Health Check 一下子敏感, 一下子不敏感, Git 你搞得我好亂啊

留言

Your browser is out-of-date!

Update your browser to view this website correctly. Update my browser now

×