(五)Kubernetes Pod狀態和生命週期管理

什麼是Pod

Podkubernetes中你能夠建立和部署的最小也是最簡的單位。Pod表明着集羣中運行的進程。html

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

Dockerkubernetes中最經常使用的容器運行時,可是Pod也支持其餘容器運行時。nginx

Kubernetes集羣中Pod有以下兩種方式:web

  • 一個Pod中運行一個容器。「每一個Pod中一個容器」的模式是最多見的用法;在這種使用方式中,你能夠把Pod想象成單個容器的封裝,Kubernetes管理的是Pod而不是直接管理容器。vim

  • 在一個Pod中同時運行多個容器。一個Pod也能夠同時封裝幾個須要緊密耦合互相協做的容器,它們之間共享資源。這些在同一個Pod中的容器能夠互相協做成爲一個service單位——一個容器共享文件,另外一個「sidecar」容器來更新這些文件。Pod將這些容器的存儲資源做爲一個實體來管理。api

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

Pod中的容器共享IP地址和端口號,它們之間能夠經過localhost互相發現。它們之間能夠經過進程間通訊,例如SystemV信號或者POSIX共享內存。不一樣Pod之間的容器具備不一樣的IP地址,不能直接經過IPC通訊。網絡

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

就像每一個應用容器,pod被認爲是臨時(非持久的)實體。在Pod的生命週期中討論過,pod被建立後,被分配一個惟一的ID(UID),調度到節點上,並一致維持指望的狀態直到被終結(根據重啓策略)或者被刪除。若是node死掉了,分配到了這個node上的pod,在通過一個超時時間後會被從新調度到其餘node節點上。一個給定的pod(如UID定義的)不會被「從新調度」到新的節點上,而是被一個一樣的pod取代,若是指望的話甚至能夠是相同的名字,可是會有一個新的UIDide

Pod中如何管理多個容器

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

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

Pod中能夠共享兩種資源:網絡和存儲

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

存儲:能夠爲一個Pod指定多個共享的VolumePod中的全部容器均可以訪問共享的volumeVolume也能夠用來持久化Pod中的存儲資源,以防容器重啓後文件丟失。

使用Pod

你不多會直接在kubernetes中建立單個Pod。由於Pod的生命週期是短暫的,用後即焚的實體。當Pod被建立後(不管是由你直接建立仍是被其它Controller),都會被Kubernetes調度到集羣的Node上。直到Pod的進程終止、被刪掉、由於缺乏資源而被驅逐、或者Node故障以前這個Pod都會一直保持在那個Node上。

注意:重啓Pod中的容器跟重啓Pod不是一回事。Pod只提供容器的運行環境並保持容器的運行狀態,重啓容器不會形成Pod重啓。

Pod不會自愈。若是Pod運行的Node故障,或者是調度器自己故障,這個Pod就會被刪除。一樣的,若是Pod所在Node缺乏資源或者Pod處於維護狀態,Pod也會被驅逐。Kubernetes使用更高級的稱爲Controller的抽象層,來管理Pod實例。雖然能夠直接使用Pod,可是在Kubernetes中一般是使用Controller來管理Pod的。

Controller能夠建立和管理多個Pod,提供副本管理、滾動升級和集羣級別的自愈能力。例如,若是一個Node故障,Controller就能自動將該節點上的Pod調度到其餘健康的Node上。

Pod對象的生命週期

官方文檔

中文文檔

Pod對象自從其建立開始至其終止退出的時間範圍稱爲其生命週期。在這段時間中,Pod會處於多種不一樣的狀態,並執行一些操做;其中,建立主容器(main container)爲必需的操做,其餘可選的操做還包括運行初始化容器(init container)、容器啓動後鉤子(post start hook)、容器的存活性探測(liveness probe)、就緒性探測(readiness probe)以及容器終止前鉤子(pre stop hook)等,這些操做是否執行則取決於Pod的定義。以下圖所示:

Pod phase

