Kubernetes學習之路(十一)之Pod狀態和生命周期管理


一、什么是Pod?

Pod是kubernetes中你可以創建和部署的最小也是最簡的單位。一個Pod代表着集群中運行的一個進程。

Pod中封裝着應用的容器(有的情況下是好幾個容器),存儲、獨立的網絡IP,管理容器如何運行的策略選項。Pod代表着部署的一個單位:kubernetes中應用的一個實例,可能由一個或者多個容器組合在一起共享資源。

在Kubrenetes集群中Pod有如下兩種使用方式:

  • 一個Pod中運行一個容器。“每個Pod中一個容器”的模式是最常見的用法;在這種使用方式中,你可以把Pod想象成是單個容器的封裝,kuberentes管理的是Pod而不是直接管理容器。
  • 在一個Pod中同時運行多個容器。一個Pod中也可以同時封裝幾個需要緊密耦合互相協作的容器,它們之間共享資源。這些在同一個Pod中的容器可以互相協作成為一個service單位——一個容器共享文件,另一個“sidecar”容器來更新這些文件。Pod將這些容器的存儲資源作為一個實體來管理。

Pod中共享的環境包括Linux的namespace,cgroup和其他可能的隔絕環境,這一點跟Docker容器一致。在Pod的環境中,每個容器中可能還有更小的子隔離環境。

Pod中的容器共享IP地址和端口號,它們之間可以通過localhost互相發現。它們之間可以通過進程間通信,需要明白的是同一個Pod下的容器是通過lo網卡進行通信。例如SystemV信號或者POSIX共享內存。不同Pod之間的容器具有不同的IP地址,不能直接通過IPC通信。

Pod中的容器也有訪問共享volume的權限,這些volume會被定義成pod的一部分並掛載到應用容器的文件系統中。

就像每個應用容器,pod被認為是臨時實體。在Pod的生命周期中,pod被創建后,被分配一個唯一的ID(UID),調度到節點上,並一致維持期望的狀態直到被終結(根據重啟策略)或者被刪除。如果node死掉了,分配到了這個node上的pod,在經過一個超時時間后會被重新調度到其他node節點上。一個給定的pod(如UID定義的)不會被“重新調度”到新的節點上,而是被一個同樣的pod取代,如果期望的話甚至可以是相同的名字,但是會有一個新的UID(查看replication controller獲取詳情)。

二、Pod中如何管理多個容器?

Pod中可以同時運行多個進程(作為容器運行)協同工作。同一個Pod中的容器會自動的分配到同一個 node 上。同一個Pod中的容器共享資源、網絡環境和依賴,它們總是被同時調度。

注意在一個Pod中同時運行多個容器是一種比較高級的用法。只有當你的容器需要緊密配合協作的時候才考慮用這種模式。例如,你有一個容器作為web服務器運行,需要用到共享的volume,有另一個“sidecar”容器來從遠端獲取資源更新這些文件,如下圖所示:

Pod中可以共享兩種資源:網絡和存儲。

  •  網絡:

  每個Pod都會被分配一個唯一的IP地址。Pod中的所有容器共享網絡空間,包括IP地址和端口。Pod內部的容器可以使用localhost互相通信。Pod中的容器與外界通信時,必須分配共享網絡資源(例如使用宿主機的端口映射)。

  • 存儲:

  可以Pod指定多個共享的Volume。Pod中的所有容器都可以訪問共享的volume。Volume也可以用來持久化Pod中的存儲資源,以防容器重啟后文件丟失。

 三、使用Pod

通常把Pod分為兩類:

  • 自主式Pod :這種Pod本身是不能自我修復的,當Pod被創建后(不論是由你直接創建還是被其他Controller),都會被Kuberentes調度到集群的Node上。直到Pod的進程終止、被刪掉、因為缺少資源而被驅逐、或者Node故障之前這個Pod都會一直保持在那個Node上。Pod不會自愈。如果Pod運行的Node故障,或者是調度器本身故障,這個Pod就會被刪除。同樣的,如果Pod所在Node缺少資源或者Pod處於維護狀態,Pod也會被驅逐。
  • 控制器管理的Pod:Kubernetes使用更高級的稱為Controller的抽象層,來管理Pod實例。Controller可以創建和管理多個Pod,提供副本管理、滾動升級和集群級別的自愈能力。例如,如果一個Node故障,Controller就能自動將該節點上的Pod調度到其他健康的Node上。雖然可以直接使用Pod,但是在Kubernetes中通常是使用Controller來管理Pod的。如下圖:

