一、資源控制器
K8S中內建了很多的控制器,這些控制器都是用來空指Pod的具體狀態和行為。從控制器的角度來說,Pod可以分為自主式Pod和控制器管理的Pod。自主式的Pod一旦退出,該類型的Pod就不會被重新創建,而控制器管理的Pod,在控制器的生命周期里,始終要維持Pod的副本數量。
常用的控制器,在K8S--架構及基本概念中已經說過,主要有ReplicationController(舊版本)、ReplaSet、Deployment、DaemonSet、Job、CronJob,具體的概念就不再說多,直接上代碼示例。
對於RC、RS、Deployment的配置可以參見K8S--實戰
(一)DaemonSet
DaemonSet確保全部Node上運行一個Pod副本,當有Node加入集群時,也會為他們新增一個pod,當有Node從集群中被移除時,這些pod也會被回收,刪除DaemonSet將會刪除其創建的所有pod。最典型的場景就是每個Pod里面都有服務在運行,需要收集服務運行日志,但是Pod是由K8S自動創建或刪除的,因此需要使用DaemonSet來設定在每一個Pod中進行日志收集。
#確保只運行一個副本,運行在集群中每一個節點上。(也可以部分節點上只運行一個且只有一個pod副本,如監控ssd硬盤) # kubectl explain ds # vim filebeat.yaml apiVersion: apps/v1 kind: DaemonSet metadata: name: my-deamon namespace: default labels: app: daemonset spec: selector: matchLabels: app: my-daemonset template: metadata: labels: app: my-daemonset spec: containers: - name: daemon-app image: nginx:1.16
使用:kubectl apply -f xxx.yaml執行該配置文件即可,就會在每個節點中創建一個名為my-deamon的pod。
然后可以使用:kubectl get daemonset查看在運行的daemonset
實際上,K8S自己就在用deamonSet在運行組件系統。
(二)Job
Job負責處理任務,即僅執行一次的任務,它保證批處理任務的一個或多個Pod成功結束。而CronJob則就是在Job上加上了時間調度。
# 我們用Job這個資源對象來創建一個任務,我們定一個Job來執行一個倒計時的任務,定義YAML文件: apiVersion: batch/v1 kind: Job metadata: name: job-demo spec: template: metadata: name: job-demo spec: restartPolicy: Never containers: - name: counter image: busybox command: - "bin/sh" - "-c" - "for i in 9 8 7 6 5 4 3 2 1; do echo $i; done"
上面的配置文件是創建了一個job,並從9輸出到1。
使用命令執行配置文件: kubectl apply -f job.yaml
查看pod:
可以看到job已經執行完成,然后查看輸出日志:
可以看到已經正常打印。
(三)CronJob
CronJob其實就是在Job的基礎上加上了時間調度,我們可以:在給定的時間點運行一個任務,也可以周期性地在給定時間點運行。這個實際上和我們Linux中的crontab就非常類似了。
apiVersion: batch/v1beta1 kind: CronJob metadata: name: cronjob-demo spec: schedule: "*/1 * * * *" jobTemplate: spec: template: spec: restartPolicy: OnFailure containers: - name: hello image: busybox args: - "bin/sh" - "-c" - "for i in 9 8 7 6 5 4 3 2 1; do echo $i; done"
執行該配置文件: kubectl apply -f cronjob.yaml
可以使用以下命令查看:
# 查詢cronjob kubectl get cronjob # 查詢jon ,cronjon會循環多個job kubectl get job # 實時監控查詢job kubectl get job -w
二、Pod
(一)Pod生命周期
Pod的status屬性描述了Pod處於生命周期的階段。
階段 | 描述 |
Pending | Pod 已被 Kubernetes 接受,但尚未創建一個或多個容器鏡像。這包括被調度之前的時間以及通過網絡下載鏡像所花費的時間,執行需要一段時間。 |
Running | Pod 已經被綁定到了一個節點,所有容器已被創建。至少一個容器正在運行,或者正在啟動或重新啟動。 |
Succeeded | 所有容器成功終止,也不會重啟。 |
Failed | 所有容器終止,至少有一個容器以失敗方式終止。也就是說,這個容器要么已非 0 狀態退出,要么被系統終止。 |
Unknown | 由於一些原因,Pod 的狀態無法獲取,通常是與 Pod 通信時出錯導致的。 |
重啟策略:
對於Pod的重啟策略,有Always、OnFailure、Never三種,默認為Always,其中Always表示容器失敗時,kubectl會自動重啟該容器,Onfailure表示容器終止運行且退出碼不為0時重啟,Never表示無論什么狀態,kubectl都不會重啟該容器。
失敗的容器由kubectl以五分鍾為上限的指數延遲重新啟動(10秒、20秒、40秒),並在成功執行十分鍾后重置。
Pod的生命周期如下圖所示:
流程說明:
(1)初始化容器階段,初始化Pod中的每一個容器,他們是串行執行的,執行完就退出了。
(2)啟動主容器main container
(3)在main container剛剛啟動之后可以執行post start命令(勾子程序)
(4)在整個main container執行的過程中可以做兩類探測:liveness probe(存活探測)和readiness probe(就緒探測)
(5)在main container結束前可以執行pre stop命令(勾子程序)
配置啟動后勾子(post start)和終止前勾子(pre stop):
post start:容器創建之后立即執行,如果失敗了就會按照重啟策略重啟容器
pre stop:容器終止前立即執行,執行完成后容器將成功終止
可以使用以下命令查看post start和pre stop的設置格式:
kubectl explain pod.spec.containers.lifecycle.preStop
kubectl explain pod.spec.containers.lifecycle.postStart
(二)Pod init
1、init容器
Pod能夠持有多個容器,應用運行在容器里面,但是它也可能有一個或多個先於應用程序啟動的init容器,init容器與普通容器非常相似,只有以下兩點區別:
(1)init容器總是運行到成功完成為止
(2)每個init容器都必須在下一個init容器啟動之前成功完成
如果pod的init容器失敗,K8S會不斷的重啟該Pod,直到init容器成功為止,不過也有特里,就是如果將Pod的重啟策略restartPolicy設置為Never,他就不會重啟了。
2、init的作用
因為init容器與應用程序容器的鏡像是分離的,所以他們啟動相關代碼具有以下優勢:
(1)它們可以包含並運行實用工具,但是處於安全考慮,一般不建議在應用程序容器鏡像中包含這些實用工具
(2)他們可以包含實用工具和定制化代碼來安裝,但是不能出現在現有應用程序鏡像中,例如創建鏡像沒有必要FROM另一個鏡像,只需要在安裝過程中使用類似sed、awk、python或dig這樣的工具
(3)應用程序鏡像可以分離出創建和部署的角色,而沒有必要聯合他們構建一個單獨的鏡像。
(4)init容器使用LinuxNamespace,所以相對應用程序來說,其具有不同文件系統視圖,因此,他們能夠具有訪問Secret的權限,而應用程序容器則不能。
(5)他們必須在應用程序啟動之前運行完成,而應用程序是並行運行的,所以init容器能夠提供一種簡單的阻塞或延遲應用容器啟動的方法,直到滿足了一組先決條件。
3、特殊說明
(1)在pod啟動過程中,init容器會按照順序在網絡和數據卷初始化之后啟動(網絡和數據卷初始化是在pause容器中),每個容器必須在下一個容器啟動前成功退出
(2)如果由於運行時或失敗退出,將導致容器啟動失敗,它會根據Pod的restartPolicy指定的重啟策略來進行處理
(3)在所有的init容器沒有成功之前,Pod將不會變成Ready狀態,init容器的端口將不會在Service中進行聚集,正在初始化的Pod處於Pending狀態,但應該會將Initializing狀態設置為true
(4)如果Pod重啟,所有的Init容器必須重新執行
(5)對init容器spec的修改被限制在容器的image字段,修改其他字段都不會生效,更改init容器的image字段,等價於重啟了Pod
(6)Init容器具有應用容器的所有字段,除了readinessProbe(就緒檢測),因為init容器無法定義不同於完成(Completion)的就緒(readiness)之外的其他狀態,這會在驗證過程中強制執行。
(7)在Pod中的每個app和init容器的名稱必須唯一,與任何其他容器共享一個名稱,會在驗證時拋出錯誤。
4、演示
創建一個init容器的配置文件,在該配置文件中,創建了一個initPod叫init-mydb,該initpod需要執行一個連接inint-db的pod
#init-pod.yaml apiVersion: v1 kind: Pod metadata: name: init-pod labels: app: nginx spec: containers: - name: myapp image: nginx command: ['sh', '-c', 'echo -n "running at " && date +%T && sleep 600'] initContainers: - name: init-mydb image: nginx command: ['sh', '-c', 'until nslookup init-db; do echo waiting for init-db;date +%T; sleep 2;echo; done;']
創建:
#創建 kubectl apply -f init-pod.yaml #查看pod狀態 init沒成功 kubectl get pod #查看log kubectl logs init-pod -c init-mydb
使用上述命令可以看到,上面創建的容器一直連不上db,導致一直不能完成。
然后創建db容器
#init-db.yaml kind: Service apiVersion: v1 metadata: name: init-db spec: ports: - protocol: TCP port: 80 targetPort: 3366
創建
#創建svr kubectl create -f init-db.yaml #查看 kubectl get svc #svc有ip地址,等待init容器運行成功 kubectl get pod
顯示原來的容器已經啟動成功。
刪除容器
#刪除 kubectl delete -f init-pod.yaml kubectl delete -f init-db.yaml
三、容器探針
(一)概述
探針是由kubectl對容器執行的定期診斷,要執行診斷,kubelet調用由容器實現的Handler,探測的診斷結果有成功、失敗和未知三種情況,探測類型有以下三種:
1、ExecAction:在容器內執行指定命令,如果命令退出時返回碼為0則認為診斷成功
2、TCPSocketAction:對指定端口上的容器的IP地址進行TCP檢查,如果端口打開,則認為診斷成功
3、HTTPGetAction:對指定的端口和路徑上的容器IP執行http get請求,如果響應狀態碼大於200小於400,則認為診斷成功。
上面提到了存活探測和就緒探測,那么對於兩種探測的方式做個解釋:
1、livenessProbe(存活探測):存活探測是用來探測容器是否正在運行,如果探測失敗,lubelet會殺死容器,並且容器將受到重啟策略的影響。如果容器不提供存活探測,則默認為狀態一直為Success。
2、readinessProbe(就緒探測):就緒探測是用來探測容器是否准備好接收服務請求,如果探測失敗,端點控制器將從與Pod匹配的所有Service的端點中刪除該Pod的IP地址。初始延遲之前的就緒狀態默認為Failure,如果容器不提供就緒探針,則默認狀態一直為Success。
(二)就緒探針
就緒探針配置:
#readinessProbe-httpget apiVersion: v1 kind: Pod metadata: name: readiness-httpget-pod namespace: default spec: containers: - name: readiness-httpget-container image: nginx imagePullPolicy: IfNotPresent readinessProbe: httpGet: port: 80 path: /index1.html initialDelaySeconds: 1 periodSeconds: 3
以上的配置文件表示創建一個名字為readiness-httpget-pod的就緒探針,readinessProbe的配置就是就緒探針的具體配置,首先使用的是httpget的方式訪問80端口,訪問路徑是/index1.html,延遲一秒訪問,每三秒探測一次。
執行以上yaml文件,查看結果:
可以看到,雖然這個Pod狀態為Running,但是卻為就緒,使用命令查看原因:
kubectl describe pod readiness-httpget-pod
可以看到是就緒探測結果為404。
那么就為該pod創建一個/index1.html配置文件
# 進入pod kubectl exec -it readiness-httpget-pod sh # 進入nginx默認訪問目錄 cd /usr/share/nginx/html # 創建index1.html echo 'hello lcl' >> index1.html # 從pod中退出 exit
重新查看,該pod已經正常運行
說明:實際生產中,訪問的路徑一般都是健康檢查的路徑,這里只是為了做個演示。
(三)存活檢測--livenessProbe-exec
配置文件:
apiVersion: v1 kind: Pod metadata: name: liveness-exec-pod namespace: default spec: containers: - name: liveness-exec-container image: hub.lcl.cn/library/busybox:v1 imagePullPolicy: IfNotPresent command: ["/bin/sh","-c","touch /tmp/live;sleep 60;rm -rf /tmp/live;sleep 3600"] livenessProbe: exec: command: ["test","-e","/tmp/live"] initialDelaySeconds: 1 periodSeconds: 3
配置文件簡單說明:
容器(liveness-exec-container)的command命令,創建一個/tmp/live文件,然后休眠60秒,然后將該文件刪除,然后再休眠3600秒
創建了一個存活探針(livenessProbe),檢測/tmp/live文件,延遲一秒開始檢測,每三秒探測一次。
執行yaml文件,查看pod運行情況
可以看到,Pod在一段時間后,檢測不到/tmp/live文件,自動重啟。
(四)存活檢測--livenessProbe-Httpget
yaml文件
apiVersion: v1 kind: Pod metadata: name: liveness-httpget-pod namespace: default spec: containers: - name: liveness-httpget-container image: nginx imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 livenessProbe: httpGet: port: http path: /index.html initialDelaySeconds: 1 periodSeconds: 3 timeoutSeconds: 10
配置文件說明:
創建了一個存活探針(livenessProbe),使用httpget方式請求/index.html,檢測/tmp/live文件,延遲3秒開始檢測,每10秒探測一次。
運行yaml文件:因為nginx默認就有index.html文件,因此pod狀態正常
進入pod中,將index.html刪除
# 進入容器 kubectl exec -it liveness-httpget-pod sh # 切換到nginx默認訪問目錄 cd /usr/share/nginx/html # 刪除文件 rm -f index.html
可以看到pod就開始重啟了。
(五)存活檢測-livenessProbe-TCP
yaml文件
apiVersion: v1 kind: Pod metadata: name: probe-tcp spec: containers: - name: probetcp image: nginx livenessProbe: initialDelaySeconds: 5 timeoutSeconds: 1 tcpSocket: port: 80 periodSeconds: 3
配置文件說明:使用tcp檢測,延遲5秒開始檢測,檢測超時時間為1秒,檢測端口80,每3秒檢測一次。
(六)存活探測和就緒探測
在實際生產中,一個Pod中應該同時存在就緒探測和存活探測,yaml樣例如下所示
apiVersion: v1 kind: Pod metadata: name: liveness-httpget-pod namespace: default spec: containers: - name: liveness-httpget-container image: hub.lcl.com/library/myapp:v1 imagePullPolicy: IfNotPresent ports: - name: http containerPort: 80 readinessProbe: httpGet: port: 80 path: /index1.html initialDelaySeconds: 1 periodSeconds: 3 livenessProbe: httpGet: port: http path: /index.html initialDelaySeconds: 1 periodSeconds: 3 timeoutSeconds: 10
(七)勾子函數
在前面說Pod的生命周期中有start勾子函數和stop勾子函數,就是在啟動前和停止后分別要做哪些事情,這里做個演示:
apiVersion: v1 kind: Pod metadata: name: lifecycle-startstop spec: containers: - name: lifecycle-container image: nginx lifecycle: postStart: exec: command: ["/bin/sh","-c","echo Hello from the postStart handler > /usr/share/message"] preStop: exec: command: ["/bin/sh","-c","echo Hello container stop"]
配置文件也比較簡單,就是在啟動的時候輸出一句話到message文件,在pod停止時,再輸出一句話
執行yaml文件,待pod運行后,進入pod,查看message文件
停止的由於已經停止,就看不了~~~