Podstatus字段是一個PodStatus的對象,PodStatus中有一個phase字段。

不管是手動建立仍是經過Deployment等控制器建立,Pod對象老是應該處於其生命進程中如下幾個相位(phase)之一。

  • 掛起(Pending):API Server建立了pod資源對象已存入etcd中,但它還沒有被調度完成,或者仍處於從倉庫下載鏡像的過程當中。

  • 運行中(Running):Pod已經被調度至某節點,而且全部容器都已經被kubelet建立完成。

  • 成功(Succeeded):Pod中的全部容器都已經成功終止而且不會被重啓

  • 失敗(Failed):Pod中的全部容器都已終止了,而且至少有一個容器是由於失敗終止。即容器以非0狀態退出或者被系統禁止。

  • 未知(Unknown):Api Server沒法正常獲取到Pod對象的狀態信息,一般是因爲沒法與所在工做節點的kubelet通訊所致。

Pod的建立過程

Podkubernetes的基礎單元,理解它的建立過程對於瞭解系統運做大有裨益。以下圖描述了一個Pod資源對象的典型建立過程。

  1. 用戶經過kubectl或其餘API客戶端提交了Pod SpecAPI Server

  2. API Server嘗試着將Pod對象的相關信息存入etcd中,待寫入操做執行完成,API Server即會返回確認信息至客戶端。

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

  4. 全部的kubernetes組件均使用「watch」機制來跟蹤檢查API Server上的相關的變更。

  5. kube-scheduler(調度器)經過其「watcher」覺察到API Server建立了新的Pod對象但還沒有綁定至任何工做節點。

  6. kube-schedulerPod對象挑選一個工做節點並將結果信息更新至API Server

  7. 調度結果信息由API Server更新至etcd存儲系統,並且API Server也開始反映此Pod對象的調度結果。

  8. Pod被調度到的目標工做節點上的kubelet嘗試在當前節點上調用Docker啓動容器,並將容器的結果狀態返回送至API Server

  9. API ServerPod狀態信息存入etcd系統中。

  10. etcd確認寫入操做成功完成後,API Server將確認信息發送至相關的kubelet,事件將經過它被接受。

Pod生命週期中的重要行爲

1)初始化容器

初始化容器(init container)即應用程序的主容器啓動以前要運行的容器,經常使用於爲主容器執行一些預置操做,它們具備兩種典型特徵。

1)初始化容器必須運行完成直至結束,若某初始化容器運行失敗,那麼kubernetes須要重啓它直到成功完成。(注意:若是podspec.restartPolicy字段值爲「Never」,那麼運行失敗的初始化容器不會被重啓。)

2)每一個初始化容器都必須按定義的順序串行運行。

2)容器探測

容器探測(container probe)是Pod對象生命週期中的一項重要的平常任務,它是kubelet對容器週期性執行的健康狀態診斷,診斷操做由容器的處理器(handler)進行定義。Kubernetes支持三種處理器用於Pod探測:

  • ExecAction:在容器內執行指定命令,並根據其返回的狀態碼進行診斷的操做稱爲Exec探測,狀態碼爲0表示成功,不然即爲不健康狀態。

  • TCPSocketAction:經過與容器的某TCP端口嘗試創建鏈接進行診斷,端口可以成功打開即爲正常,不然爲不健康狀態。

  • HTTPGetAction:經過向容器IP地址的某指定端口的指定path發起HTTP GET請求進行診斷,響應碼爲2xx3xx時即爲成功,不然爲失敗。

任何一種探測方式均可能存在三種結果:「Success」(成功)「Failure」(失敗)「Unknown」(未知),只有success表示成功經過檢測。

容器探測分爲兩種類型:

  • 存活性探測(livenessProbe):用於斷定容器是否處於「運行」(Running)狀態;一旦此類檢測未經過,kubelet將殺死容器並根據重啓策略(restartPolicy)決定是否將其重啓;未定義存活檢測的容器的默認狀態爲「Success」。

  • 就緒性探測(readinessProbe):用於判斷容器是否準備就緒並可對外提供服務;未經過檢測的容器意味着其還沒有準備就緒,端點控制器(如Service對象)會將其IP從全部匹配到此Pod對象的Service對象的端點列表中移除;檢測經過以後,會再將其IP添加至端點列表中。