每個Pod都有一個特殊的被稱為“根容器”的Pause 容器。 Pause容器對應的鏡像屬於Kubernetes平台的一部分,除了Pause容器,每個Pod還包含一個或者多個緊密相關的用戶業務容器。

Kubernetes設計這樣的Pod概念和特殊組成結構有什么用意?????

原因一:在一組容器作為一個單元的情況下,難以對整體的容器簡單地進行判斷及有效地進行行動。比如,一個容器死亡了,此時是算整體掛了么?那么引入與業務無關的Pause容器作為Pod的根容器,以它的狀態代表着整個容器組的狀態,這樣就可以解決該問題。

原因二:Pod里的多個業務容器共享Pause容器的IP,共享Pause容器掛載的Volume,這樣簡化了業務容器之間的通信問題,也解決了容器之間的文件共享問題。

四、Pod的持久性和終止

(1)Pod的持久性

Pod在設計支持就不是作為持久化實體的。在調度失敗、節點故障、缺少資源或者節點維護的狀態下都會死掉會被驅逐

通常,用戶不需要手動直接創建Pod,而是應該使用controller(例如Deployments),即使是在創建單個Pod的情況下。Controller可以提供集群級別的自愈功能、復制和升級管理。

(2)Pod的終止

因為Pod作為在集群的節點上運行的進程,所以在不再需要的時候能夠優雅的終止掉是十分必要的(比起使用發送KILL信號這種暴力的方式)。用戶需要能夠放松刪除請求,並且知道它們何時會被終止,是否被正確的刪除。用戶想終止程序時發送刪除pod的請求,在pod可以被強制刪除前會有一個寬限期,會發送一個TERM請求到每個容器的主進程。一旦超時,將向主進程發送KILL信號並從API server中刪除。如果kubelet或者container manager在等待進程終止的過程中重啟,在重啟后仍然會重試完整的寬限期。

示例流程如下:

  1. 用戶發送刪除pod的命令,默認寬限期是30秒;
  2. 在Pod超過該寬限期后API server就會更新Pod的狀態為“dead”;
  3. 在客戶端命令行上顯示的Pod狀態為“terminating”;
  4. 跟第三步同時,當kubelet發現pod被標記為“terminating”狀態時,開始停止pod進程:
    1. 如果在pod中定義了preStop hook,在停止pod前會被調用。如果在寬限期過后,preStop hook依然在運行,第二步會再增加2秒的寬限期;
    2. 向Pod中的進程發送TERM信號;
  5. 跟第三步同時,該Pod將從該service的端點列表中刪除,不再是replication controller的一部分。關閉的慢的pod將繼續處理load balancer轉發的流量;
  6. 過了寬限期后,將向Pod中依然運行的進程發送SIGKILL信號而殺掉進程。
  7. Kublete會在API server中完成Pod的的刪除,通過將優雅周期設置為0(立即刪除)。Pod在API中消失,並且在客戶端也不可見。

刪除寬限期默認是30秒。 kubectl delete命令支持 —grace-period=<seconds> 選項,允許用戶設置自己的寬限期。如果設置為0將強制刪除pod。在kubectl>=1.5版本的命令中,你必須同時使用 --force 和 --grace-period=0 來強制刪除pod。

Pod的強制刪除是通過在集群和etcd中將其定義為刪除狀態。當執行強制刪除命令時,API server不會等待該pod所運行在節點上的kubelet確認,就會立即將該pod從API server中移除,這時就可以創建跟原pod同名的pod了。這時,在節點上的pod會被立即設置為terminating狀態,不過在被強制刪除之前依然有一小段優雅刪除周期。 

 五、Pause容器

 Pause容器,又叫Infra容器。我們檢查node節點的時候會發現每個node上都運行了很多的pause容器,例如如下。

