k8s--pod 生命周期、初始化容器、鈎子函數


pod 生命周期

我們一般將 pod 對象從創建至終的這段時間范圍稱為 pod 的生命周期,它主要包含下面的過程

  • pod 創建過程
  • 運行初始化容器(init container)過程
  • 運行主容器(main container)
    • 容器啟動后鈎子(post start)、容器終止前鈎子(pre stop)
    • 容器的存活性探測(liveness probe)、就緒性探測(readiness probe)
  • pod 終止過程

在整個生命周期中,pod 會出現 5 種狀態(相位),分別如下

  • 掛起(Pending):apiserver 已經創建了 pod 資源對象,但它尚未被調度完成或者仍處於下載鏡像的過程中
  • 運行中(Running):pod 已經被調度至某節點,並且所有容器都已經被 kubelet 創建完成
  • 成功(Succeeded):pod 中的所有容器都已經成功終止並且不會被重啟
  • 失敗(Failed):所有容器都已經終止,但至少有一個容器終止失敗,即容器返回了非 0 值的退出狀態
  • 未知(Unknown):apiserver 無法正常獲取到 pod 對象的狀態信息,通常由網絡通信失敗所導致

創建和終止

pod 的創建過程

  1. 用戶通過 kubectl 或其他 api 客戶端提交需要創建的 pod 信息給 apiServer

  2. apiServer 開始生成 pod 對象的信息,並將信息存入 etcd,然后返回確認信息至客戶端

  3. apiServer 開始反映 etcd 中的 pod 對象的變化,其它組件使用 watch 機制來跟蹤檢查 apiServer 上的變動

  4. scheduler 發現有新的 pod 對象要創建,開始為 Pod 分配主機並將結果信息更新至 apiServer

  5. node 節點上的 kubelet 發現有 pod 調度過來,嘗試調用 docker 啟動容器,並將結果回送至 apiServer

  6. apiServer 將接收到的 pod 狀態信息存入 etcd 中

pod 的終止過程

  1. 用戶向 apiServer 發送刪除 pod 對象的命令
  2. apiServcer 中的 pod 對象信息會隨着時間的推移而更新,在寬限期內(默認30s),pod 被視為 dead
  3. 將 pod 標記為 terminating 狀態
  4. kubelet 在監控到 pod 對象轉為 terminating 狀態的同時啟動 pod 關閉過程
  5. 端點控制器監控到 pod 對象的關閉行為時將其從所有匹配到此端點的 service 資源的端點列表中移除
  6. 如果當前 pod 對象定義了 preStop 鈎子處理器,則在其標記為 terminating 后即會以同步的方式啟動執行
  7. pod 對象中的容器進程收到停止信號
  8. 寬限期結束后,若 pod 還存在仍在運行的進程,那么 pod 對象會收到立即終止的信號
  9. kubelet 請求 apiServer 將此 pod 資源的寬限期設置為 0 從而完成刪除操作,此時 pod 對於用戶已不可見

初始化容器

初始化容器是在 pod 的主容器啟動之前要運行的容器,主要是做一些主容器的前置工作,它具有兩大特征:

  • 初始化容器必須運行完成直至結束,若某初始化容器運行失敗,那么 kubernetes 需要重啟它直到成功完成
  • 初始化容器必須按照定義的順序執行,當且僅當前一個成功之后,后面的一個才能運行

初始化容器有很多的應用場景,下面列出的是最常見的幾個

  • 提供主容器鏡像中不具備的工具程序或自定義代碼
  • 初始化容器要先於應用容器啟動

接下來做一個案例,模擬下面這個需求:

假設要以主容器來運行 nginx,但是要求在運行 nginx 之前先要能夠連接上 mysql 和 redis 所在服務器

為了簡化測試,事先規定好mysql(192.168.90.14)和redis(192.168.90.15)服務器的地址

創建 pod-initcontainer.yaml,內容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-initcontainer
  namespace: zouzou
spec:
  containers:
  - name: main-container
    image: nginx:1.14
    ports: 
    - name: nginx-port
      containerPort: 80
  initContainers: # 初始化容器,有兩個,分別 ping mysql 和 redis,mysql 可以 ping 通才會 ping redis
  - name: test-mysql
    image: busybox:1.30
    command: ['sh', '-c', 'until ping 192.168.90.14 -c 1 ; do echo waiting for mysql...; sleep 2; done;']
  - name: test-redis
    image: busybox:1.30
    command: ['sh', '-c', 'until ping 192.168.90.15 -c 1 ; do echo waiting for reids...; sleep 2; done;']

執行下面命令

# 創建pod
[root@dce-10-6-215-215 ~]# kubectl create -f pod-initcontainer.yaml
pod/pod-initcontainer created

# 查看pod狀態
# 發現pod卡在啟動第一個初始化容器過程中,后面的容器不會運行
[root@dce-10-6-215-215 ~]# kubectl describe pod  pod-initcontainer -n zouzou
........
Events:
  Type    Reason     Age   From               Message
  ----    ------     ----  ----               -------
  Normal  Scheduled  49s   default-scheduler  Successfully assigned dev/pod-initcontainer to node1
  Normal  Pulled     48s   kubelet, node1     Container image "busybox:1.30" already present on machine
  Normal  Created    48s   kubelet, node1     Created container test-mysql
  Normal  Started    48s   kubelet, node1     Started container test-mysql

# 動態查看pod
[root@dce-10-6-215-215 ~]# kubectl get pods pod-initcontainer -n zouzou -w
NAME                             READY   STATUS     RESTARTS   AGE
pod-initcontainer                0/1     Init:0/2   0          15s
pod-initcontainer                0/1     Init:1/2   0          52s
pod-initcontainer                0/1     Init:1/2   0          53s
pod-initcontainer                0/1     PodInitializing   0          89s
pod-initcontainer                1/1     Running           0          90s

# 接下來新開一個shell,為當前服務器新增兩個ip,觀察pod的變化
[root@dce-10-6-215-215 ~]# ifconfig ens33:1 192.168.90.14 netmask 255.255.255.0 up
[root@dce-10-6-215-215 ~]# ifconfig ens33:2 192.168.90.15 netmask 255.255.255.0 up

鈎子函數

鈎子函數能夠感知自身生命周期中的事件,並在相應的時刻到來時運行用戶指定的程序代碼

k8s 在主容器的啟動之后和停止之前提供了兩個鈎子函數

  • post start:容器創建之后執行,如果失敗了會重啟容器
  • pre stop:容器終止之前執行,執行完成之后容器將成功終止,在其完成之前會阻塞刪除容器的操作

鈎子處理器支持使用下面三種方式定義動作

  • Exec 命令:在容器內執行一次命令
……
  lifecycle:
    postStart: 
      exec:
        command:
        - cat
        - /tmp/healthy
……
  • TCPSocket:在當前容器嘗試訪問指定的 socket
……      
  lifecycle:
    postStart:
      tcpSocket:
        port: 8080
……
  • HTTPGet:在當前容器中向某 url 發起 http 請求
……
  lifecycle:
    postStart:
      httpGet:
        path: / #URI地址
        port: 80 #端口號
        host: 192.168.5.3 #主機地址
        scheme: HTTP #支持的協議,http或者https
……

接下來,以 exec 方式為例,演示下鈎子函數的使用,創建 pod-hook-exec.yaml 文件,內容如下:

apiVersion: v1
kind: Pod
metadata:
  name: pod-hook-exec
  namespace: zouzou
spec:
  containers:
  - name: main-container
    image: nginx:1.14
    ports:
    - name: nginx-port
      containerPort: 80
    lifecycle:
      postStart:
        exec: # 在容器啟動的時候執行一個命令,修改掉 nginx 的默認首頁內容
          command: ["/bin/sh", "-c", "echo postStart... > /usr/share/nginx/html/index.html"]
      preStop:
        exec: # 在容器停止之前停止nginx服務,這個效果在這里看不到
          command: ["/usr/sbin/nginx","-s","quit"]

啟動 pod,查看內容

# 創建 pod
[root@dce-10-6-215-215 tmp]# kubectl apply -f pod-hook-exec.yaml
pod/pod-hook-exec created

# 查看 pod 的詳細信息
[root@dce-10-6-215-215 tmp]# kubectl get pod pod-hook-exec -n zouzou -o wide
NAME            READY   STATUS    RESTARTS   AGE   IP              NODE               NOMINATED NODE   READINESS GATES
pod-hook-exec   1/1     Running   0          48s   172.29.34.229   dce-10-6-215-200   <none>           <none>

# 查看內容,可以看到返回的是更改后的
[root@dce-10-6-215-215 tmp]# curl 172.29.34.229:80
postStart...

 


免責聲明!

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



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