1、简介

OpenKruise 由 Alibaba 开源,是 Kubernetes 的一个标准扩展,它可以配合原生 Kubernetes 使用,对云原生应用的自动化,比如部署、发布、运维以及可用性防护做了很多贡献。

OpenKruise 是面向自动化场景的 Kubernetes 应用负载扩展控制器。而 Kruise 是 OpenKruise 项目的核心,它是一组控制器,可在应用程序工作负载管理上扩展和补充 Kubernetes 核心控制器。OpenKruise 弥补了 Kubernetes 在应用部署、升级、防护、运维等领域的不足。

2、核心功能

  • 原地升级:原地升级是一种可以避免删除、新建 Pod 的升级镜像能力。它比原生 Deployment/StatefulSet 的重建 Pod 升级更快、更高效,并且避免对 Pod 中其他不需要更新的容器造成干扰。
  • Sidecar 管理:支持在一个单独的 CR 中定义 sidecar 容器,OpenKruise 能够帮你把这些 Sidecar 容器注入到所有符合条件的 Pod 中。这个过程和 Istio 的注入很相似,但是你可以管理任意你关心的 Sidecar。
  • 跨多可用区部署:定义一个跨多个可用区的全局 workload、容器,OpenKruise 会帮你在每个可用区创建一个对应的下属 workload。你可以统一管理 workload 的副本数、版本、甚至针对不同可用区采用不同的发布策略。
  • 镜像预热:支持用户指定在任意范围的节点上下载镜像。

3、架构

OpenKruise所有功能都是通过CRD来提供的:

[root@mast01 OpenKruise]# kubectl get crd | grep kruise.io
advancedcronjobs.apps.kruise.io                       2024-09-24T07:20:47Z
broadcastjobs.apps.kruise.io                          2024-09-24T07:20:47Z
clonesets.apps.kruise.io                              2024-09-24T07:20:47Z
containerrecreaterequests.apps.kruise.io              2024-09-24T07:20:47Z
daemonsets.apps.kruise.io                             2024-09-24T07:20:47Z
imagepulljobs.apps.kruise.io                          2024-09-24T07:20:47Z
nodeimages.apps.kruise.io                             2024-09-24T07:20:47Z
nodepodprobes.apps.kruise.io                          2024-09-24T07:20:47Z
persistentpodstates.apps.kruise.io                    2024-09-24T07:20:47Z
podprobemarkers.apps.kruise.io                        2024-09-24T07:20:47Z
podunavailablebudgets.policy.kruise.io                2024-09-24T07:20:47Z
resourcedistributions.apps.kruise.io                  2024-09-24T07:20:47Z
sidecarsets.apps.kruise.io                            2024-09-24T07:20:47Z
statefulsets.apps.kruise.io                           2024-09-24T07:20:47Z
uniteddeployments.apps.kruise.io                      2024-09-24T07:20:47Z
workloadspreads.apps.kruise.io                        2024-09-24T07:20:47Z

CRD列表

  • CloneSet: 提供更加高效、确定可控的应用管理和部署能力,支持优雅原地升级、指定删除、发布顺序可配置、并行/灰度发布等丰富的策略,可以满足更多样化的应用场景。
  • StatefulSet: 基于原生 StatefulSet 之上的增强版本,默认行为与原生完全一致,在此之外提供了原地升级、并行发布(最大不可用)、发布暂停等功能。
  • SidecarSet: 对 sidecar 容器做统一管理,在满足 selector 条件的 Pod 中注入指定的 sidecar 容器。
  • UnitedDeployment: 通过多个 subset workload 将应用部署到多个可用区。
  • BroadcastJob: 配置一个 job,在集群中所有满足条件的 Node 上都跑一个 Pod 任务。
  • DaemonSet: 基于原生 DaemonSet 之上的增强版本,默认行为与原生一致,在此之外提供了灰度分批、按 Node label 选择、暂停、热升级等发布策略。
  • AdvancedCronJob: 一个扩展的 CronJob 控制器,目前 template 模板支持配置使用 Job 或 BroadcastJob。
  • ImagePullJob: 支持用户指定在任意范围的节点上下载镜像 。

4、原地升级特性

  • 避免重建 Pod:传统 Kubernetes 滚动更新会通过删除旧 Pod、创建新 Pod 的方式进行容器镜像升级。而 OpenKruise 的原地升级不删除 Pod,仅更新其容器镜像。
  • 状态保留:对于有状态服务,保持 Pod 不重启,原地升级可以保留服务的网络、状态和其他相关信息,避免因 Pod 重新调度引起的中断。
  • 自定义更新控制:通过设置策略和条件,可以灵活控制哪些条件下允许进行原地更新,比如镜像版本的更新、资源的调整等。

5、使用场景

  • 有状态服务:如数据库、缓存服务等,这类服务往往需要长时间运行,无法接受频繁的 Pod 重建,原地升级可以保证这些服务的平稳运行。
  • 大规模微服务集群:对微服务集群中的某些容器进行更新,而不影响其他部分的服务,减少了服务中断的可能性。
  • 资源紧张环境:在资源受限的环境中,避免重建 Pod 可以节省调度和资源开销,提升系统的稳定性。

6、安装

#添加镜像仓库
$ helm repo add openkruise https://openkruise.github.io/charts/

#更新本地的 Helm chart 仓库
$ helm repo update

#安装(k8s集群用的docker,别用太高版本,太高版本用的Containerd,会有问题)
helm install kruise openkruise/kruise --version 1.3.0

#卸载
$ helm uninstall kruise

7、部署

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
name: demo
namespace: default
spec:
replicas: 3
selector:
  matchLabels:
    app: cs
template:
  metadata:
    labels:
      app: cs
  spec:
    containers:
    - name: nginx
      image: nginx:alpine
      imagePullPolicy: IfNotPresent
      ports:
      - containerPort: 80

创建成功之后通过 kubectl describe命令查看对应的 Events 信息,可以发现 cloneset-controller 是直接创建的 Pod,而原生的Deployment 是通过 ReplicaSet 去创建的 Pod

[root@mast01 CloneSet]# kubectl apply -f 1.yaml
cloneset.apps.kruise.io/demo created

[root@mast01 CloneSet]# kubectl get cloneset demo
NAME   DESIRED   UPDATED   UPDATED_READY   READY   TOTAL   AGE
demo   3         3         3               3       3       13m

[root@mast01 CloneSet]# kubectl describe cloneset demo
Status:
Available Replicas:         3
Collision Count:            0
Current Revision:           demo-5c5f449787
Expected Updated Replicas:  3
Label Selector:             app=cs
Observed Generation:        1
Ready Replicas:             3
Replicas:                   3
Update Revision:           demo-5c5f449787
Updated Ready Replicas:     3
Updated Replicas:           3
Events:
Type   Reason           Age   From                 Message
 ----    ------            ----  ----                 -------
Normal SuccessfulCreate 13m   cloneset-controller succeed to create pod demo-slfrq
Normal SuccessfulCreate 13m   cloneset-controller succeed to create pod demo-s2rhp
Normal SuccessfulCreate 12m   cloneset-controller succeed to create pod demo-tsgqn

8、扩容

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
name: demo
namespace: default
spec:
minReadySeconds: 30 # 创建了一个pod之后30s后才会创建第二个
scaleStrategy:
  maxUnavailable: 1
replicas: 5
selector:
  matchLabels:
    app: cs
template:
  metadata:
    labels:
      app: cs
  spec:
    containers:
    - name: nginx
      image: nginx:alpine
      imagePullPolicy: IfNotPresent
      ports:
      - containerPort: 80

滚动更新时 Pod 的可用性和更新速度的两个重要参数

  • maxUnavailable:指在滚动更新过程中,最多可以有多少个不可用的 Pod。例如,设置为 1 表示在更新期间,最多只能有 1 个 Pod 处于不可用状态。这个参数确保在更新期间,总是有一定数量的 Pod 保持可用,防止服务中断。
  • maxSurge:指在滚动更新过程中,最多可以有多少个额外的 Pod 超过期望的副本数量。例如,设置为 1 表示在更新期间,可以临时创建多 1 个 Pod,从而加快更新过程。
[root@mast01 CloneSet]# kubectl apply -f 2.yaml
cloneset.apps.kruise.io/demo configured

[root@mast01 CloneSet]# kubectl get pod
NAME         READY   STATUS   RESTARTS   AGE
demo-2hz68   1/1     Running   0         6m18s
demo-c2gsl   1/1     Running   0         5m46s
demo-s2rhp   1/1     Running   0         39m
demo-slfrq   1/1     Running   0         39m
demo-tsgqn   1/1     Running   0         38m

9、缩容

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
name: demo
namespace: default
spec:
minReadySeconds: 30
scaleStrategy:
  maxUnavailable: 1
  podsToDelete:
  - demo-2hz68     # 优先删除这些
replicas: 4
selector:
  matchLabels:
    app: cs
template:
  metadata:
    labels:
      app: cs
  spec:
    containers:
    - name: nginx
      image: nginx:alpine
      imagePullPolicy: IfNotPresent
      ports:
      - containerPort: 80

缩容时,CloneSet可以指定一些pod删除,而 StatefulSet 或者 Deployment 做不到

  • StatefulSet 是根据序号来删除 Pod,而 Deployment/ReplicaSet 目前只能根据控制器里定义的排序来删除。而 CloneSet 允许用户在缩小 replicas 数量的同时,指定想要删除的 Pod 名字。
  • 如果只是把name加入podsToDelete,而没有修改replicas的话,删完之后会再扩一个pod 。
[root@mast01 CloneSet]# kubectl apply -f 3.yaml
cloneset.apps.kruise.io/demo configured

[root@mast01 CloneSet]# kubectl get pod
NAME         READY   STATUS   RESTARTS   AGE
demo-c2gsl   1/1     Running   0         7m21s
demo-s2rhp   1/1     Running   0         40m
demo-slfrq   1/1     Running   0         40m
demo-tsgqn   1/1     Running   0         39m