[root@k8s-node01 ~]# docker ps |grep pause
0cbf85d4af9e    k8s.gcr.io/pause:3.1   "/pause"     7 days ago  Up 7 days   k8s_POD_myapp-848b5b879b-ksgnv_default_0af41a40-a771-11e8-84d2-000c2972dc1f_0
d6e4d77960a7    k8s.gcr.io/pause:3.1   "/pause"     7 days ago  Up 7 days   k8s_POD_myapp-848b5b879b-5f69p_default_09bc0ba1-a771-11e8-84d2-000c2972dc1f_0
5f7777c55d2a    k8s.gcr.io/pause:3.1   "/pause"     7 days ago  Up 7 days   k8s_POD_kube-flannel-ds-pgpr7_kube-system_23dc27e3-a5af-11e8-84d2-000c2972dc1f_1
8e56ef2564c2    k8s.gcr.io/pause:3.1   "/pause"     7 days ago  Up 7 days   k8s_POD_client2_default_17dad486-a769-11e8-84d2-000c2972dc1f_1
7815c0d69e99    k8s.gcr.io/pause:3.1   "/pause"     7 days ago  Up 7 days   k8s_POD_nginx-deploy-5b595999-872c7_default_7e9df9f3-a6b6-11e8-84d2-000c2972dc1f_2
b4e806fa7083    k8s.gcr.io/pause:3.1   "/pause"     7 days ago  Up 7 days   k8s_POD_kube-proxy-vxckf_kube-system_23dc0141-a5af-11e8-84d2-000c2972dc1f_2

kubernetes中的pause容器主要為每個業務容器提供以下功能:

  • 在pod中擔任Linux命名空間共享的基礎;
  • 啟用pid命名空間,開啟init進程。

如圖:

 

[root@k8s-node01 ~]# docker run -d --name pause -p 8880:80 k8s.gcr.io/pause:3.1
d3057ceb54bc6565d28ded2c33ad2042010be73d76117775c130984c3718d609
[root@k8s-node01 ~]# cat <<EOF >> nginx.conf
> error_log stderr;
> events { worker_connections  1024; }
> http {
>     access_log /dev/stdout combined;
>     server {
>         listen 80 default_server;
>         server_name example.com www.example.com;
>         location / {
>             proxy_pass http://127.0.0.1:2368;
>         }
>     }
> }
> EOF
[root@k8s-node01 ~]# docker run -d --name nginx -v `pwd`/nginx.conf:/etc/nginx/nginx.conf --net=container:pause --ipc=container:pause --pid=container:pause nginx
d04f848b7386109085ee350ebb81103e4efc7df8e48da18404efb9712f926082
[root@k8s-node01 ~]#  docker run -d --name ghost --net=container:pause --ipc=container:pause --pid=container:pause ghost
332c86a722f71680b76b3072e85228a8d8e9608456c653edd214f06c2a77f112

現在訪問http://192.168.56.12:8880/就可以看到ghost博客的界面了。

解析

pause容器將內部的80端口映射到宿主機的8880端口,pause容器在宿主機上設置好了網絡namespace后,nginx容器加入到該網絡namespace中,我們看到nginx容器啟動的時候指定了--net=container:pause,ghost容器同樣加入到了該網絡namespace中,這樣三個容器就共享了網絡,互相之間就可以使用localhost直接通信,--ipc=contianer:pause --pid=container:pause就是三個容器處於同一個namespace中,init進程為pause,這時我們進入到ghost容器中查看進程情況。

[root@k8s-node01 ~]# docker exec -it ghost /bin/bash
root@d3057ceb54bc:/var/lib/ghost# ps axu 
USER        PID %CPU %MEM    VSZ   RSS TTY      STAT START   TIME COMMAND
root          1  0.0  0.0   1012     4 ?        Ss   03:48   0:00 /pause
root          6  0.0  0.0  32472   780 ?        Ss   03:53   0:00 nginx: master process nginx -g daemon off;
systemd+     11  0.0  0.1  32932  1700 ?        S    03:53   0:00 nginx: worker process
node         12  0.4  7.5 1259816 74868 ?       Ssl  04:00   0:07 node current/index.js
root         77  0.6  0.1  20240  1896 pts/0    Ss   04:29   0:00 /bin/bash
root         82  0.0  0.1  17496  1156 pts/0    R+   04:29   0:00 ps axu

