Kubernetes之(九)Pod控制器,ReplicaSet,Deployment,DaemonSet
Kubernetes中內建了很多controller(控制器),這些相當於⼀個狀態機,⽤來控制Pod的具體狀態和⾏為。
Pod控制器有多種類型:
ReplicaSet:它的核心作用是代用戶創建指定數量的Pod副本,並確定Pod副本一直處於滿足用戶期望數量的狀態,多退少補,同時支持擴縮容機制。主要有三個組件:
- 用戶期望的Pod副本數量;
- 標簽選擇器,選擇屬於自己管理和控制的Pod;
- 當前Pod數量不滿足用戶期望數量時,根據資源模板進行新建。
Deployment:工作在ReplicaSet之上,用於管理無狀態應用,除了ReplicaSet的機制,還增加了滾動更新和回滾功能,提供聲明式配置。
DaemonSet:用於確保集群中的每一個節點只運行特定的pod副本,通常用於實現系統級后台任務。比如ELK服務。要求:服務是無狀態的;服務必須是守護進程
Job::只要完成就立即退出,不需要重啟或重建。
Cronjob:周期性任務控制,不需要持續后台運行。
StatefulSet:管理有狀態應用,如mysql,redis等。
ReplicaSet
ReplicationController用來確保容器應用的副本數始終保持在用戶定義的副本數,即如果有容器異常退出,會自動創建新的Pod來替代;而如果異常多出來的容器也會自動回收。
雖然ReplicaSet可以獨立使用,但一般還是建議使用 Deployment 來自動管理ReplicaSet,這樣就無需擔心跟其他機制的不兼容問題(比如ReplicaSet不支持rolling-update但Deployment支持)。
舉例
[root@master ~]# kubectl explain rs
[root@master manifests]# vim rs-demo.yaml
apiVersion: apps/v1 #群組/版本
kind: ReplicaSet #類型 注意大小寫
metadata: #元數據
name: myapp
namespace: default
spec:
replicas: 2 #定義ReplicaSet副本數量
selector: #定義選擇器
matchLabels: #匹配 ,創建的模板的標簽需要包含此處的標簽,不然無法被創建
app: myapp
release: canary
template: #定義模板
metadata: #模板元數據
name: myapp-pod #此處名稱定義沒有用,被控制器創建的pod都會以控制器的名稱后加隨機字符串來命名
labels: #此處要包含replicaset處定義的標簽選擇器
app: myapp
release: canary
spec:
containers: #定義模板的容器
- name: myapp-container
image: ikubernetes/myapp:v1
ports: #端口
- name: http
containerPort: 80
#運行后驗證
[root@master manifests]# kubectl create -f rs-demo.yaml
replicaset.apps/myapp created
[root@master manifests]# kubectl get rs #replicaset 簡寫rs
NAME DESIRED CURRENT READY AGE
client-f5cdb799f 1 1 1 3d19h
myapp 2 2 2 10s
nginx-deploy-84cbfc56b6 1 1 1 3d23h
#查看pod
[root@master manifests]# kubectl get pods
NAME READY STATUS RESTARTS AGE
client-f5cdb799f-pklmc 1/1 Running 0 3d19h
myapp-fxmjz 1/1 Running 0 59s
myapp-hxvnz 1/1 Running 0 59s
nginx-deploy-84cbfc56b6-tcssz 1/1 Running 0 3d22h
pod-demo 2/2 Running 7 2d22h
poststart-pod 1/1 Running 1 2d16h
readiness-httpget-pod 1/1 Running 0 2d16h
#可以使用kubectl describe pods <POD_NAME>來查看詳細信息
修改Pod的副本數量:
[root@master manifests]# kubectl edit rs myapp
replicas: 5
[root@master manifests]# kubectl get pods
NAME READY STATUS RESTARTS AGE
client-f5cdb799f-pklmc 1/1 Running 0 3d19h
myapp-64qnb 1/1 Running 0 9s
myapp-fxmjz 1/1 Running 0 3m53s
myapp-hdv9c 1/1 Running 0 9s
myapp-hxvnz 1/1 Running 0 3m53s
myapp-mwb27 1/1 Running 0 9s
nginx-deploy-84cbfc56b6-tcssz 1/1 Running 0 3d23h
pod-demo 2/2 Running 7 2d22h
poststart-pod 1/1 Running 1 2d16h
readiness-httpget-pod
修改Pod的鏡像版本:
[root@master manifests]# kubectl edit rs myapp
- image: ikubernetes/myapp:v2
此時查看原來存在的pod副本還是v1版本,只有重建后的pod才會是V2版本。
kubectl delete -f *** && kube create -f &&
Deployment控制器
Deployment為Pod和Replica Set(下一代Replication Controller)提供聲明式更新。
只需要在 Deployment 中描述想要的目標狀態,Deployment controller 就會幫您將 Pod 和ReplicaSet 的實際狀態改變到您的目標狀態。也可以定義一個全新的 Deployment 來創建 ReplicaSet 或者刪除已有的 Deployment 並創建一個新的來替換。
典型的用例如下:
- 使用Deployment來創建ReplicaSet。ReplicaSet在后台創建pod。檢查啟動狀態。
- 通過更新Deployment的PodTemplateSpec字段來聲明Pod的新狀態。這會創建一個新的ReplicaSet,Deployment會按照控制的速率將pod從舊的ReplicaSet移動到新的ReplicaSet中.
- 如果當前狀態不穩定,回滾到之前的Deployment revision。每次回滾都會更新Deployment的revision.
- 擴容Deployment以滿足更高的負載。
- 暫停Deployment來應用PodTemplateSpec的多個修復,然后恢復上線。
- 根據Deployment 的狀態判斷上線是否hang住了。
- 清除舊的不必要的 ReplicaSet。
官方定義
查看deployment.spec定義所需字段:
[root@master ~]# kubectl explain deploy.spec.
KIND: Deployment
VERSION: extensions/v1beta1 #現在最新式apps/v1
minReadySeconds <integer>
paused <boolean> #暫停
progressDeadlineSeconds <integer>
replicas <integer> #replicas
revisionHistoryLimit <integer> #保存歷史版本數量,用於回滾,默認10
rollbackTo <Object> #回滾
selector <Object> #選擇器,和replicaset的一樣
strategy <Object> #更新策略 rollingUpdate滾動更新和Recreate重建更新,如果使用rollingUpdate,內部還可以定義更新粒度
maxSurge #更新時最多可超出副本數 可以是數量和百分比
maxUnavailable #最大不可用 可以是數量和百分比,和上面的maxSurge不能同為0
template <Object> -required- #模板,和replicaset的一樣
創建Deployment
舉例
[root@master manifests]# vim deploy-damo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deploy
namespace: default
spec:
replicas: 2
selector:
matchLabels:
app: myapp
release: canary
template:
metadata:
labels:
app: myapp
release: canary
spec:
containers:
- name: myapp
image: ikubernetes/myapp:v1
imagePullPolicy: IfNotPresent
ports:
- name: http
containerPort: 80
[root@master manifests]# kubectl apply -f deploy-damo.yaml
deployment.apps/myapp-deploy created
Deployment更新
apply表示聲明式創建,也可以用來更新
查看創建結果
[root@master manifests]# kubectl get deploy
NAME READY UP-TO-DATE AVAILABLE AGE
myapp-deploy 2/2 2 2 2m31s
[root@master manifests]# kubectl get rs
NAME DESIRED CURRENT READY AGE
myapp-deploy-65df64765c 2 2 2 3m22s
[root@master manifests]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-deploy-65df64765c-95dwm 1/1 Running 0 3m24s
myapp-deploy-65df64765c-btbhg 1/1 Running 0 3m24s
pod-demo 2/2 Running 8 2d22h
poststart-pod 1/1 Running 2 2d17h
readiness-httpget-pod 1/1 Running 0 2d17h
Deployment擴容
直接編輯deploy-damo.yaml,副本數修改為4,然后使用kubectl apply -f 更新 也可以使用-w 監控實時更新
[root@master manifests]# vim deploy-damo.yaml
replicas: 4
[root@master manifests]# kubectl apply -f deploy-damo.yaml
deployment.apps/myapp-deploy configured
再次查看
[root@master manifests]# kubectl get rs,deploy,pods
NAME DESIRED CURRENT READY AGE
replicaset.extensions/myapp-deploy-65df64765c 4 4 4 6m53s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.extensions/myapp-deploy 4/4 4 4 6m53s
NAME READY STATUS RESTARTS AGE
pod/myapp-deploy-65df64765c-8q8bq 1/1 Running 0 31s
pod/myapp-deploy-65df64765c-95dwm 1/1 Running 0 6m53s
pod/myapp-deploy-65df64765c-btbhg 1/1 Running 0 6m53s
pod/myapp-deploy-65df64765c-x742g 1/1 Running 0 31s
pod/pod-demo 2/2 Running 8 2d22h
pod/poststart-pod 1/1 Running 2 2d17h
pod/readiness-httpget-pod 1/1 Running 0 2d17h
每次使用apply改變的信息都會被保存在annotations里面。
[root@master manifests]# kubectl describe deploy myapp-deploy
Annotations: deployment.kubernetes.io/revision: 1
kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"apps/v1","kind":"Deployment","metadata":{"annotations":{},"name":"myapp-deploy","namespace":"default"},"spec":{"replicas":4...
StrategyType: RollingUpdate #默認滾動策略
RollingUpdateStrategy: 25% max unavailable, 25% max surge #更新策略25% 低於1補為1,
如果只是更新模板的image 可以使用kubectl set image命令
[root@master manifests]# kubectl set image deployment/myapp-deploy myapp=ikubernetes/myapp:v2
如果修改其他配置,例如修改副本數量,滾動更新策略等,可以使用kubectl patch 打補丁后面使用對象的jason格式內容
[root@master ~]# kubectl patch deployment myapp-deploy -p '{"spec":{"replicas":5}}'
[root@master ~]# kubectl patch deployment myapp-deploy -p '{"spec":{"strategy":{"rollingupdate":{"maxsurge“:1,"maxUnavailable":0}}}}'
金絲雀發布
Deployment控制器支持自定義控制更新過程中的滾動節奏,如“暫停(pause)”或“繼續(resume)”更新操作。比如等待第一批新的Pod資源創建完成后立即暫停更新過程,此時,僅存在一部分新版本的應用,主體部分還是舊的版本。然后,再篩選一小部分的用戶請求路由到新版本的Pod應用,繼續觀察能否穩定地按期望的方式運行。確定沒問題之后再繼續完成余下的Pod資源滾動更新,否則立即回滾更新操作。這就是所謂的金絲雀發布(Canary Release),如下:
#更新deloyment的v3版本,並配置暫停deployment
[root@master manifests]# kubectl set image deployment myapp-deploy myapp=ikubernetes/myapp:v3 && kubectl rollout pause deployment myapp-deploy
deployment.extensions/myapp-deploy image updated
deployment.extensions/myapp-deploy paused
#查看
[root@master ~]# kubectl get pod -w
NAME READY STATUS RESTARTS AGE
myapp-deploy-65df64765c-48bjw 1/1 Running 0 8m2s
myapp-deploy-65df64765c-5qd4x 1/1 Running 0 18s
myapp-deploy-65df64765c-w4htd 1/1 Running 0 8m2s
pod-demo 2/2 Running 8 2d23h
poststart-pod 1/1 Running 3 2d17h
readiness-httpget-pod 1/1 Running 0 2d18h
myapp-deploy-548f47d899-cbhsf 0/1 Pending 0 0s
myapp-deploy-548f47d899-cbhsf 0/1 Pending 0 0s
myapp-deploy-548f47d899-cbhsf 0/1 ContainerCreating 0 0s
myapp-deploy-548f47d899-cbhsf 1/1 Running 0 1s
此時只有一個pod版本更新為V3版本
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-deploy-548f47d899-cbhsf 1/1 Running 0 49s
myapp-deploy-65df64765c-48bjw 1/1 Running 0 9m2s
myapp-deploy-65df64765c-5qd4x 1/1 Running 0 78s
myapp-deploy-65df64765c-w4htd 1/1 Running 0 9m2s
pod-demo 2/2 Running 8 2d23h
poststart-pod 1/1 Running 3 2d17h
readiness-httpget-pod 1/1 Running 0 2d18h
確保更新的pod沒問題了,繼續更新
[root@master manifests]# kubectl rollout resume deployment myapp-deploy
deployment.extensions/myapp-deploy resumed
[root@master ~]# kubectl get pods
NAME READY STATUS RESTARTS AGE
myapp-deploy-548f47d899-5rdgh 1/1 Running 0 59s
myapp-deploy-548f47d899-cbhsf 1/1 Running 0 2m54s
myapp-deploy-548f47d899-prvpl 1/1 Running 0 57s
pod-demo 2/2 Running 8 2d23h
poststart-pod 1/1 Running 3 2d17h
readiness-httpget-pod 1/1 Running 0 2d18h
也可以使用kubectl rollout status <TYPE> <TYPE_NAME>監控
[root@master ~]# kubectl rollout status deployment myapp-deploy
deployment "myapp-deploy" successfully rolled out
Deployment回滾
默認情況下,kubernetes 會在系統中保存前兩次的 Deployment 的 rollout 歷史記錄,以便可以隨時回退(您可以修改revision history limit來更改保存的revision數)。
注意: 只要 Deployment 的 rollout 被觸發就會創建一個 revision。也就是說當且僅當 Deployment 的 Pod template(如.spec.template)被更改,例如更新template 中的 label 和容器鏡像時,就會創建出一個新的 revision。
其他的更新,比如擴容 Deployment 不會創建 revision——因此我們可以很方便的手動或者自動擴容。這意味着當您回退到歷史 revision 時,只有 Deployment 中的 Pod template 部分才會回退。
[root@master ~]# kubectl rollout history deploy myapp-deploy #查看升級記錄
deployment.extensions/myapp-deploy
REVISION CHANGE-CAUSE
9 <none>
10 <none>
這里在創建deployment時沒有增加--record參數,所以並不能看到revision的變化。在創建 Deployment 的時候使用了--record參數可以記錄命令,就可以方便的查看每次 revision 的變化。
查看單個revision的詳細信息:
[root@master ~]# kubectl rollout history deployment/myapp-deploy --revision=10
回滾歷史版本,默認是上一個版本
[root@master ~]# kubectl rollout undo deployment/myapp-deploy
deployment.extensions/myapp-deploy rolled back
使用 --to-revision參數指定某個歷史版本:
[root@master ~]# kubectl rollout undo deployment/myapp-deploy --to-revision=11
deployment.extensions/myapp-deploy skipped rollback (current template already matches revision 11)
DaemonSet
定義
DaemonSet確保全部(或者一些)Node上運行一個Pod的副本。當有Node加入集群時也會為他們新增一個Pod。當有Node從集群移除時,這些Pod也會被回收。刪除DaemonSet將會刪除它創建的所有Pod。
DaemonSet 的一些典型用法:
- 運行集群存儲 daemon,例如在每個 Node 上運行 glusterd、ceph。
- 在每個 Node 上運行日志收集 daemon,例如fluentd、logstash。
- 在每個 Node 上運行監控 daemon,例如 Prometheus Node Exporter、collectd、Datadog 代理、New Relic 代理,或 Ganglia gmond。
一個簡單的用法是,在所有的 Node 上都存在一個 DaemonSet,將被作為每種類型的 daemon 使用。 一個稍微復雜的用法可能是,對單獨的每種類型的 daemon 使用多個 DaemonSet,但具有不同的標志,和/或對不同硬件類型具有不同的內存、CPU要求。
[root@master ~]# kubectl explain ds.spec.
KIND: DaemonSet
minReadySeconds <integer>
revisionHistoryLimit <integer>
selector <Object>
template <Object> -required-
templateGeneration <integer>
updateStrategy <Object>
DaemonSet演示 redis-filebeat
[root@master manifests]# vim ds-demo.yaml
apiVersion: apps/v1
kind: Deployment
metadata:
name: redis
namespace": default
spec:
replicas: 1
selector:
matchLabels:
app: redis
role: logstore
template:
metadata:
labels:
app: redis
role: logstore
spec:
containers:
- name: redis
image: redis:4.0-alpine
ports:
- name: redis
containerPort: 6379
---
apiVersion: apps/v1
kind: DaemonSet
metadata:
name: filebeat-ds
namespace: default
spec:
selector:
matchLabels:
app: filebeat
release: stable
template:
metadata:
labels:
app: filebeat
release: stable
spec:
containers:
- name: filebeat
image: ikubernetes/filebeat:5.6.5-alpine
env:
- name: REDIS_HOST
value: redis.default.svc.cluster.local
- name: REDIS_LOG_LEVEL
value: info
創建並暴漏端口
[root@master manifests]# kubectl apply -f ds-demo.yaml
deployment.apps/redis created
daemonset.apps/filebeat-ds created
[root@master manifests]# kubectl expose deploy redis --port=6379
service/redis exposed
[root@master manifests]# kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
kubernetes ClusterIP 10.96.0.1 <none> 443/TCP 4d19h
myapp NodePort 10.104.138.182 <none> 80:30298/TCP 3d21h
nginx ClusterIP 10.98.2.12 <none> 80/TCP 4d
redis ClusterIP 10.97.149.76 <none> 6379/TCP 15s
測試redis是否收到日志
[root@master manifests]# kubectl get pods
NAME READY STATUS RESTARTS AGE
filebeat-ds-28kmv 1/1 Running 0 48s
filebeat-ds-wmlzj 1/1 Running 0 48s
myapp-deploy-65df64765c-9g9bv 1/1 Running 0 29m
myapp-deploy-65df64765c-ll8bk 1/1 Running 0 29m
myapp-deploy-65df64765c-xd2kn 1/1 Running 0 29m
pod-demo 2/2 Running 9 3d
poststart-pod 1/1 Running 3 2d18h
readiness-httpget-pod 1/1 Running 0 2d18h
redis-76c85b5744-7zt7l 1/1 Running 0 48s
#進入redis
[root@master manifests]# kubectl exec -it redis-76c85b5744-7zt7l -- /bin/sh
/data # netstat -lnt
Active Internet connections (only servers)
Proto Recv-Q Send-Q Local Address Foreign Address State
tcp 0 0 0.0.0.0:6379 0.0.0.0:* LISTEN
tcp 0 0 :::6379 :::* LISTEN
/data # nslookup redis.default.svc.cluster.local
nslookup: can't resolve '(null)': Name does not resolve
Name: redis.default.svc.cluster.local
Address 1: 10.97.149.76 redis.default.svc.cluster.local
#由於redis在filebeat后面才啟動,日志可能已經發走了,所以查看key為空
/data # redis-cli -h redis.default.svc.cluster.local
redis.default.svc.cluster.local:6379> keys *
(empty list or set)
#進入filebeat容器
[root@master manifests]# kubectl get pods
NAME READY STATUS RESTARTS AGE
filebeat-ds-28kmv 1/1 Running 0 4m48s
filebeat-ds-wmlzj 1/1 Running 0 4m48s
myapp-deploy-65df64765c-9g9bv 1/1 Running 0 33m
myapp-deploy-65df64765c-ll8bk 1/1 Running 0 33m
myapp-deploy-65df64765c-xd2kn 1/1 Running 0 33m
pod-demo 2/2 Running 9 3d
poststart-pod 1/1 Running 3 2d18h
readiness-httpget-pod 1/1 Running 0 2d18h
redis-76c85b5744-7zt7l 1/1 Running 0 4m48s
[root@master manifests]# kubectl exec -it filebeat-ds-28kmv -- /bin/sh
#查看filebeat配置文件
filebeat.registry_file: /var/log/containers/filebeat_registry
filebeat.idle_timeout: 5s
filebeat.spool_size: 2048
logging.level: info
filebeat.prospectors:
- input_type: log
paths:
- "/var/log/containers/*.log"
- "/var/log/docker/containers/*.log"
- "/var/log/startupscript.log"
- "/var/log/kubelet.log"
- "/var/log/kube-proxy.log"
- "/var/log/kube-apiserver.log"
- "/var/log/kube-controller-manager.log"
- "/var/log/kube-scheduler.log"
- "/var/log/rescheduler.log"
- "/var/log/glbc.log"
- "/var/log/cluster-autoscaler.log"
symlinks: true
json.message_key: log
json.keys_under_root: true
json.add_error_key: true
multiline.pattern: '^\s'
multiline.match: after
document_type: kube-logs
tail_files: true
fields_under_root: true
output.redis:
hosts: ${REDIS_HOST:?No Redis host configured. Use env var REDIS_HOST to set host.}
key: "filebeat"
DaemonSet的滾動更新
DaemonSet有兩種更新策略類型:
[root@master ~]# kubectl explain ds.spec.updateStrategy.type.
KIND: DaemonSet
VERSION: extensions/v1beta1
FIELD: type <string>
DESCRIPTION:
Type of daemon set update. Can be "RollingUpdate" or "OnDelete". Default is
OnDelete.
- OnDelete:向后兼容性的默認更新策略。使用 OnDelete更新策略,在更新DaemonSet模板后,只有在手動刪除舊的DaemonSet pod時才會創建新的DaemonSet pod。這與Kubernetes 1.5或更早版本中DaemonSet的行為相同
- RollingUpdate:使用RollingUpdate更新策略,在更新DaemonSet模板后,舊的DaemonSet pod將被終止,並且將以受控方式自動創建新的DaemonSet pod。
要啟用DaemonSet的滾動更新功能,必須將其設置 .spec.updateStrategy.type為RollingUpdate。
查看當前的更新策略:
[root@master manifests]# kubectl get ds/filebeat-ds -o go-template='{{.spec.updateStrategy.type}}{{"\n"}}'
RollingUpdate
更新DaemonSet模板
對RollingUpdateDaemonSet的任何更新都.spec.template將觸發滾動更新。這可以通過幾個不同的kubectl命令來完成。
- 聲明式命令方式: 修改配置文件后使用kubectl apply更新
2)補丁式命令方式:kubectl edit ds/filebeat-ds
kubectl patch ds/filebeat-ds -p=<strategic-merge-patch>
僅僅更新容器鏡像還可以使用以下命令:
kubectl set image ds/<daemonset-name> <container-name>=<container-new-image>
對filebeat-ds的鏡像進行版本更新
[root@master manifests]# kubectl set image ds filebeat-ds filebeat=ikubernetes/filebeat:5.6.6-alpine
daemonset.extensions/filebeat-ds image updated
[root@master manifests]# kubectl get pods -w
NAME READY STATUS RESTARTS AGE
filebeat-ds-28kmv 1/1 Running 0 21m
filebeat-ds-wmlzj 0/1 Terminating 0 21m
myapp-deploy-65df64765c-9g9bv 1/1 Running 0 50m
myapp-deploy-65df64765c-ll8bk 1/1 Running 0 50m
myapp-deploy-65df64765c-xd2kn 1/1 Running 0 50m
pod-demo 2/2 Running 10 3d
poststart-pod 1/1 Running 4 2d18h
readiness-httpget-pod 1/1 Running 0 2d19h
redis-76c85b5744-7zt7l 1/1 Running 0 21m
filebeat-ds-wmlzj 0/1 Terminating 0 21m
filebeat-ds-wmlzj 0/1 Terminating 0 21m
filebeat-ds-j69gd 0/1 Pending 0 0s
filebeat-ds-j69gd 0/1 Pending 0 0s
filebeat-ds-j69gd 0/1 ContainerCreating 0 0s
filebeat-ds-j69gd 1/1 Running 0 14s
filebeat-ds-28kmv 1/1 Terminating 0 21m
filebeat-ds-28kmv 0/1 Terminating 0 21m
filebeat-ds-28kmv 0/1 Terminating 0 21m
filebeat-ds-28kmv 0/1 Terminating 0 21m
filebeat-ds-p5r4n 0/1 Pending 0 0s
filebeat-ds-p5r4n 0/1 Pending 0 0s
filebeat-ds-p5r4n 0/1 ContainerCreating 0 0s
filebeat-ds-p5r4n 1/1 Running 0 13s
從上面的滾動更新,可以看到在更新過程中,是先終止舊的pod,再創建一個新的pod,逐步進行替換的,這就是DaemonSet的滾動更新策略。
參考資料
https://www.cnblogs.com/linuxk
馬永亮. Kubernetes進階實戰 (雲計算與虛擬化技術叢書)
Kubernetes-handbook-jimmysong-20181218