Kubernetes Workload Basics - 1

本篇文章將會介紹 k8s 中 PodSpec 最常見的幾個與 container 本身有關的設定,特別是 Resources 以及 Probes。

Kubernetes Workload Basics - 1

本篇文章將會介紹 k8s 中 PodSpec 最常見的幾個與 container 本身有關的設定,特別是 Resources 以及 Probes。在上一篇中最後提到 Pod 的基本信息,快速地複習一下幾個重點:

  • Pod 是 k8s 中可部署的最小單位
  • Pod 是一或多個 Container 的集合體
  • Pod 中的 Container 共用同一個 Pod IP
  • Pod 中的 Container 可以使用同樣的 Volume

這裡我們來簡單的看看 Pod 的常用設定:

這裡只會提到最常見的幾個設定,並以 k8s@1.17 為主,可以參考 Pod API Reference 來看設定細項。
apiVersion: v1
kind: Pod
metadata:
  labels:
    app: echoserver
  name: echoserver
spec:
  initContainers:
    - name: init
      image: busybox:1.28
      command:
        - "sh"
        - "-c"
        - 'echo "preparing application"'
  containers:
    - name: server
      image: ewocker/slim-echoserver:1.0.0
      imagePullPolicy: IfNotPresent
      resources:
        limits:
          cpu: "100m"
          memory: "50Mi"
        requests:
          cpu: "100m"
          memory: "50Mi"
      ports:
        - name: service-port
          containerPort: 8080
      readinessProbe:
        httpGet:
          path: /healthy
          port: service-port
        initialDelaySeconds: 5
        failureThreshold: 2
        periodSeconds: 10
      livenessProbe:
        httpGet:
          path: /ready
          port: service-port
        initialDelaySeconds: 5
        failureThreshold: 2
        periodSeconds: 10
  restartPolicy: Always
  terminationGracePeriodSeconds: 5

首先是 containersinitContainers,一個 Pod 可以包含多個容器,而在 k8s 中還將其分為兩種,分別是 主容器運行前先運行的 initContainers 和 包含主容器的 containers

  • initContainer 顧名思義就是用於 initialization。如果有多個 initContainers 時,會依序逐個運行。常見的 initContainer 有像是用 nslookup 確保 DNS reachability,或是預先將 configuration 處理成所需的格式等等。‌‌(這裡因為演示需要,就隨便 echo 一串字)
  • container 則是在所有 initContainer 運行結束後才開始的,如果有多個 containers 時,所有 containers 會同時運行。

接著來看看 ContainerSpec,這裡使用的幾個常見的 field 是:

  • name - 容器的名字,主要是使除錯或指檢查日誌時更容易分別 Pod 中的多個容器。
  • image - 映像檔,該 container 所使用的映像檔。
  • resources -  資源,該容器所需使用的 cpu 和 memory 資源,細分為 request 和 limit:‌‌request - 是容器所請求的資源,kube-scheduler 會在創建 Pod 時會根據所有 container request 的資源來決定該 Pod 將發派到哪一個 Node 上,被發配到的 Node 必須有足夠的資源。‌‌limit - 是限制容器不能超過的資源用量,如果 cpu 超過 limit 的話 container 會被 throttle (每當超過時會被壓抑回限制的用量)。如果 memory 超標的話則是會被 OOMKill (Out of Memory Kill,該容器會因為內存不足而被刪掉),這種狀況下在 k8s 中 container 等於是被重啟了。‌‌resources 的設定非常重要,它會被用於確保 Pod 至少保有屬於自己 request 的資源。Application owner 必須要了解怎麼樣的資源配置對自己的 app 是最有效率的,並且與以後會提到的自適應擴縮 autoscaling 有關。(下面有更多信息)
  • ports - 是 container 的端口,如果加上了 name 來命名的話,則可以在其他設定中直接用名稱來代替端口。
  • livenessProbe - kubelet 會根據 livenessProbe 的定義來檢查 container 是否健康的在運行,如果 livenessProbe 發生錯誤則 container 會被是於 不健康 (Unhealthy)kubelet 會重啟該 container。‌‌上面是以最常見的 httpGet 為例子,如果 container 沒辦法準時回應 /healthy HTTP GET 的要求或發生錯誤等等,則會被視為 Unhealthy 並且被重啟。(除了 httpGet 以外還有其他方法,請參考 Probe
  • readinessProbe - kubelet 會根據 readinessProbe 的定義來檢查 container 是否處於準備好的狀態,當readinessProbe 發生錯誤時 container 並不會像 livenessProbe Failure 一樣被重啟,但 container 會被當作處於 未就緒 (Unready) 的狀態,並且如果是 Service 所選擇的 Pod 時則會被剔除於 Service 的 LoadBalancing 選擇中 。(以後說到 Service 時會在多加說明)‌‌舉個常見 readinessProbe 的用法,像是 container 需要構通一個 database,但是 database 卻因為某些原因而無法架設連結,這時候 container 雖然是健康的狀態 (Healthy) 卻也是 未就緒狀態 (Unready)。(下面有更多信息)

Resources & QoS

了解自己 container 所需的資源是非常重要的一件事,除了在自適應擴縮 (autoscaling)上有極大的影響外, 在 k8s 中還有非常重要的意義,那就是 Pod 的 QoS 屬性。

💡 k8s 說到底就是多個 Node (機器/伺服器) 和再一起共同的集合體。在機器的資源不夠用的時候,k8s 會根據 Pod 的重要性來依次將 Pod 剔除 (eviction),直到系統有足夠的資源使用。‌‌Pod 的重要性首先是看 PriorityClass,接著就是看 QoS。(以後會在提到 PriorityClass)

首先要在細說下當 container 使用超過 Request 和 Limit 時會發生什麼事:

  • CPU exceeds request,當 CPU 使用超過要求的資源時,無論是否有設置 CPU limit Pod 可以使用系統中多餘的 CPU。
  • CPU exceeds limit,當 CPU 使用超過限制的資源時, Pod 中的 container 會被壓抑 (throttling)。
  • Memory exceeds request,當 Memory 使用超過要求時,‌‌- 如果 Pod 有設置 Memory limit,Pod 中的 container 可以使用系統中多餘的  Memory。‌‌但如果 Pod 沒有設置 Memory limit,在系統需要內存資源時 Pod 中的 container 可能會被刪除 (OOM Killed,Out of Memory Kill)。
  • Memory exceeds limit,當 Memory 使用超過限制時 Pod 中的 container 會被刪除 (OOM Killed,Out of Memory Kill)。
💡 CPU - Compressible (可壓縮)
    Memory - Incompressible (不可壓縮)

QoS (Quality of Service) 中文直翻服務質量,用於表示 Pod 的可變動性。QoS 有三個值,分別是:

  • Guaranteed - High Priority (高重要性,不容易被刪除的 Pod)‌‌當所有 container 中 resource 的 request 和 limit 相同時,Pod 的 QoS 將會是 Guaranteed。簡單來說就是使用者保證自己的 Pod 不會使用超過 resource 的定義。
  • Burstable - Medium Priority (中等重要性,有可能被刪除的 Pod)‌‌當條件不符合 Guaranteed 時,並且 Pod 中有任一 container 有設置 resource request 時,Pod 的 QoS 將會是 Burstable。
  • BestEffort - Low Priority (低重要性,容易被刪除的 Pod)‌‌當 Pod 中沒有任一 container 有設置 resource request 時,Pod 的 QoS 將會是 Burstable。

所以 QoS 究竟代表什麼呢?簡單來說如果今天有兩個正在運行的 Pod,分別有 QoS Guaranteed 和 Burstable,在系統資源不夠用時,k8s 會首先剔除 QoS 為 Burstable 的 Pod 來緩解系統的壓力。

❗️ 創建新的 Pod 時,當 k8s cluster 中資源不夠用時,即便有較低的 QoS Pod 存在,k8s 也不會因為新要創建的 Pod 有較高的 QoS 而剔除較低 QoS 的 Pod。‌‌這種為了 High Priority 而剔除 Low Priority 的型態叫做 Preemption,是屬於 PriorityClass 相關的內容,和 QoS 並無關連。
QoS 只有在系統資源不足時必須剔除 Pod 時才會被考慮進去,如果你使用的 cluster 有高手在後面細心關照,並且有設置 kubelet reservation 及 system reservation,則這種事情將會很少發生。

Probe

因為 livenessProbe readinessProbe 是非常重要的概念,所以這裡細說一下例子中的幾個設定 initialDelaySeconds、periodSeconds、failureThreshold:

  • initialDelaySeconds 是初始延遲時間,在 container 啟動之後可能需要數秒甚至幾分鐘來維持狀態。一般來說 readinessProbe 的 initialDelaySeconds 會比 livenessProbe 要長一些。(先確保處於健康的可執行狀態,在確定是否就緒)
  • periodSeconds 是每次確認的間隔秒數
  • failureThreshold 是指失敗多少次才將其歸類於不健康或未就緒狀態。相反的,也有 successThreshold 的設定。
  • 其他設定還有 timeoutSeconds,這裡因為非常顧名思義所以就不多做說明。
initialDelaySeconds: 5
periodSeconds: 10
failureThreshold: 2

以上面的設定來說就是,container 創建好 5 秒後開始 liveness/readiness Probe,每 10 秒一次,不能連續失敗兩次。

總結

除了上面的設定以外,Pod 還有許多其他的設定,這裡只介紹了幾個創建 Pod 時必須要知道的設定,特別是 livenessProbe/readinessProbe 以及 resource。‌‌一般來說使用者不會自己創建 Pod,而是會在其它 k8s 工作附載資源 (Workload Resource) 中透過定義 PodTemplate 來創建 Pod。接下來幾個章節會慢慢介紹幾個常見的 Workloads。