在ghost容器中同時可以看到pause和nginx容器的進程,並且pause容器的PID是1。而在kubernetes中容器的PID=1的進程即為容器本身的業務進程。

六、init容器 

Pod 能夠具有多個容器,應用運行在容器里面,但是它也可能有一個或多個先於應用容器啟動的 Init 容器。

Init 容器與普通的容器非常像,除了如下兩點:

  • Init 容器總是運行到成功完成為止。
  • 每個 Init 容器都必須在下一個 Init 容器啟動之前成功完成。

如果 Pod 的 Init 容器失敗,Kubernetes 會不斷地重啟該 Pod,直到 Init 容器成功為止。然而,如果 Pod 對應的 restartPolicy 為 Never,它不會重新啟動。

七、Pod的生命周期

(1)Pod phase(Pod的相位)

Pod 的 status 在信息保存在 PodStatus 中定義,其中有一個 phase 字段。

Pod 的相位(phase)是 Pod 在其生命周期中的簡單宏觀概述。該階段並不是對容器或 Pod 的綜合匯總,也不是為了做為綜合狀態機。

Pod 相位的數量和含義是嚴格指定的。除了本文檔中列舉的狀態外,不應該再假定 Pod 有其他的 phase值。

下面是 phase 可能的值:

  • 掛起(Pending):API Server創建了Pod資源對象並已經存入了etcd中,但是它並未被調度完成,或者仍然處於從倉庫下載鏡像的過程中。
  • 運行中(Running):Pod已經被調度到某節點之上,並且所有容器都已經被kubelet創建完成。
  • 成功(Succeeded):Pod 中的所有容器都被成功終止,並且不會再重啟。
  • 失敗(Failed):Pod 中的所有容器都已終止了,並且至少有一個容器是因為失敗終止。也就是說,容器以非0狀態退出或者被系統終止。
  • 未知(Unknown):因為某些原因無法取得 Pod 的狀態,通常是因為與 Pod 所在主機通信失敗。

下圖是Pod的生命周期示意圖,從圖中可以看到Pod狀態的變化。

(2)Pod的創建過程

Pod是Kubernetes的基礎單元,了解其創建的過程,更有助於理解系統的運作。

①用戶通過kubectl或其他API客戶端提交Pod Spec給API Server。

②API Server嘗試將Pod對象的相關信息存儲到etcd中,等待寫入操作完成,API Server返回確認信息到客戶端。

③API Server開始反映etcd中的狀態變化。

④所有的Kubernetes組件通過"watch"機制跟蹤檢查API Server上的相關信息變動。

⑤kube-scheduler(調度器)通過其"watcher"檢測到API Server創建了新的Pod對象但是沒有綁定到任何工作節點。

⑥kube-scheduler為Pod對象挑選一個工作節點並將結果信息更新到API Server。

⑦調度結果新消息由API Server更新到etcd,並且API Server也開始反饋該Pod對象的調度結果。

⑧Pod被調度到目標工作節點上的kubelet嘗試在當前節點上調用docker engine進行啟動容器,並將容器的狀態結果返回到API Server。

⑨API Server將Pod信息存儲到etcd系統中。

⑩在etcd確認寫入操作完成,API Server將確認信息發送到相關的kubelet。

(3)Pod的狀態

Pod 有一個 PodStatus 對象,其中包含一個 PodCondition 數組。 PodCondition 數組的每個元素都有一個 type 字段和一個 status 字段。type 字段是字符串,可能的值有 PodScheduled、Ready、Initialized 和 Unschedulable。status 字段是一個字符串,可能的值有 True、False 和 Unknown。

(4)Pod存活性探測

在pod生命周期中可以做的一些事情。主容器啟動前可以完成初始化容器,初始化容器可以有多個,他們是串行執行的,執行完成后就推出了,在主程序剛剛啟動的時候可以指定一個post start 主程序啟動開始后執行一些操作,在主程序結束前可以指定一個 pre stop 表示主程序結束前執行的一些操作。在程序啟動后可以做兩類檢測 liveness probe(存活性探測) 和 readness probe(就緒性探測)。如下圖:

 