10、原地升级

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
name: demo
namespace: default
spec:
minReadySeconds: 30
updateStrategy:
  type: InPlaceIfPossible  #修改1:指定为最大限度的原地升级的方式
scaleStrategy:
  maxUnavailable: 1
replicas: 4
selector:
  matchLabels:
    app: cs
template:
  metadata:
    labels:
      app: cs
  spec:
    containers:
    - name: nginx
      image: nginx:1.7.9 #修改2:把镜像版本替换了
      imagePullPolicy: IfNotPresent
      ports:
      - containerPort: 80

原地升级最常见的几种策略

  • ReCreate : 更新时 Pod 将被删除,然后重新创建新的 Pod 实例。这个过程会导致 Pod 的 IP 地址和其他相关属性发生变化。使用场景:常见的无状态服务或不需要原地更新的场景。
  • InPlaceIfPossible : 系统会尽量在不重启 Pod 的前提下进行升级。如果无法原地更新(如某些字段更新需要重建 Pod),则会删除并重新创建 Pod。使用场景:大多数场景下的推荐策略,尤其是有状态服务,减少重建 Pod 的开销。
  • InPlaceOnly : 强制要求所有更新都必须通过原地升级进行,不能删除和重建 Pod。如果某些字段不支持原地更新,则更新会失败。使用场景:要求严格控制 Pod 不被重新创建的场景,例如需要保持 Pod 的 IP 地址或其他属性不变的情况。
[root@mast01 CloneSet]# kubectl apply -f 4.yaml
cloneset.apps.kruise.io/demo configured

[root@mast01 CloneSet]# kubectl get po
NAME         READY   STATUS   RESTARTS       AGE
demo-c2gsl   1/1     Running   1 (8m25s ago)   30m
demo-s2rhp   1/1     Running   1 (6m30s ago)   63m
demo-slfrq   1/1     Running   1 (5m57s ago)   63m
demo-tsgqn   1/1     Running   1 (7m32s ago)   62m

[root@mast01 CloneSet]# kubectl get po demo-c2gsl -oyaml|grep image
  apps.kruise.io/inplace-update-state: '{"revision":"demo-7cb9c88699","updateTimestamp":"2024-09-26T08:04:18Z","lastContainerStatuses":{"nginx":{"imageID":"docker-pullable://nginx@sha256:a5127daff3d6f4606be3100a252419bfa84fd6ee5cd74d0feaca1a5068f97dcf"}},"containerBatchesRecord":[{"timestamp":"2024-09-26T08:04:18Z","containers":["nginx"]}]}'
 - image: nginx:1.7.9
  imagePullPolicy: IfNotPresent
  image: nginx:1.7.9
  imageID: docker-pullable://nginx@sha256:e3456c851a152494c3e4ff5fcc26f240206abac0c9d794affb40e0714846c451

11、灰度

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
name: demo
namespace: default
spec:
minReadySeconds: 30
updateStrategy:
  type: InPlaceIfPossible
  partition: 2
scaleStrategy:
  maxUnavailable: 1
replicas: 4
selector:
  matchLabels:
    app: cs
template:
  metadata:
    labels:
      app: cs
  spec:
    containers:
    - name: nginx
      image: nginx:latest #修改2:把镜像版本替换了
      imagePullPolicy: IfNotPresent
      ports:
      - containerPort: 80

灰度发布常用的两个参数

  • partition: 表示最开始会保留 几 个旧版本 Pod,另外 几 个 Pod 会被更新为新版本。
  • **maxUnavailable:**限制更新时最多只有 1几个 Pod 会处于不可用状态,保证更新过程中服务的稳定性。
[root@mast01 CloneSet]# kubectl apply -f 5.yaml
cloneset.apps.kruise.io/demo configured

[root@mast01 CloneSet]# kubectl get po
NAME         READY   STATUS   RESTARTS       AGE
demo-c2gsl   1/1     Running   1 (9m27s ago)   31m
demo-s2rhp   1/1     Running   2 (10s ago)     64m
demo-slfrq   1/1     Running   2 (88s ago)     64m
demo-tsgqn   1/1     Running   1 (8m34s ago)   63m
[root@mast01 CloneSet]# kubectl get po demo-slfrq -oyaml|grep image
  apps.kruise.io/inplace-update-state: '{"revision":"demo-7c4d79f5bc","updateTimestamp":"2024-09-26T08:12:17Z","lastContainerStatuses":{"nginx":{"imageID":"docker-pullable://nginx@sha256:e3456c851a152494c3e4ff5fcc26f240206abac0c9d794affb40e0714846c451"}},"containerBatchesRecord":[{"timestamp":"2024-09-26T08:12:17Z","containers":["nginx"]}]}'
 - image: nginx:latest
  imagePullPolicy: IfNotPresent
  image: nginx:latest
  imageID: docker-pullable://nginx@sha256:04ba374043ccd2fc5c593885c0eacddebabd5ca375f9323666f28dfd5a9710e3

微信打赏:

支付宝打赏: