1. 程式人生 > >Kubernetes學習筆記(二):部署託管的Pod -- 存活探針、ReplicationController、ReplicaSet、DaemonSet、Job、CronJob

Kubernetes學習筆記(二):部署託管的Pod -- 存活探針、ReplicationController、ReplicaSet、DaemonSet、Job、CronJob

## 存活探針 Kubernetes可以通過存活探針(liveness probe)檢查容器是否存活。如果探測失敗,Kubernetes將定期執行探針並重新啟動容器。 官方文件請見:https://kubernetes.io/docs/tasks/configure-pod-container/configure-liveness-readiness-startup-probes/ 存活探針分為三種: - exec:在容器內執行任意命令,並檢查命令的退出狀態碼,為0則成功,否則失敗。 - httpGet:執行http get請求,http code大於等於200並且小於400表示成功,否則失敗。 - tcp:嘗試與指定埠建立socket連線,建立成功則探測成功,否則失敗。 ### exec探針 從官網複製個yaml,但是要將image從k8s.gcr.io/busybox更改為busybox。 ``` -> [[email protected]] [~] cat exec-liveness.yaml apiVersion: v1 kind: Pod metadata: labels: test: liveness name: liveness-exec spec: containers: - name: liveness image: busybox args: - /bin/sh - -c - touch /tmp/healthy; sleep 30; rm -rf /tmp/healthy; sleep 600 livenessProbe: exec: command: - cat - /tmp/healthy initialDelaySeconds: 5 periodSeconds: 5 ``` 執行然後30秒後檢視 ``` -> [[email protected]] [~] k create -f exec-liveness.yaml pod/liveness-exec created -> [[email protected]] [~] k describe po liveness-exec ....... Liveness: exec [cat /tmp/healthy] delay=5s timeout=1s period=5s #success=1 #failure=3 ....... Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal Scheduled default-scheduler Successfully assigned default/liveness-exec to kube1.vm Normal Pulling kubelet, kube1.vm Pulling image "busybox" Normal Pulled kubelet, kube1.vm Successfully pulled image "busybox" Normal Created kubelet, kube1.vm Created container liveness Normal Started kubelet, kube1.vm Started container liveness Warning Unhealthy (x3 over ) kubelet, kube1.vm Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory Normal Killing kubelet, kube1.vm Container liveness failed liveness probe, will be restarted ``` 前30秒,/tmp/healthy是存在的,探針返回成功。30秒後,因為/tmp/healthy不存在了,所以一直失敗,直到失敗3次後重啟。 ### livenessProbe下的欄位 這時候`kubectl explain po.spec.containers.livenessProbe`就派上了用場。 - exec:exec探針配置 - httpGet:httpGet探針配置 - tcpSocket:tcpSocket探針配置 - initialDelaySeconds:初始延遲時間,在此時間內不進行探測,給程式預留啟動時間。 - periodSeconds:探測週期,預設10s - timeoutSeconds:超時時間,預設1s - failureThreshold:被認為失活的最小連續失敗次數,預設3次 - successThreshold:失敗後被認為存活的最小連續成功次數,預設為1次。 這些引數在上面的`kubectl describe`的結果中的Liveness欄位有: ``` exec [cat /tmp/healthy] delay=5s timeout=1s period=5s #success=1 #failure=3 ``` ### 注意事項 - 一定要檢查程式的內部,而沒有外界因素影響。 例如,當伺服器無法連線到資料庫時,前端服務的探針不應返回失敗。因為問題在資料庫,重啟前端服務也無法解決問題。 - 無須再探針中實現重試 - 探針要輕量 ## ReplicationController ReplicationController是一種Kubernetes資源,可以確保他的pod始終處於執行狀態。 ReplicationController描述檔案分為三大部分: - label selector(標籤選擇器):用於確定ReplicationController管理哪些pod - replica count(副本個數):指定執行pod的數量 - pod template(pod模板):用於建立pod ReplicationController的目的就是建立和管理若干個pod副本,它會持續監控正在執行的pod列表,保證標籤選擇器匹配的pod數量與副本個數一致。如果少於副本數量,就要根據pod模板建立新的副本;如果多餘副本數量,就要刪除多餘的pod。 數量少的原因可能是: - 增加了副本個數 - pod所在的工作節點出現故障 - pod的標籤更改了,導致pod與ReplicationController的標籤選擇器不再匹配了。此時,如果它不被任何ReplicationController的標籤選擇器匹配,它就稱為一個孤兒了。 數量多的原因可能是: - 減少了副本個數 - 新建的pod與該ReplicationController的標籤選擇器匹配 - 已存在的pod標籤修改後與該ReplicationController的標籤選擇器匹配 ### nginx-rc.yaml API伺服器會檢查模板中的標籤是否與selector匹配,如果不匹配是無法建立的。可以不指定selector,它會根據模板中的labels自動配置。 ``` apiVersion: v1 kind: ReplicationController metadata: name: nginx-rc spec: replicas: 3 # 副本數量 selector: # pod選擇器,決定RC的操作物件 app: nginx template: # pod模板 metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 ``` ### 使用ReplicationController 建立ReplicationController ``` -> [[email protected]] [~] k create -f nginx-rc.yaml replicationcontroller/nginx-rc created ``` 檢視pod,確實新建了3個pod。 ``` -> [[email protected]] [~] k get po --show-labels NAME READY STATUS RESTARTS AGE LABELS nginx-rc-2c47w 0/1 ContainerCreating 0 5s app=nginx nginx-rc-jrcl2 0/1 ContainerCreating 0 5s app=nginx nginx-rc-qgchh 0/1 ContainerCreating 0 5s app=nginx ``` 檢視ReplicationController,rc是ReplicationController的簡寫。 ``` -> [[email protected]] [~] k get rc NAME DESIRED CURRENT READY AGE nginx-rc 3 3 3 5m58s ``` 檢視詳情 ``` -> [[email protected]] [~] k describe rc nginx-rc Name: nginx-rc Namespace: default Selector: app=nginx Labels: app=nginx Annotations: Replicas: 3 current / 3 desired # 當前數量、期望數量 Pods Status: 3 Running / 0 Waiting / 0 Succeeded / 0 Failed # 各種狀態下的數量 Pod Template: Labels: app=nginx Containers: nginx: Image: nginx Port: 80/TCP Host Port: 0/TCP Environment: Mounts: Volumes: Events: Type Reason Age From Message ---- ------ ---- ---- ------- Normal SuccessfulCreate 7m26s replication-controller Created pod: nginx-rc-2c47w Normal SuccessfulCreate 7m26s replication-controller Created pod: nginx-rc-jrcl2 Normal SuccessfulCreate 7m26s replication-controller Created pod: nginx-rc-qgchh ``` 可以搞一些破壞,比如更改、刪除pod的標籤,或者乾脆刪除pod。ReplicationController會因為當前數量與期望數量不符而建立新的副本。 ### 控制器如何建立的pod 控制器通過建立一個新的副本代替被刪除的副本時,**它並沒有對刪除本身做出反應,而是針對由此產生的狀態——副本數量不足做出反應。** 雖然控制器會立即受到pod被刪除的通知,但這並不是它建立新副本的原因。該通知會觸發控制器檢查實際的副本數量並採取相應措施。 ### kubectl edit `kubectl edit rc nginx-rc`可以在編輯器中開啟nginx-rc的yaml配置,修改在儲存後會立刻做出改變。 ``` -> [[email protected]] [~] k edit rc nginx-rc replicationcontroller/nginx-rc edited 通過KUBE_EDITOR環境變數可以指定用什麼編輯器開啟。 ``` ### kubectl scale 可以使用`kubectl scale`命令進行擴縮容。 ``` -> [[email protected]] [~] k scale rc nginx-rc --replicas=6 replicationcontroller/nginx-rc scaled ``` 以上操作會修改`spec.replicas`欄位,就像通過`kubectl edit`修改一樣。 ### 刪除ReplicationController 使用 kubectl delete 刪除ReplicationController時,pod也會被刪除。但由於pod是被ReplicationController建立的而不是它的組成部分,所以可以通過指定`--cascade=false`而不刪除pod。 ### 注意事項 - pod永遠不會被重新安置到另一個節點。 - 雖然一個pod沒有繫結在ReplicationController上,但該pod在`metadata.ownerReferences`引用它。 ## ReplicaSet ReplicationController最終將要被棄用,代替它的是ReplicaSet。它們的行為完全相同,但是ReplicaSet的選擇器更具有表達力。 ### nginx-rs.yaml 讓我們來看一個ReplicaSet的描述檔案: ``` apiVersion: apps/v1 # api版本與ReplicationController不同 kind: ReplicaSet metadata: name: nginx-rs spec: replicas: 3 selector: # ReplicaSet的pod選擇器有matchLabels和matchExpressions,與ReplicationController的是相似的,但更強大 matchLabels: app: nginx template: # 模板內容是一致的 metadata: labels: app: nginx spec: containers: - name: nginx image: nginx ports: - containerPort: 80 ``` 主要區別在於pod選擇器。ReplicaSet的創建於ReplicationController一樣,縮寫是rs,就不再贅敘了。 ### matchExpressions 上面描述檔案的選擇器使用matchExpressions可以改為: ``` selector: matchExpressions: - key: app operator: In values: - nginx ``` 每個表示式都必須包含key、operator(運算子),有可能包含values(取決於運算子),運算子有以下四種: - In:Label的值必須與values中的一個相等 - NotIn:Label的值不能與values中的任何一個相等 - Exists:Pod必須包含一個指定名稱的標籤,values無所謂 - DoesNotExists:Pod不得包含指定名稱的標籤,values不能指定 ## DaemonSet DaemonSet與ReplicaSet的不同在於,DaemonSet可以讓pod在叢集的每個節點上執行,有且只有一個。 如果節點下線,DaemonSet不會在其他地方重建pod;如果叢集新加入了一個節點,DaemonSet會立刻部署一個新的pod。如果有人刪除了pod,DaemonSet會建立一個新的。 這些pod通常用於執行系統級別或基礎結構相關的工作,如日誌收集和資源監控。典型的例子就是Kubernetes自己的kube-proxy。 如果想讓DaemonSet只在特定節點執行pod,需要通過pod模板中的nodeSelector屬性指定。 DaemonSet中沒有期望副本數的概念,它不需要。因為它的工作是確保有一個匹配它選擇器的pod在節點上執行。 ### nginx-ds.yaml 可能這裡用繼續用nginx作為例子不太恰當,但目前我們關注的重點是DaemonSet,繼續吧。。。 ``` apiVersion: apps/v1 kind: DaemonSet metadata: name: nginx-ds spec: # 去掉了replicas,因為不需要 selector: matchLabels: app: nginx template: metadata: labels: app: nginx spec: nodeSelector: # 添加了一個節點的標籤選擇器,選擇只部署地區在在北京的節點上 region: "beijing" containers: - name: nginx image: nginx ports: - containerPort: 80 ``` ### 建立DaemonSet 先給kube1.vm打個標籤 ``` -> [[email protected]] [~] k label node kube1.vm region=beijing node/kube1.vm labeled -> [[email protected]] [~] k get node -L region NAME STATUS ROLES AGE VERSION REGION kube0.vm Ready master 40h v1.17.3 kube1.vm Ready 40h v1.17.3 beijing kube2.vm Ready 40h v1.17.3 ``` 提交描述檔案 ``` -> [[email protected]] [~] k create -f nginx-ds.yaml daemonset.apps/nginx-ds created -> [[email protected]] [~] k get ds,po -o wide NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR daemonset.apps/nginx-ds 1 1 1 1 1 region=beijing 52s nginx nginx app=nginx NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/nginx-ds-5z95c 1/1 Running 0 52s 10.244.1.24 kube1.vm ``` 給kube2.vm也打個標籤 ``` -> [[email protected]] [~] k label node kube2.vm region=beijing node/kube2.vm labeled -> [[email protected]] [~] k get ds,po -o wide NAME DESIRED CURRENT READY UP-TO-DATE AVAILABLE NODE SELECTOR AGE CONTAINERS IMAGES SELECTOR daemonset.apps/nginx-ds 2 2 1 2 1 region=beijing 113s nginx nginx app=nginx NAME READY STATUS RESTARTS AGE IP NODE NOMINATED NODE READINESS GATES pod/nginx-ds-5z95c 1/1 Running 0 113s 10.244.1.24 kube1.vm pod/nginx-ds-b46lb 0/1 ContainerCreating 0 3s kube2.vm ``` ## Job Job可以執行一種pod,在該pod內的程序成功結束時,不再重啟。一旦任務完成,pod就被認為處於完成狀態。 比如可以使用在將一些資料匯出到其他地方,這個工作可能會持續幾個小時。 我們基於busybox映象,sleep一段時間用於模擬這個操作。 ### job.yaml ``` apiVersion: batch/v1 kind: Job metadata: name: job spec: template: # 沒有指定selector,會根據pod標籤中自動建立 metadata: labels: app: job spec: restartPolicy: OnFailure # 執行遇到異常則重啟,預設為Always。 containers: - name: sleepbusybox image: busybox command: ["/bin/sh","-c","sleep 60;echo this is busybox"] ``` **restartPolicy表示pod的重啟策略,預設Always,其他兩項為OnFailure和Never。** ### 執行檢視 建立job ``` -> [[email protected]] [~] k create -f job.yaml job.batch/job created ``` 60秒內檢視: ``` -> [[email protected]] [~] k get job,pod NAME COMPLETIONS DURATION AGE job.batch/job 0/1 14s 14s NAME READY STATUS RESTARTS AGE pod/job-4sfv4 1/1 Running 0 14s ``` 60秒後檢視: ``` -> [[email protected]] [~] k get job,pod NAME COMPLETIONS DURATION AGE job.batch/job 1/1 68s 71s NAME READY STATUS RESTARTS AGE pod/job-4sfv4 0/1 Completed 0 71s ``` 使用jsonpath獲取 pod name 檢視log ``` -> [[email protected]] [~] k logs $(k get po --selector=app=job --output=jsonpath={.items..metadata.name}) this is busybox ``` ### completions與parallelism job描述檔案下的spec有兩個欄位: - completions:job要確保完成多少個pod,預設為1。 - parallelism:最多並行執行多少個pod,預設為1。 job-batch.yaml ``` apiVersion: batch/v1 kind: Job metadata: name: job-batch spec: completions: 5 parallelism: 2 template: # 與job.yaml相同 ``` ### activeDeadlineSeconds `job.spec.activeDeadlineSeconds`屬性來限制Job在叢集中的存活時間,超過此值,所有的pod都被終止。Job的status變為 `type: Failed`,`reason: DeadlineExceeded` ## CronJob 與Linux的crontab類似,使pod可以在特定時間執行,或者週期執行。 ### cronjob.yaml 這個描述檔案是個套娃。。 CronJob包含job的模板,也就是jobTemplate;job裡還包含pod的模板,也就是template。 schedule欄位中的值是"分 小時 每月第幾天 月份 星期幾",詳情請參考Linux crontab。 ``` apiVersion: batch/v1beta1 kind: CronJob metadata: name: cron-job spec: schedule: "*/3 * * * * " # 每三分鐘執行一次 jobTemplate: # job的模板 spec: template: # pod的模板 metadata: labels: app: job-in-cron spec: restartPolicy: OnFailure containers: - name: sleepbusybox image: busybox command: ["/bin/sh","-c","sleep 60;echo this is busybox"] ``` ### 執行 建立cron-job ``` -> [[email protected]] [~] k create -f cronjob.yaml cronjob.batch/cron-job created ``` 等了幾分鐘 ``` -> [[email protected]] [~] k get all NAME READY STATUS RESTARTS AGE pod/cron-job-1590053040-pqhhh 0/1 Completed 0 97s NAME COMPLETIONS DURATION AGE job.batch/cron-job-1590053040 1/1 68s 97s NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE cronjob.batch/cron-job */3 * * * * False 0 105s 4m39s ``` 又等了幾分鐘 ``` -> [[email protected]] [~] k get all NAME READY STATUS RESTARTS AGE pod/cron-job-1590053040-pqhhh 0/1 Completed 0 3m4s pod/cron-job-1590053220-whflp 0/1 ContainerCreating 0 3s NAME COMPLETIONS DURATION AGE job.batch/cron-job-1590053040 1/1 68s 3m4s job.batch/cron-job-1590053220 0/1 3s 3s NAME SCHEDULE SUSPEND ACTIVE LAST SCHEDULE AGE cronjob.batch/cron-job */3 * * * * False 1 12s 6m6s ``` **可以看到就當前的描述檔案而言,cron-job每次建立一個job,job建立一個pod的執行。** ### startingDeadlineSeconds `cronjob.spec.startingDeadlineSeconds`規定pod必須預定時間之後的startingDeadlineSeconds秒內執行,超過此時間則不執行,並將其顯示未Failed。 ## 小結 - 使用存活探針檢查容器是否存活。 - ReplicationController建立並管理Pod,但並不是繫結關係。它始終保持期望數量的副本正在執行。 - ReplicationController將被棄用,ReplicaSet擁有更強的標籤選擇器。 - DaemonSet會在每個節點上保持執行有且只有一個Pod,可以通過nodeSelector讓其只在特定節點執行。 - Job建立Pod執行完成後,Pod為為`Completed`狀態。completions與parallelism指定需要完成的數量與並行度。 - restartPolicy:預設Always,還有OnFailure、Never。 - CronJob建立Job,Job建立Pod。 - 命令:edit