1. 程式人生 > 其它 >深入理解Pod-初始化容器

深入理解Pod-初始化容器

1、什麼是Init Container?

Init Container 就是⽤來做初始化⼯作的容器,可以是⼀個或者多個。如果有多個的話,這些容器會按定義的順序依次執行,只有所有的 Init Container 執行完後,主容器才會被啟動。我們知道⼀個 Pod ⾥⾯的所有容器是共享資料卷和網路名稱空間的,所以 Init Container ⾥⾯產生的資料可以被主容器使⽤到的。

其實, Init Container 和前面講的鉤⼦函式有點類似,只是鉤子函式是在容器執⾏前來做⼀些⼯作。從直觀的⻆度看上去的話,初始化容器的確有點像 PreStart ,但是鉤⼦函式和我們的 Init Container 是處在不同的階段的,我們可以通過下⾯的圖來了解下:

從上⾯這張圖我們可以直觀的看到 PostStart 和 PreStop 函式包括 liveness 和 readiness 探針是屬於主容器生命週期範圍內的,而 Init Container 是獨⽴於主容器之外的,當然他們都屬於 Pod 的⽣命週期範疇之內的,這就是 Init Container 和鉤子函式之類的區別。

從上面的圖我們可以看到 Pod 右邊還有⼀個 infra 的容器,這是⼀個什麼容器呢?我們可以在叢集環境中去檢視下⼈任意⼀個 Pod 對應的運⾏的 Docker 容器,我們可以發現每⼀個 Pod 下⾯都包含了⼀個 pause-amd64 的映象,這個就是我們的 infra 映象,我們知道 Pod 下⾯的所有容器是共享同⼀個⽹絡名稱空間的,這個映象就是來做這個事情的,所以每⼀個 Pod 當中都會包含⼀個這個映象。

注:很多同學最開始 Pod 啟動不起來就是因為這個 infra 映象沒有被拉下來,因為預設該映象是需要到⾕歌伺服器上拉取的,所以需要提前拉取到節點上⾯

2、Init Container應用場景

Init Container 主要是來做初始化容器⼯作的,那麼他有哪些應⽤場景呢?

  • 等待其他模組Ready:這個可以⽤來解決服務之間的依賴問題,例如我們有⼀個 Web 服務,該服務⼜依賴於另外⼀個數據庫服務,但是在我們啟動這個 Web 服務的時候我們並不能保證依賴的這個資料庫服務就已經啟動起來了,所以可能會出現⼀段時間內 Web 服務連線資料庫異常。要解決這個問題的話我們就可以在 Web 服務的 Pod 中使⽤⼀個 Init Container,在這個初始化容器中去檢查資料庫是否已經準備好了,準備好了過後初始化容器就結束退出,然後我們的主容器 Web 服務被啟動起來,這個時候去連線資料庫就不會有問題了。
  • 初始化配置:例如叢集⾥檢測所有已經存在的成員節點,為主容器準備好叢集的配置資訊,這樣主容器起來後就能⽤這個配置資訊加⼊叢集。
  • 其它場景:例如將 pod 註冊到⼀箇中央資料庫、配置中⼼等。

等待其他模組Ready

我們還是通過示例的方式先來給⼤家演示下服務依賴的場景下初始化容器的使⽤方法,Pod 的定義方法如下:

apiVersion: v1
kind: Pod
metadata:
  name: init-pod
  labels:
    app: init
spec:
  containers:
  - name: main-container
    image: busybox
    command: ['sh', '-c', 'echo The app is running! && sleep 3600']
  initContainers:
  - name: init-myservice
    image: busybox
    command: ['sh', '-c', 'until nslookup myservice; do echo waiting for myservice; sleep 2; done;']
  - name: init-mydb
    image: busybox
    command: ['sh', '-c', 'until nslookup mydb; do echo waiting for mydb; sleep 2; done;']

通過 kubectl get pods 我們可以看到 REDY 0/1 表示還有1個主容器沒有準備好;Init:0/2 表示有兩個初始化容器,都還沒有準備好。

檢視帶初始化容器的pod的詳情,main-container裡面還在waiting

kubectl describe pod main-pod1

通過yaml的方式啟動myservice服務 和 mydb 服務,然後檢視main-pod1的狀態

kind: Service
apiVersion: v1
metadata:
  name: myservice
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 6376
---
kind: Service
apiVersion: v1
metadata:
  name: mydb
spec:
  ports:
  - protocol: TCP
    port: 80
    targetPort: 6377

檢視帶初始化容器的pod的詳

跟上邊的最初的init 0:2已經完全不一樣

通過初始化容器下載某個html到volumes上,然後在將volumes中的html掛載到主容器

apiVersion: v1
kind: Pod
metadata:
  name: init-demo
spec:
  containers:
  - name: nginx
    image: nginx
    ports:
    - containerPort: 80
    volumeMounts:
    - name: workdir
      mountPath: /usr/share/nginx/html
  initContainers:
  - name: install
    image: busybox
    command:
    - wget
    - "-O"
    - "/work-dir/index.html"
    - http://www.idig8.com
    volumeMounts:
    - name: workdir
      mountPath: "/work-dir"
  volumes:
  - name: workdir
    emptyDir: {}

編譯 yaml

進入容器檢視是否是init下載的html

kubectl exec -it init-demo -- /bin/bash
# 進入容器
cd /usr/share/nginx/html
cat html

檢視某一個init-container的日誌

kubectl logs main-pod1 -c init-myservice

參考:

https://blog.z0ukun.com/?p=1456

https://cloud.tencent.com/developer/article/1491377

https://kubernetes.io/zh/docs/concepts/workloads/pods/init-containers/