探針是由 kubelet 對容器執行的定期診斷。要執行診斷,kubelet 調用由容器實現的Handler。其存活性探測的方法有以下三種:

  • ExecAction:在容器內執行指定命令。如果命令退出時返回碼為 0 則認為診斷成功。
  • TCPSocketAction:對指定端口上的容器的 IP 地址進行 TCP 檢查。如果端口打開,則診斷被認為是成功的。
  • HTTPGetAction:對指定的端口和路徑上的容器的 IP 地址執行 HTTP Get 請求。如果響應的狀態碼大於等於200 且小於 400,則診斷被認為是成功的。

設置exec探針舉例:

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness-exec
  name: liveness-exec
spec:
  containers:
  - name: liveness-exec-demo
    image: busybox
    args: ["/bin/sh","-c","touch /tmp/healthy;sleep 60;rm -rf /tmp/healthy;"sleep 600]
    livenessProbe:
      exec:
        command: ["test","-e","/tmp/healthy"]

上面的資源清單中定義了一個Pod 對象, 基於 busybox 鏡像 啟動 一個 運行“ touch/ tmp/ healthy; sleep 60; rm- rf/ tmp/ healthy; sleep 600” 命令 的 容器, 此 命令 在 容器 啟動 時 創建/ tmp/ healthy 文件, 並於 60 秒 之后 將其 刪除。 存活 性 探針 運行“ test -e/ tmp/ healthy” 命令 檢查/ tmp/healthy 文件 的 存在 性, 若 文件 存在 則 返回 狀態 碼 0, 表示 成功 通過 測試。

設置HTTP探針舉例:

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness-http
  name: liveness-http
spec:
  containers:
  - name: liveness-http-demo
    image: nginx:1.12-alpine
    ports:
    - name: http
      containerPort: 80
    lifecycle:
      postStart:
        exec:
          command: ["/bin/sh","-c","echo healthy > /usr/share/nginx/html/healthy"]
    livenessProbe:
      httpGet:
        path: /healthy
        port: http
        scheme: HTTP

上面 清單 文件 中 定義 的 httpGet 測試 中, 請求 的 資源 路徑 為“/ healthy”, 地址 默認 為 Pod IP, 端口 使用 了 容器 中 定義 的 端口 名稱 HTTP, 這也 是 明確 為 容器 指明 要 暴露 的 端口 的 用途 之一。

設置TCP探針舉例:

apiVersion: v1
kind: Pod
metadata:
  labels:
    test: liveness-tcp
  name: liveness-tcp
spec:
  containers:
  - name: liveness-tcp-demo
    image: nginx:1.12-alpine
    ports:
    - name: http
      containerPort: 80
    livenessProbe:
      tcpSocket:
        port: http

上面的資源清單文件,向Pod IP的80/tcp端口發起連接請求,並根據連接建立的狀態判斷Pod存活狀態。

每次探測都將獲得以下三種結果之一:

  • 成功:容器通過了診斷。
  • 失敗:容器未通過診斷。
  • 未知:診斷失敗,因此不會采取任何行動。

Kubelet 可以選擇是否執行在容器上運行的兩種探針執行和做出反應:

  • livenessProbe指示容器是否正在運行。如果存活探測失敗,則 kubelet 會殺死容器,並且容器將受到其 重啟策略 的影響。如果容器不提供存活探針,則默認狀態為 Success
  • readinessProbe指示容器是否准備好服務請求。如果就緒探測失敗,端點控制器將從與 Pod 匹配的所有 Service 的端點中刪除該 Pod 的 IP 地址。初始延遲之前的就緒狀態默認為 Failure。如果容器不提供就緒探針,則默認狀態為 Success

(5)livenessProbe和readinessProbe使用場景

如果容器中的進程能夠在遇到問題或不健康的情況下自行崩潰,則不一定需要存活探針; kubelet 將根據 Pod 的restartPolicy 自動執行正確的操作。

如果希望容器在探測失敗時被殺死並重新啟動,那么請指定一個存活探針,並指定restartPolicy 為 Always 或 OnFailure。

如果要僅在探測成功時才開始向 Pod 發送流量,請指定就緒探針。在這種情況下,就緒探針可能與存活探針相同,但是 spec 中的就緒探針的存在意味着 Pod 將在沒有接收到任何流量的情況下啟動,並且只有在探針探測成功后才開始接收流量。

如果您希望容器能夠自行維護,您可以指定一個就緒探針,該探針檢查與存活探針不同的端點。

請注意,如果您只想在 Pod 被刪除時能夠排除請求,則不一定需要使用就緒探針;在刪除 Pod 時,Pod 會自動將自身置於未完成狀態,無論就緒探針是否存在。當等待 Pod 中的容器停止時,Pod 仍處於未完成狀態。

(6)Pod的重啟策略

PodSpec 中有一個 restartPolicy 字段,可能的值為 Always、OnFailure 和 Never。默認為 Always。 restartPolicy 適用於 Pod 中的所有容器。restartPolicy 僅指通過同一節點上的 kubelet 重新啟動容器。失敗的容器由 kubelet 以五分鍾為上限的指數退避延遲(10秒,20秒,40秒...)重新啟動,並在成功執行十分鍾后重置。pod一旦綁定到一個節點,Pod 將永遠不會重新綁定到另一個節點。

(7)Pod的生命

一般來說,Pod 不會消失,直到人為銷毀他們。這可能是一個人或控制器。這個規則的唯一例外是成功或失敗的 phase 超過一段時間(由 master 確定)的Pod將過期並被自動銷毀。

有三種可用的控制器:

  • 使用 Job 運行預期會終止的 Pod,例如批量計算。Job 僅適用於重啟策略為 OnFailure 或 Never 的 Pod。
  • 對預期不會終止的 Pod 使用 ReplicationControllerReplicaSet 和 Deployment ,例如 Web 服務器。 ReplicationController 僅適用於具有 restartPolicy 為 Always 的 Pod。
  • 提供特定於機器的系統服務,使用 DaemonSet 為每台機器運行一個 Pod 。

所有這三種類型的控制器都包含一個 PodTemplate。建議創建適當的控制器,讓它們來創建 Pod,而不是直接自己創建 Pod。這是因為單獨的 Pod 在機器故障的情況下沒有辦法自動復原,而控制器卻可以。

如果節點死亡或與集群的其余部分斷開連接,則 Kubernetes 將應用一個策略將丟失節點上的所有 Pod 的 phase 設置為 Failed。

 (8)livenessProbe解析

[root@k8s-master ~]# kubectl explain pod.spec.containers.livenessProbe

KIND:     Pod
VERSION:  v1

RESOURCE: livenessProbe <Object>

exec  command 的方式探測 例如 ps 一個進程
failureThreshold 探測幾次失敗 才算失敗 默認是連續三次
periodSeconds 每次的多長時間探測一次 默認10s
timeoutSeconds 探測超市的秒數 默認1s
initialDelaySeconds 初始化延遲探測,第一次探測的時候,因為主程序未必啟動完成
tcpSocket 檢測端口的探測
httpGet http請求探測

舉個例子:定義一個liveness的pod資源類型,基礎鏡像為busybox,在busybox這個容器啟動后會執行創建/tmp/test的文件啊,並刪除,然后等待3600秒。隨后定義了存活性探測,方式是以exec的方式執行命令判斷/tmp/test是否存在,存在即表示存活,不存在則表示容器已經掛了。

[root@k8s-master ~]# vim liveness.yaml

apiVersion: v1
kind: Pod
metadata:
  name: liveness-exec-pod
  namespace: default
  labels:
    name: myapp
spec:
  containers:
  - name: livess-exec
    image: busybox:latest
    imagePullPolicy: IfNotPresent
    command: ["/bin/sh","-c","touch /tmp/test; sleep 30; rm -f /tmp/test; sleep 3600"]
    livenessProbe:
      exec:
        command: ["test","-e","/tmp/test"]
      initialDelaySeconds: 1
      periodSeconds: 3
[root@k8s-master ~]# kubectl apply -f lineness.yaml 

 (9)資源需求和資源限制

 在Docker的范疇內,我們知道可以對運行的容器進行請求或消耗的資源進行限制。而在Kubernetes中,也有同樣的機制,容器或Pod可以進行申請和消耗的資源就是CPU和內存。CPU屬於可壓縮型資源,即資源的額度可以按照需求進行收縮。而內存屬於不可壓縮型資源,對內存的收縮可能會導致無法預知的問題。

資源的隔離目前是屬於容器級別,CPU和內存資源的配置需要Pod中的容器spec字段下進行定義。其具體字段,可以使用"requests"進行定義請求的確保資源可用量。也就是說容器的運行可能用不到這樣的資源量,但是必須確保有這么多的資源供給。而"limits"是用於限制資源可用的最大值,屬於硬限制。

在Kubernetes中,1個單位的CPU相當於虛擬機的1顆虛擬CPU(vCPU)或者是物理機上一個超線程的CPU,它支持分數計量方式,一個核心(1core)相當於1000個微核心(millicores),因此500m相當於是0.5個核心,即二分之一個核心。內存的計量方式也是一樣的,默認的單位是字節,也可以使用E、P、T、G、M和K作為單位后綴,或者是Ei、Pi、Ti、Gi、Mi、Ki等形式單位后綴。 

資源需求舉例:

apiVersion: v1
kind: Pod
metadata:
  name: nginx-pod
spec:
  containers:
  - name: nginx
    image: nginx
    resources:
      requests:
        memory: "128Mi"
        cpu: "200m"

上面的配置清單中,nginx請求的CPU資源大小為200m,這意味着一個CPU核心足以滿足nginx以最快的方式運行,其中對內存的期望可用大小為128Mi,實際運行時不一定會用到這么多的資源。考慮到內存的資源類型,在超出指定大小運行時存在會被OOM killer殺死的可能性,於是該請求值屬於理想中使用的內存上限。

資源限制舉例:

容器的資源需求只是能夠確保容器運行時所需要的最少資源量,但是並不會限制其可用的資源上限。當應用程序存在Bug時,也有可能會導致系統資源被長期占用的情況,這就需要另外一個limits屬性對容器進行定義資源使用的最大可用量。CPU是屬於可壓縮資源,可以進行自由地調節。而內存屬於硬限制性資源,當進程申請分配超過limit屬性定義的內存大小時,該Pod將會被OOM killer殺死。如下:

[root@k8s-master ~]# vim memleak-pod.yaml
apiVersion: v1
kind: Pod
metadata:
  name: memleak-pod
  labels:
    app: memleak
spec:
  containers:
  - name: simmemleak
    image: saadali/simmemleak
    resources:
      requests:
        memory: "64Mi"
        cpu: "1"
      limits:
        memory: "64Mi"
        cpu: "1"

[root@k8s-master ~]# kubectl apply -f memleak-pod.yaml 
pod/memleak-pod created
[root@k8s-master ~]# kubectl get pods -l app=memleak
NAME          READY     STATUS      RESTARTS   AGE
memleak-pod   0/1       OOMKilled   2          12s
[root@k8s-master ~]# kubectl get pods -l app=memleak
NAME          READY     STATUS             RESTARTS   AGE
memleak-pod   0/1       CrashLoopBackOff   2          28s

Pod資源默認的重啟策略為Always,在memleak因為內存限制而終止會立即重啟,此時該Pod會被OOM killer殺死,在多次重復因為內存資源耗盡重啟會觸發Kunernetes系統的重啟延遲,每次重啟的時間會不斷拉長,后面看到的Pod的狀態通常為"CrashLoopBackOff"。

 這里還需要明確的是,在一個Kubernetes集群上,運行的Pod眾多,那么當節點都無法滿足多個Pod對象的資源使用時,是按照什么樣的順序去終止這些Pod對象呢??

Kubernetes是無法自行去判斷的,需要借助於Pod對象的優先級進行判定終止Pod的優先問題。根據Pod對象的requests和limits屬性,Kubernetes將Pod對象分為三個服務質量類別:

  • Guaranteed:每個容器都為CPU和內存資源設置了相同的requests和limits屬性的Pod都會自動歸屬於該類別,屬於最高優先級。
  • Burstable:至少有一個容器設置了CPU或內存資源的requests屬性,單不滿足Guaranteed類別要求的資源歸於該類別,屬於中等優先級。
  • BestEffort:未對任何容器設置requests屬性和limits屬性的Pod資源,自動歸於該類別,屬於最低級別。

 

顧名思義,最低級別,死得越快!


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM