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 最大弹性数量、升级顺序、打散策略、生命周期钩子等,鉴于文章篇幅,这些特性不再演示了,有需要的可以查看官方文档。
原文地址:https://www.toutiao.com/i6909374901640118788/