何時使用存活(liveness)和就緒(readiness)探針?

若是容器中的進程可以在遇到問題或不健康的狀況下自行崩潰,則不必定須要存活探針,kubelet將根據PodrestartPolicy自動執行正確的操做。

若是但願容器在探測失敗時被殺死並從新啓動,那麼請指定一個存活探針,並指定restartPolicyAlwaysOnFailure

若是要僅在探測成功時纔開始向Pod發送流量,請指定就緒探針。在這種狀況下,就緒探針可能與存活探針相同,可是spec中的就緒探針的存在乎味着Pod將在沒有接收到任何流量的狀況下啓動,而且只有在探針探測成功纔開始接收流量。

若是但願容器可以自行維護,能夠指定一個就緒探針,該探針檢查與存活探針不一樣的端點。

注意:若是隻想在Pod被刪除時可以排除請求,則不必定須要使用就緒探針;在刪除Pod時,Pod會自動將自身置於未完成狀態,不管就緒探針是否存在。當等待Pod中的容器中止時,Pod仍處於未完成狀態。

容器的重啓策略

PodSpec中有一個restartPolicy字段,可能的值爲AlwaysOnFailureNever。默認爲AlwaysrestartPolicy適用於Pod中的全部容器。並且它僅用於控制在同一節點上從新啓動Pod對象的相關容器。首次須要重啓的容器,將在其須要時當即進行重啓,隨後再次須要重啓的操做將由kubelet延遲一段時間後進行,且反覆的重啓操做的延遲時長依次爲10秒、20秒、40秒... 300秒是最大延遲時長。事實上,一旦綁定到一個節點,Pod對象將永遠不會被從新綁定到另外一個節點,它要麼被重啓,要麼終止,直到節點發生故障或被刪除。

  • Always:但凡Pod對象終止就將其重啓,默認值

  • OnFailure:僅在Pod對象出現錯誤時方纔將其重啓

  • Never:從不重啓

Pod存活性探測示例

設置exec探針示例

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

[root@k8s-master ~]# kubectl create -f manfests/liveness-exec.yaml    #建立pod
pod/liveness-exec-pod created
[root@k8s-master ~]# kubectl get pods   #查看pod
NAME                READY   STATUS    RESTARTS   AGE
liveness-exec-pod   1/1     Running   0          6s

#等待一段時間後再次查看其狀態
[root@k8s-master ~]# kubectl get pods
NAME                READY   STATUS    RESTARTS   AGE
liveness-exec-pod   1/1     Running   2          2m46s

上面的資源清單中定義了一個pod對象,基於busybox鏡像啓動一個運行「touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 3600"命令的容器,此命令在容器啓動時建立了/tmp/healthy文件,並於60秒以後將其刪除。存活性探針運行」test -e /tmp/healthy"命令檢查/tmp/healthy文件的存在性,若文件存在則返回狀態碼0,表示成功經過測試。在60秒內使用「kubectl describe pods/liveness-exec-pod」查看其詳細信息,其存活性探測不會出現錯誤。而超過60秒以後,再執行該命令查看詳細信息,能夠發現存活性探測出現了故障,而且還可經過「kubectl get pods"查看該pod的重啓的相關信息。

設置HTTP探針示例

基於HTTP的探測(HTTPGetAction)向目標容器發起一個HTTP請求,根據其響應碼進行結果斷定,響應碼如2xx3xx時表示測試經過。經過該命令」# kubectl explain pod.spec.containers.livenessProbe.httpGet「查看httpGet定義的字段

host    <string>:請求的主機地址,默認爲Pod IP,也能夠在httpHeaders中使用「Host:」來定義。
httpHeaders    <[]Object>:自定義的請求報文首部。
port    <string>:請求的端口,必選字段。
path    <string>:請求的HTTP資源路徑,即URL path。
scheme    <string>:創建鏈接使用的協議,僅可爲HTTP或HTTPS,默認爲HTTP。
[root@k8s-master ~]# vim manfests/liveness-httpget.yaml
apiVersion: v1
kind: Pod
metadata:
  name: liveness-http
  namespace: default
  labels:
    test: liveness
spec:
  containers:
    - name: liveness-http-demo
      image: nginx:1.12
      imagePullPolicy: IfNotPresent
      ports:
      - name: http
        containerPort: 80
      lifecycle:
        postStart:
          exec:
            command: ["/bin/sh", "-c", "echo Healthz > /usr/share/nginx/html/healthz"]
      livenessProbe:
        httpGet:
          path: /healthz
          port: http
          scheme: HTTP
[root@k8s-master ~]# kubectl create -f manfests/liveness-httpget.yaml    #建立pod
pod/liveness-http created
[root@k8s-master ~]# kubectl get pods    #查看pod
NAME            READY   STATUS    RESTARTS   AGE
liveness-http   1/1     Running   0          7s

[root@k8s-master ~]# kubectl describe pods/liveness-http    #查看liveness-http詳細信息
......
Containers:
  liveness-http-demo:
......
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Mon, 09 Sep 2019 15:43:29 +0800
    Ready:          True
    Restart Count:  0
......

上面清單中定義的httpGet測試中,經過lifecycle中的postStart hook建立了一個專用於httpGet測試的頁面文件healthz,請求的資源路徑爲"/healthz",地址默認爲Pod IP,端口使用了容器中頂一個端口名稱http,這也是明確了爲容器指明要暴露的端口的用途之一。並查看健康狀態檢測相關的信息,健康狀態檢測正常時,容器也將正常運行。下面經過「kubectl exec」命令進入容器刪除由postStart hook建立的測試頁面healthz。再次查看容器狀態

[root@k8s-master ~]# kubectl exec pods/liveness-http -it -- /bin/sh    #進入到上面建立的pod中
# rm -rf /usr/share/nginx/html/healthz   #刪除healthz測試頁面
# 

[root@k8s-master ~]# kubectl get pods 
NAME            READY   STATUS    RESTARTS   AGE
liveness-http   1/1     Running   1          10m

[root@k8s-master ~]# kubectl describe pods/liveness-http
......
Containers:
  liveness-http-demo:
......
    Port:           80/TCP
    Host Port:      0/TCP
    State:          Running
      Started:      Mon, 09 Sep 2019 15:53:04 +0800
    Last State:     Terminated
      Reason:       Completed
      Exit Code:    0
      Started:      Mon, 09 Sep 2019 15:43:29 +0800
      Finished:     Mon, 09 Sep 2019 15:53:03 +0800
    Ready:          True
    Restart Count:  1
......

經過上面測試能夠看出,當發起http請求失敗後,容器將被殺掉後進行了從新構建。

設置TCP探針

基於TCP的存活性探測(TCPSocketAction)用於向容器的特定端口發起TCP請求並創建鏈接進行結果斷定,鏈接創建成功即爲經過檢測。相比較來講,它比基於HTTP的探測要更高效、更節約資源,但精確度略低,畢竟鏈接創建成功未必意味着頁面資源可用。經過該命令」# kubectl explain pod.spec.containers.livenessProbe.tcpSocket「查看tcpSocket定義的字段

host    <string>:請求鏈接的目標IP地址,默認爲Pod IP
port    <string>:請求鏈接的目標端口,必選字段
[root@k8s-master ~]# vim manfests/liveness-tcp.yaml
apiVersion: v1
kind: Pod
metadata:
  name: liveness-tcp-pod
  namespace: default
  labels:
    test: liveness-tcp
spec:
  containers:
  - name: liveness-tcp-demo
    image: nginx:1.12
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80
    livenessProbe:
      tcpSocket:
        port: http

上面清單中定義的tcpSocket測試中,經過向容器的80端口發起請求,若是端口正常,則代表正常運行。

livenessProbe行爲屬性

[root@k8s-master ~]# kubectl explain pods.spec.containers.livenessProbe
KIND:     Pod
VERSION:  v1

RESOURCE: livenessProbe <Object>

exec   command 的方式探測,例如 ps 一個進程是否存在

failureThreshold    探測幾回失敗 纔算失敗, 默認是連續三次

initialDelaySeconds  初始化延遲探測,即容器啓動多久以後再開始探測,默認爲0秒

periodSeconds  每隔多久探測一次,默認是10秒

successThreshold  處於失敗狀態時,探測操做至少連續多少次的成功纔算經過檢測,默認爲1秒

timeoutSeconds  存活性探測的超時時長,默認爲1秒

httpGet   http請求探測

tcpSocket    端口探測

Pod就緒性探測示例

Pod對象啓動後,容器應用一般須要一段時間才能完成其初始化過程,例如加載配置或數據,甚至有些程序須要運行某類的預熱過程,若在這個階段完成以前即接入客戶端的請求,勢必會等待過久。所以,這時候就用到了就緒性探測(readinessProbe)。

與存活性探測機制相似,就緒性探測是用來判斷容器就緒與否的週期性(默認週期爲10秒鐘)操做,它用於探測容器是否已經初始化完成並可服務於客戶端請求,探測操做返回」success「狀態時,即爲傳遞容器已經」就緒「的信號。

就緒性探測也支持ExecHTTPGetTCPSocket三種探測方式,且各自的定義機制也都相同。但與存活性探測觸發的操做不一樣的是,探測失敗時,就緒探測不會殺死或重啓容器以保證其健康性,而是通知其還沒有就緒,並觸發依賴於其就緒狀態的操做(例如,從Service對象中移除此Pod對象)以確保不會有客戶端請求接入此Pod對象。

這裏只是示例http探針示例,不管是httpGet仍是exec仍是tcpSocket和存活性探針相似。

設置HTTP探針示例

#終端1:
[root@k8s-master ~]# vim manfests/readiness-httpget.yaml  #編輯readiness-httpget測試pod的yaml文件
apiVersion: v1
kind: Pod
metadata:
  name: readiness-http
  namespace: default
  labels:
    test: readiness-http
spec:
  containers:
  - name: readiness-http-demo
    image: nginx:1.12
    imagePullPolicy: IfNotPresent
    ports:
    - name: http
      containerPort: 80
    readinessProbe:
      httpGet:
        path: /index.html
        port: http
        scheme: HTTP
[root@k8s-master ~]# kubectl create -f manfests/readiness-httpget.yaml    #建立pod
pod/readiness-http created
[root@k8s-master ~]# kubectl get pods      查看pod狀態
NAME               READY   STATUS    RESTARTS   AGE
liveness-tcp-pod   1/1     Running   1          7d18h
readiness-http     1/1     Running   0          7s


#新打開一個終端2進入到容器裏面
[root@k8s-master ~]# kubectl exec pods/readiness-http -it -- /bin/sh    #進入上面建立的pod
# rm -f /usr/share/nginx/html/index.html     #刪除nginx的主頁面文件
# ls /usr/share/nginx/html
50x.html
# 


#回到終端1上面查看pod狀態
[root@k8s-master ~]# kubectl get pods     #查看pod狀態
NAME               READY   STATUS    RESTARTS   AGE
liveness-tcp-pod   1/1     Running   1          7d18h
readiness-http     0/1     Running   0          2m44s

經過上面測試能夠看出,當咱們刪除了nginx主頁文件後,readinessProbe發起的測試就會失敗,此時咱們再查看pod的狀態會發現並不會將pod刪除從新啓動,只是在READY字段能夠看出,當前的Pod處於未就緒狀態。

相關文章
相關標籤/搜索