Init Container 概述
Init Container(Init 容器)
?是一種特殊容器,在 Pod 內的應用容器啟動之前運行,執行相關的初始化操作。Init 容器可以包括一些應用鏡像中不存在的?實用工具
?和?安裝腳本
?。
每個 Pod 中可以包含一個或多個容器, App 應用運行在這些 Container 容器里面,同樣 Pod 中的?Init 容器
?也可以有一個或多個(先于應用容器啟動),用于完成應用容器所需的預置條件,如下圖所示:
Init 容器與 應用容器非常像(在本質上是一樣的),除了以下特點:
??它們僅運行一次就結束的任務,總是運行到成功完成。
??每個?
Init Container
?都必須在下一個啟動之前成功完成才能繼續執行。
說明:多個 Init 容器 存在的情況,這些 Init 容器 會按先后順序?
線性執行
,并且每個 Init 容器 必須成功完成,下一個 Init 容器 才能執行;而多個應用容器可?并行執行
。
依據 Pod 的重啟策略(RestartPolicy
),如果 Pod 的 Init 容器失敗,并且Pod 設置了?RestartPolicy=Never
?時,則 Kubernetes 會將整個 Pod 狀態設置為失敗。而設置了?RestartPolicy=Always
?時,kubelet 會不斷地重啟該 Init 容器直到該容器成功為止。
Init Container 應用場景
講解了 Init Container 的使用,接下來介紹 Init Container 有哪些應用場景。
在很多的應用場景中,應用在啟動之前都需要執行如下初始化操作:
??等待其他關聯組件運行(例如:數據庫或某個后臺服務)。
??基于環境變量(env)或者配置模板生成配置文件。
??從遠程數據庫獲取本地所需的配置信息(類似配置中心),或者將自身注冊到某個中央數據庫中(類似服務注冊)。
??下載相關依賴包,或者對系統進行一些預配置操作。
??應用 Init Container 對集群環境進行故障排查。與其他幾種應用場景相比較特殊。
關于這些應用場景的示例,這里不再詳述,生產環境中依據自己的實際情況按照示例配置使用即可。
??《應用 Init Container 故障排查》:https://kubernetes.io/zh-cn/docs/tasks/debug/debug-application/debug-init-containers/
如何使用 Init Container ?
為 Pod 設置?Init Container
?需要在 Pod?spec 規約
?中添加?initContainers
?字段, 該字段以 Container 類型對象數組的形式組織,和應用的?containers
?數組同級相鄰。
Init Container
?的狀態在?status.initContainerStatuses
?字段中以容器狀態數組的格式返回 (類似?status.containerStatuses
?字段)。
示例一
舉例:定義一個具有 2 個?Init Container
?的簡單 Pod。第一個等待 init-myservice 啟動, 第二個等待 init-mydb 啟動。一旦這兩個?Init Container
?都啟動完成,Pod 將啟動?spec
?節中的應用容器。?myapp-pod.yaml
?文件定義如下所示:
apiVersion:?v1
kind:?Pod
metadata:name:?myapp-podlabels:app.kubernetes.io/name:?MyApp
spec:containers:-?name:?myapp-containerimage:?busybox:1.28command:?['sh',?'-c',?'echo?The?app?is?running!?&&?sleep?3600']initContainers:-?name:?init-myserviceimage:?busybox:1.28command:?['sh',?'-c',?"until?nslookup?myservice.$(cat?/var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local;?do?echo?waiting?for?myservice;?sleep?2;?done"]-?name:?init-mydbimage:?busybox:1.28command:?['sh',?'-c',?"until?nslookup?mydb.$(cat?/var/run/secrets/kubernetes.io/serviceaccount/namespace).svc.cluster.local;?do?echo?waiting?for?mydb;?sleep?2;?done"]
執行命令創建上面定義的 Pod:
kubectl?apply?-f?myapp-pod.yaml
pod/myapp-pod?created
檢查該 Pod 狀態信息:
kubectl?get?-f??myapp-pod.yaml
輸出信息:
NAME????????READY?????STATUS?????RESTARTS???AGE
myapp-pod???0/1???????Init:0/2???0??????????6m
查看 Pod 更多詳細信息:
kubectl?describe?-f?myapp-pod.yaml
查看 Pod 內 Init 容器的日志:
kubectl?logs?myapp-pod?-c?init-myservice??#?查看第一個?Init?容器
kubectl?logs?myapp-pod?-c?init-mydb? ? ? ?#?查看第二個?Init?容器
說明:通過查看 Pod 狀態、詳細信息或者內部的 Init 容器日志,可以進一步的排查 Pod 異常的原因。
從上面輸出的信息中,可以看到?STATUS
?的值為?Init:0/2
?,說明該 Pod 內有 2 個?Init Container
,并且 Pod 的?READY
?為?0/1
?未就緒態,原因是由于我們定義的 2 個?Init Container
?需要對應的?Service
?依賴,接下來我們繼續創建對應的?Service
,myapp-pod-initc-svc.yaml
?文件定義如下:
apiVersion:?v1
kind:?Service
metadata:name:?myservice
spec:ports:-?protocol:?TCPport:?80targetPort:?9376
---
apiVersion:?v1
kind:?Service
metadata:name:?mydb
spec:ports:-?protocol:?TCPport:?80targetPort:?9377
執行命令 創建 mydb 和 myservice 服務:
kubectl?create?-f?myapp-pod-initc-svc.yaml
輸出信息:
service?"myservice"?created
service?"mydb"?created
然后我們再次查看 Pod 狀態信息:
kubectl?get?-f??myapp-pod.yaml
輸出信息:
NAME????????READY?????STATUS????RESTARTS???AGE
myapp-pod???1/1???????Running???0??????????9m
看到 Pod 的?STATUS
?的值為?Running
?并且?READY
?為?1/1
?,此時說明該 Pod 創建成功,就緒態可提供服務了。
理解 Pod 的狀態
以?Init:
?開頭的 Pod 狀態匯總了?Init 容器
?執行的狀態。下表介紹調試 Init 容器時可能看到的一些狀態值示例。
狀態 | 含義 |
Init:N/M | Pod 包含 M 個 Init 容器,其中 N 個已經運行完成。 |
Init:Error | Init 容器已執行失敗。 |
Init:CrashLoopBackOff | Init 容器執行總是失敗。 |
Pending | Pod 還沒有開始執行 Init 容器。 |
PodInitializing or Running | Pod 已經完成執行 Init 容器。 |
示例二
以 Nginx 為例,在啟動 Nginx 之前,通過初始化容器 busybox 為 Nginx 創建一個 index.html 主頁文件。
說明:此處 init container 和 Nginx 設置了一個共享的 Volume,提供 Nginx 訪問 init container 設置的 index.html 文件。
nginx-initc.yaml
?文件定義如下:
apiVersion:?v1
kind:?Pod
metadata:name:?myNginxlabels:app.kubernetes.io/name:?myNginx
spec:initContainers:-?name:?init-installimage:?busybox:1.34.1command:?-?wget-?"-O"-?"/work-dir/index.html"-?http://kubernetes.iovolumeMounts:-?mountPath:?"/workdir"name:?workdircontainers:-?name:?myNginx-containerimage:?nginx:1.23.1-alpineports:?-?containerPort:?80volumeMounts:-?mountPath:?"/usr/share/nginx/html"name:?workdirdnsPolicy:?Defaultvolumes:-?name:?workdiremptyDir:?{}
創建?nginx-initc.yaml
?文件定義的 Pod:
kubectl?create?-f?nginx-initc.yaml
輸出信息:
pod?"myNginx"?created
查看 Pod 信息:
kubectl?get?pods
查看 Pod 詳細信息:
kubectl?describe?pod?myNginx
啟動成功后,登錄 Nginx 容器,可以看到?/usr/share/nginx/html
?目錄下的?index.html
?文件為 init container 所生成,其內容為(如下偽代碼)Kubernetes 的官網首頁:
<!DOCTYPE?html>
<html?lang="en">
<head><meta?charset="UTF-8"><meta?http-equiv="X-UA-Compatible"?content="IE=edge"><meta?name="viewport"?content="width=device-width,?initial-scale=1.0"><title>Kubernetes</title>
</head>
<body><H1>Production-Grade?Container?Orchestration</H1><script?src="/js/xxx.js"></script>
</body>
</html>
與普通容器的區別
Init 容器
?支持應用容器的全部字段和特性,包括資源限制、數據卷和安全設置。然而,Init 容器對資源請求和限制的處理稍有不同,在下面資源節有說明。
同時?Init 容器
?不支持?lifecycle、livenessProbe、readinessProbe
?和?startupProbe
, 因為它們必須在 Pod 就緒之前運行完成。
如果為一個 Pod 指定了多個 Init 容器,這些容器會?按順序逐個運行
。每個 Init 容器必須運行成功,下一個才能夠運行。當所有的 Init 容器運行完成時, Kubernetes 才會為 Pod 初始化應用容器并像平常一樣運行。
Init Container 與 普通應用容器他們之間的區別總結如下:
(1) init container 的?運行方式
?與 應用容器不同,它們必須先于應用容器執行完成,當 Pod 設置了多個?init container
?時,將按順序逐個運行(線性執行),并且只有前一個 init container 運行成功才能運行后一個 init container。當所有 init container 都成功運行后,Kubernetes 才會初始化 Pod 的各種信息,并開始創建和運行應用容器。
(2) 在 init container 的定義中也可以設置資源限制、Volume 的使用和 安全策略 等等。但?資源限制
?的設置與應用容器略有不同。
??如果多個 init container 都定義了資源請求/資源限制,則取最大的值作為所有 init container 的資源請求值/資源限制值。
? Pod 的有效(effective) 資源請求值/資源限制值取以下二者中的較大值。a) 所有應用容器的資源請求值/資源限制值之和。b) init container 的有效資源請求值/資源限制值。
??調度算法將基于 Pod 的有效資源請求值/資源限制值進行計算,也就是說 init container 可以為初始化操作預留系統資源,即使后續應用容器無須使用這些資源,Pod 的有效 Qos(Quality of Service,服務等級) 等級適用于 init container 和應用容器。
??資源配額和限制將根據 Pod 的有效資源請求值/資源限制值計算生效。
? Pod 級別的 cgroup 將基于 Pod 的有效資源請求/限制,與調度機制一致。
(3) init container 不能設置?readinessProbe
?探針,因為必須在它們成功運行后才能繼續運行在 Pod 中定義的普通容器。
在Pod重新啟動時,init container 將會重新運行,常見的 Pod 重啟場景如下:
??
init container
?的鏡像被更新時,init container 將會重新運行,導致 Pod重啟。僅更新應用容器的鏡像只會使得應用容器被重啟。? Pod 的?
infrastructure
?容器更新時,Pod 將會重啟。??若 Pod 中的所有應用容器都終止了,并且設置了?
RestartPolicv=Alwavs
?時,則 Pod 會重啟。
Pod 知識擴展
關于Pod 的其他屬性配置,如上面的【Pod 生命周期】圖中的更多信息請查看:
??《Init 容器》,https://kubernetes.io/zh-cn/docs/concepts/workloads/pods/init-containers/
??《調試 Init 容器》,https://kubernetes.io/zh-cn/docs/tasks/debug/debug-application/debug-init-containers/
??《配置存活、就緒和啟動探針》,https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/
??《為容器的生命周期事件設置處理函數,定義 postStart 和 preStop 處理函數》,https://kubernetes.io/zh-cn/docs/tasks/configure-pod-container/attach-handler-lifecycle-event/