存活探針
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。
-> [root@kube0.vm] [~] 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秒後檢視
-> [root@kube0.vm] [~] k create -f exec-liveness.yaml
pod/liveness-exec created
-> [root@kube0.vm] [~] 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 <unknown> default-scheduler Successfully assigned default/liveness-exec to kube1.vm
Normal Pulling <invalid> kubelet, kube1.vm Pulling image "busybox"
Normal Pulled <invalid> kubelet, kube1.vm Successfully pulled image "busybox"
Normal Created <invalid> kubelet, kube1.vm Created container liveness
Normal Started <invalid> kubelet, kube1.vm Started container liveness
Warning Unhealthy <invalid> (x3 over <invalid>) kubelet, kube1.vm Liveness probe failed: cat: can't open '/tmp/healthy': No such file or directory
Normal Killing <invalid> 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
-> [root@kube0.vm] [~] k create -f nginx-rc.yaml
replicationcontroller/nginx-rc created
檢視pod,確實新建了3個pod。
-> [root@kube0.vm] [~] 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的簡寫。
-> [root@kube0.vm] [~] k get rc
NAME DESIRED CURRENT READY AGE
nginx-rc 3 3 3 5m58s
檢視詳情
-> [root@kube0.vm] [~] k describe rc nginx-rc
Name: nginx-rc
Namespace: default
Selector: app=nginx
Labels: app=nginx
Annotations: <none>
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: <none>
Mounts: <none>
Volumes: <none>
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配置,修改在儲存後會立刻做出改變。
-> [root@kube0.vm] [~] k edit rc nginx-rc
replicationcontroller/nginx-rc edited
通過KUBE_EDITOR環境變數可以指定用什麼編輯器開啟。
kubectl scale
可以使用kubectl scale
命令進行擴縮容。
-> [root@kube0.vm] [~] 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打個標籤
-> [root@kube0.vm] [~] k label node kube1.vm region=beijing
node/kube1.vm labeled
-> [root@kube0.vm] [~] k get node -L region
NAME STATUS ROLES AGE VERSION REGION
kube0.vm Ready master 40h v1.17.3
kube1.vm Ready <none> 40h v1.17.3 beijing
kube2.vm Ready <none> 40h v1.17.3
提交描述檔案
-> [root@kube0.vm] [~] k create -f nginx-ds.yaml
daemonset.apps/nginx-ds created
-> [root@kube0.vm] [~] 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 <none> <none>
給kube2.vm也打個標籤
-> [root@kube0.vm] [~] k label node kube2.vm region=beijing
node/kube2.vm labeled
-> [root@kube0.vm] [~] 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 <none> <none>
pod/nginx-ds-b46lb 0/1 ContainerCreating 0 3s <none> kube2.vm <none> <none>
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
-> [root@kube0.vm] [~] k create -f job.yaml
job.batch/job created
60秒內檢視:
-> [root@kube0.vm] [~] 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秒後檢視:
-> [root@kube0.vm] [~] 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
-> [root@kube0.vm] [~] 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
-> [root@kube0.vm] [~] k create -f cronjob.yaml
cronjob.batch/cron-job created
等了幾分鐘
-> [root@kube0.vm] [~] 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
又等了幾分鐘
-> [root@kube0.vm] [~] 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、scale