OpenKruise
OpenKruise 是 Kubernetes 的一個標準擴充套件,它可以配合原生 Kubernetes 使用,併為管理應用容器、sidecar、映象分發等方面提供更加強大和高效的能力。
核心功能
-
原地升級
原地升級是一種可以避免刪除、新建 Pod 的升級映象能力。它比原生 Deployment/StatefulSet 的重建 Pod 升級更快、更高效,並且避免對 Pod 中其他不需要更新的容器造成干擾。 -
Sidecar 管理
支援在一個單獨的 CR 中定義 sidecar 容器,OpenKruise 能夠幫你把這些 Sidecar 容器注入到所有符合條件的 Pod 中。這個過程和 Istio 的注入很相似,但是你可以管理任意你關心的 Sidecar。 -
跨多可用區部署
定義一個跨多個可用區的全域性 workload,容器,OpenKruise 會幫你在每個可用區建立一個對應的下屬 workload。你可以統一管理他們的副本數、版本、甚至針對不同可用區採用不同的釋出策略。
CRD 列表
CloneSet
提供更加高效、確定可控的應用管理和部署能力,支援優雅原地升級、指定刪除、釋出順序可配置、並行/灰度釋出等豐富的策略,可以滿足更多樣化的應用場景。
Advanced StatefulSet
基於原生 StatefulSet 之上的增強版本,預設行為與原生完全一致,在此之外提供了原地升級、並行釋出(最大不可用)、釋出暫停等功能。
SidecarSet
對 sidecar 容器做統一管理,在滿足 selector 條件的 Pod 中注入指定的 sidecar 容器。
UnitedDeployment
通過多個 subset workload 將應用部署到多個可用區。
BroadcastJob
配置一個 job,在叢集中所有滿足條件的 Node 上都跑一個 Pod 任務。
Advanced DaemonSet
基於原生 DaemonSet 之上的增強版本,預設行為與原生一致,在此之外提供了灰度分批、按 Node label 選擇、暫停、熱升級等釋出策略。
AdvancedCronJob
一個擴充套件的 CronJob 控制器,目前 template 模板支援配置使用 Job 或 BroadcastJob。
以上在官方文件都有介紹,本文主要著重實戰,先講CloneSet,其他控制器後面會陸續更新。。。
部署Kruise到Kubernetes叢集
這裡使用helm來安裝Kruise
1、現在kruise Chart
wget https://github.com/openkruise/kruise/releases/download/v0.7.0/kruise-chart.tgz
tar -zxf kruise-chart.tgz
cd kruise
[root@ kruise]# ls -l
total 16
-rw-r--r-- 1 root root 311 Dec 20 15:09 Chart.yaml
-rw-r--r-- 1 root root 4052 Dec 20 15:09 README.md
drwxr-xr-x 2 root root 4096 Dec 23 10:18 templates
-rw-r--r-- 1 root root 659 Dec 20 15:09 values.yaml
2、修改values.yaml,預設不用修改也行
3、執行部署
[root@qd01-stop-k8s-master001 kruise]# kubectl create ns kruise
namespace/kruise created
[root@qd01-stop-k8s-master001 kruise]# helm install kruise -n kruise -f values.yaml .
W1223 10:22:13.562088 1589994 warnings.go:67] apiextensions.k8s.io/v1beta1 CustomResourceDefinition is deprecated in v1.16+, unavailable in v1.22+; use apiextensions.k8s.io/v1 CustomResourceDefinition
。。。。。。。
NAME: kruise
LAST DEPLOYED: Wed Dec 23 10:22:12 2020
NAMESPACE: kruise
STATUS: deployed
REVISION: 1
TEST SUITE: None
這裡會看到一堆的deprecated資訊,因為新版的kubernetes對CRD的版本會淘汰,可以根據自己的叢集版本修改CRD的API版本即可
4、檢查kruise部署狀態
[root@qd01-stop-k8s-master001 kruise]# helm ls -n kruise
NAME NAMESPACE REVISION UPDATED STATUS CHART APP VERSION
kruise kruise 1 2020-12-23 10:22:12.963651877 +0800 CST deployed kruise-0.7.0
可以看到,叢集中有的kruise crd型別
[root@qd01-stop-k8s-master001 kruise]# kubectl get crd|grep kruise
advancedcronjobs.apps.kruise.io 2020-12-23T02:22:13Z
broadcastjobs.apps.kruise.io 2020-12-23T02:22:13Z
clonesets.apps.kruise.io 2020-12-23T02:22:13Z
daemonsets.apps.kruise.io 2020-12-23T02:22:13Z
sidecarsets.apps.kruise.io 2020-12-23T02:22:13Z
statefulsets.apps.kruise.io 2020-12-23T02:22:13Z
uniteddeployments.apps.kruise.io 2020-12-23T02:22:13Z
下面我們開始來使用這些管理器
CloneSet
CloneSet 控制器提供了高效管理無狀態應用的能力,它可以對標原生的 Deployment,但 CloneSet 提供了很多增強功能。
1、我們先建立一個簡單的CloneSet,yaml如下
apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
labels:
app: nginx-alpine
name: nginx-alpine
spec:
replicas: 5
selector:
matchLabels:
app: nginx-alpine
template:
metadata:
labels:
app: nginx-alpine
spec:
containers:
- name: nginx
image: nginx:alpine
2、部署
[root@qd01-stop-k8s-master001 demo]# kubectl apply -f CloneSet.yaml
cloneset.apps.kruise.io/nginx-alpine created
[root@qd01-stop-k8s-master001 demo]# kubectl get po |grep nginx
nginx-alpine-29g7n 1/1 Running 0 45s
nginx-alpine-bvgqm 1/1 Running 0 45s
nginx-alpine-q9tlw 1/1 Running 0 45s
nginx-alpine-s2t46 1/1 Running 0 44s
nginx-alpine-sslvf 1/1 Running 0 44s
從輸出結果看,和原生的Deployment沒有啥區別
#注意,這裡如果get deployment是看不到nginx-alpine這個應用的,需要get cloneset才能看到
[root@qd01-stop-k8s-master001 demo]# kubectl get deployment
[root@qd01-stop-k8s-master001 demo]# kubectl get cloneset
NAME DESIRED UPDATED UPDATED_READY READY TOTAL AGE
nginx-alpine 5 5 5 5 5 2m16s
CloneSet 允許使用者配置 PVC 模板 volumeClaimTemplates,用來給每個 Pod 生成獨享的 PVC,這是 Deployment 所不支援的。 如果使用者沒有指定這個模板,CloneSet 會建立不帶 PVC 的 Pod。
3、現在來建立一個帶有 PVC 模板的例子
apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
labels:
app: nginx-2
name: nginx-2
spec:
replicas: 5
selector:
matchLabels:
app: nginx-2
template:
metadata:
labels:
app: nginx-2
spec:
containers:
- name: nginx
image: nginx:alpine
volumeMounts:
- name: data-vol
mountPath: /usr/share/nginx/html
volumeClaimTemplates:
- metadata:
name: rbd
spec:
accessModes: [ "ReadWriteOnce" ]
storageClassName: rbd
resources:
requests:
storage: 2Gi
部署
[root@qd01-stop-k8s-master001 demo]# kubectl apply -f CloneSet.yaml
cloneset.apps.kruise.io/nginx-2 created
[root@qd01-stop-k8s-master001 demo]# kubectl get pv|grep data-vol
pvc-0fde19f3-ea4b-47e0-81be-a8e43812e47b 2Gi RWO Delete Bound default/data-vol-nginx-2-t55h8 rbd 83s
pvc-72accf10-57a6-4418-a1bc-c64633b84434 2Gi RWO Delete Bound default/data-vol-nginx-2-t49mk rbd 82s
pvc-8fc8b9a5-afe8-446a-9190-08fcee0ec9f6 2Gi RWO Delete Bound default/data-vol-nginx-2-jw2zp rbd 84s
pvc-c9fba396-e357-43e8-9510-616f698da765 2Gi RWO Delete Bound default/data-vol-nginx-2-b5fdd rbd 84s
pvc-e5302eab-a9f2-4a71-a5a3-4cd43205e8a0 2Gi RWO Delete Bound default/data-vol-nginx-2-l54dz rbd 84s
[root@qd01-stop-k8s-master001 demo]# kubectl get po|grep nginx
nginx-2-b5fdd 1/1 Running 0 97s
nginx-2-jw2zp 1/1 Running 0 97s
nginx-2-l54dz 1/1 Running 0 97s
nginx-2-t49mk 1/1 Running 0 96s
nginx-2-t55h8 1/1 Running 0 96s
從部署結果可以看到,每個pod都建立了一個PVC,這個是原生的Deployment不能實現的。
注意:
每個被自動建立的 PVC 會有一個 ownerReference 指向 CloneSet,因此 CloneSet 被刪除時,它建立的所有 Pod 和 PVC 都會被刪除。
每個被 CloneSet 建立的 Pod 和 PVC,都會帶一個 apps.kruise.io/cloneset-instance-id: xxx 的 label。關聯的 Pod 和 PVC 會有相同的 instance-id,且它們的名字字尾都是這個 instance-id。
如果一個 Pod 被 CloneSet controller 縮容刪除時,這個 Pod 關聯的 PVC 都會被一起刪掉。
如果一個 Pod 被外部直接呼叫刪除或驅逐時,這個 Pod 關聯的 PVC 還都存在;並且 CloneSet controller 發現數量不足重新擴容時,新擴出來的 Pod 會複用原 Pod 的 instance-id 並關聯原來的 PVC。
當 Pod 被重建升級時,關聯的 PVC 會跟隨 Pod 一起被刪除、新建。
當 Pod 被原地升級時,關聯的 PVC 會持續使用。
4、指定 Pod 縮容
當一個 CloneSet 被縮容時,有時候使用者需要指定一些 Pod 來刪除。這對於 StatefulSet 或者 Deployment 來說是無法實現的,因為 StatefulSet 要根據序號來刪除 Pod,而 Deployment/ReplicaSet 目前只能根據控制器裡定義的排序來刪除。
CloneSet 允許使用者在縮小 replicas 數量的同時,指定想要刪除的 Pod 名字。
現在我們來修改上面例子的部署檔案,指定刪除nginx-2-t55h8
這個Pod
apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
labels:
app: nginx-2
name: nginx-2
spec:
replicas: 4
scaleStrategy:
podsToDelete:
- nginx-2-t55h8
然後更新yaml檔案
[root@qd01-stop-k8s-master001 demo]# kubectl apply -f CloneSet.yaml
cloneset.apps.kruise.io/nginx-2 configured
[root@qd01-stop-k8s-master001 demo]# kubectl get po|grep nginx
nginx-2-b5fdd 1/1 Running 0 11m
nginx-2-jw2zp 1/1 Running 0 11m
nginx-2-l54dz 1/1 Running 0 11m
nginx-2-t49mk 1/1 Running 0 11m
現在看輸入結果,已經沒有nginx-2-t55h8
這個Pod了
這個功能很實用,比如某臺機器故障了,或者負載太高,你想刪除指定的pod。
5、升級功能
CloneSet 提供了和 Advanced StatefulSet 相同的 3 個升級方式,預設為 ReCreate:
ReCreate: 控制器會刪除舊 Pod 和它的 PVC,然後用新版本重新建立出來。
InPlaceIfPossible: 控制器會優先嚐試原地升級 Pod,如果不行再採用重建升級。目前,只有修改 spec.template.metadata.* 和 spec.template.spec.containers[x].image 這些欄位才可以走原地升級。
InPlaceOnly: 控制器只允許採用原地升級。因此,使用者只能修改上一條中的限制欄位,如果嘗試修改其他欄位會被 Kruise 拒絕。
現在我們來嘗試原地升級Pod功能,把nginx映象由nginx:alpine 升級為 nginx:latest
首先修改yaml檔案,這裡只貼上出檔案的修改的部分
apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
...
spec:
replicas: 4
updateStrategy:
type: InPlaceIfPossible
inPlaceUpdateStrategy:
gracePeriodSeconds: 10
......
spec:
containers:
- name: nginx
image: nginx
執行升級
[root@qd01-stop-k8s-master001 demo]# kubectl apply -f CloneSet.yaml
cloneset.apps.kruise.io/nginx-2 configured
使用 kubectl describe檢視升級過程
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Warning FailedScheduling 59m default-scheduler 0/22 nodes are available: 22 pod has unbound immediate PersistentVolumeClaims.
Warning FailedScheduling 59m default-scheduler 0/22 nodes are available: 22 pod has unbound immediate PersistentVolumeClaims.
Warning FailedScheduling 59m default-scheduler 0/22 nodes are available: 22 pod has unbound immediate PersistentVolumeClaims.
Normal Scheduled 59m default-scheduler Successfully assigned default/nginx-2-l54dz to qd01-stop-k8s-node007.ps.easou.com
Normal SuccessfulAttachVolume 59m attachdetach-controller AttachVolume.Attach succeeded for volume "pvc-e5302eab-a9f2-4a71-a5a3-4cd43205e8a0"
Normal Pulling 58m kubelet Pulling image "nginx:alpine"
Normal Pulled 58m kubelet Successfully pulled image "nginx:alpine" in 6.230045975s
Normal Killing 55s kubelet Container nginx definition changed, will be restarted
Normal Pulling 55s kubelet Pulling image "nginx"
Normal Pulled 26s kubelet Successfully pulled image "nginx" in 29.136659264s
Normal Created 23s (x2 over 58m) kubelet Created container nginx
Normal Started 23s (x2 over 58m) kubelet Started container nginx
從輸出可以看到,Container nginx definition changed, will be restarted
,Pod並沒有刪除在重建,而是在原來的基礎上直接更新了映象檔案,並重啟了服務。
原地升級減少了刪除重建環節,節省了升級時間和資源排程頻率。。。
6、Partition 分批灰度
Partition 的語義是 保留舊版本 Pod 的數量或百分比,預設為 0。這裡的 partition 不表示任何 order 序號。
在釋出過程中設定了 partition:
如果是數字,控制器會將 (replicas - partition) 數量的 Pod 更新到最新版本。
如果是百分比,控制器會將 (replicas * (100% - partition)) 數量的 Pod 更新到最新版本。
現在我將上面的例子的 image 更新為 nginx:1.19.6-alpine 並且設定 partition=3
kind: CloneSet
metadata:
labels:
app: nginx-2
name: nginx-2
spec:
replicas: 5
updateStrategy:
type: InPlaceIfPossible
inPlaceUpdateStrategy:
gracePeriodSeconds: 10
partition: 3
selector:
matchLabels:
app: nginx-2
template:
metadata:
labels:
app: nginx-2
spec:
containers:
- name: nginx
image: nginx:1.19.6-alpine
檢視結果
Status:
Available Replicas: 5
Collision Count: 0
Label Selector: app=nginx-2
Observed Generation: 6
Ready Replicas: 5
Replicas: 5
Update Revision: nginx-2-7b44cb9c8
Updated Ready Replicas: 2
Updated Replicas: 2
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulUpdatePodInPlace 45m cloneset-controller successfully update pod nginx-2-l54dz in-place(revision nginx-2-5879fd9f7)
Normal SuccessfulUpdatePodInPlace 44m cloneset-controller successfully update pod nginx-2-t49mk in-place(revision nginx-2-5879fd9f7)
Normal SuccessfulUpdatePodInPlace 43m cloneset-controller successfully update pod nginx-2-b5fdd in-place(revision nginx-2-5879fd9f7)
Normal SuccessfulUpdatePodInPlace 43m cloneset-controller successfully update pod nginx-2-jw2zp in-place(revision nginx-2-5879fd9f7)
Normal SuccessfulCreate 22m cloneset-controller succeed to create pod nginx-2-zpp8z
Normal SuccessfulUpdatePodInPlace 5m22s cloneset-controller successfully update pod nginx-2-zpp8z in-place(revision nginx-2-7b44cb9c8)
Normal SuccessfulUpdatePodInPlace 4m55s cloneset-controller successfully update pod nginx-2-jw2zp in-place(revision nginx-2-7b44cb9c8)
[root@qd01-stop-k8s-master001 demo]# kubectl get pod -L controller-revision-hash
NAME READY STATUS RESTARTS AGE CONTROLLER-REVISION-HASH
nginx-2-b5fdd 1/1 Running 1 99m nginx-2-5879fd9f7
nginx-2-jw2zp 1/1 Running 2 99m nginx-2-7b44cb9c8
nginx-2-l54dz 1/1 Running 1 99m nginx-2-5879fd9f7
nginx-2-t49mk 1/1 Running 1 99m nginx-2-5879fd9f7
nginx-2-zpp8z 1/1 Running 1 19m nginx-2-7b44cb9c8
從輸出資訊我們可以看到,Update Revision已經更新為nginx-2-7b44cb9c8
,而Pod中只有兩個Pod升級了。
由於我們設定了 partition=3,控制器只升級了 2 個 Pod。
Partition 分批灰度功能完善了原生的Pod升級方式,使得升級能夠進行更靈活,能夠進行灰度上線。超讚。。。
7、最後再演示下發布暫停
使用者可以通過設定 paused 為 true 暫停釋出,不過控制器還是會做 replicas 數量管理:
- 首先,我們將示例中image改為nginx:1.18.0 並設定副本數為10,修改後更新yaml,執行結果如下:
[root@qd01-stop-k8s-master001 demo]# kubectl get po -o=jsonpath='{range .items[*]}{"\n"}{.metadata.name}{":\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}' |sort
nginx-2-7lzx9: nginx:1.18.0,
nginx-2-b5fdd: nginx:1.18.0,
nginx-2-jw2zp: nginx:1.18.0,
nginx-2-l54dz: nginx:1.18.0,
nginx-2-nknrt: nginx:1.18.0,
nginx-2-rgmsc: nginx:1.18.0,
nginx-2-rpr5z: nginx:1.18.0,
nginx-2-t49mk: nginx:1.18.0,
nginx-2-v2bpx: nginx:1.18.0,
nginx-2-zpp8z: nginx:1.18.0,
- 現在我們修改yaml檔案,將image修改為nginx:alpine 執行更新,執行如下
[root@qd01-stop-k8s-master001 demo]# kubectl get po -o=jsonpath='{range .items[*]}{"\n"}{.metadata.name}{":\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}' |sort
nginx-2-7lzx9: nginx:1.18.0,
nginx-2-b5fdd: nginx:1.18.0,
nginx-2-jw2zp: nginx:1.18.0,
nginx-2-l54dz: nginx:1.18.0,
nginx-2-nknrt: nginx:alpine,
nginx-2-rgmsc: nginx:alpine,
nginx-2-rpr5z: nginx:alpine,
nginx-2-t49mk: nginx:1.18.0,
nginx-2-v2bpx: nginx:alpine,
nginx-2-zpp8z: nginx:1.18.0,
- 現在看到,有4個pod的image已經更新為nginx:alpine 然後我們再次修改yaml檔案,新增
paused: true
spec:
replicas: 10
updateStrategy:
paused: true
type: InPlaceIfPossible
inPlaceUpdateStrategy:
gracePeriodSeconds: 10
- 再次執行apply,更新yaml,再次檢視更新進度,發現pod並沒有繼續更新了,已經暫停升級image了
[root@qd01-stop-k8s-master001 demo]# kubectl get po -o=jsonpath='{range .items[*]}{"\n"}{.metadata.name}{":\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}' |sort
nginx-2-7lzx9: nginx:1.18.0,
nginx-2-b5fdd: nginx:1.18.0,
nginx-2-jw2zp: nginx:1.18.0,
nginx-2-l54dz: nginx:1.18.0,
nginx-2-nknrt: nginx:alpine,
nginx-2-rgmsc: nginx:alpine,
nginx-2-rpr5z: nginx:alpine,
nginx-2-t49mk: nginx:1.18.0,
nginx-2-v2bpx: nginx:alpine,
nginx-2-zpp8z: nginx:1.18.0,
- 最後把
paused: true
取消,再次apply yaml檔案,升級會繼續。。。
[root@qd01-stop-k8s-master001 demo]# kubectl get po -o=jsonpath='{range .items[*]}{"\n"}{.metadata.name}{":\t"}{range .spec.containers[*]}{.image}{", "}{end}{end}' |sort
nginx-2-7lzx9: nginx:alpine,
nginx-2-b5fdd: nginx:alpine,
nginx-2-jw2zp: nginx:alpine,
nginx-2-l54dz: nginx:alpine,
nginx-2-nknrt: nginx:alpine,
nginx-2-rgmsc: nginx:alpine,
nginx-2-rpr5z: nginx:alpine,
nginx-2-t49mk: nginx:alpine,
nginx-2-v2bpx: nginx:alpine,
nginx-2-zpp8z: nginx:alpine,
以上就是整個釋出暫停的演示,這個功能好處就是;我們在升級的過程中可以隨時中斷升級。
除此之外,CloneSet還有很多特性,例如:MaxUnavailable 最大不可用數量、MaxSurge 最大彈性數量、升級順序、打散策略、生命週期鉤子等,鑑於文章篇幅,這些特性不再演示了,有需要的可以檢視官方文件。