前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >使用 Open Kruise 升级指定 Pod

使用 Open Kruise 升级指定 Pod

作者头像
崔秀龙
发布2023-08-28 15:34:46
2040
发布2023-08-28 15:34:46
举报
文章被收录于专栏:伪架构师伪架构师

最近在和同事讨论一个非典型的云原生应用更新场景。目标应用是一系列有状态的 Statefulset,其中的实例用类似投票的机制对外提供服务,这意味着始终有一部分实例是处于待命状态的。由此情况,这个应用在虚拟化时期,会提供一个仲裁服务,每次对实例进行更新时,首先要从这个仲裁服务查出可以更新的摸鱼实例,然后仅仅对这些空闲实例进行升级。

这种行为在虚拟化场景是行之有效的,到了 Kubernetes 环境就难搞了,Statefulset 的 Partition 能力官网说明如下:

RollingUpdate更新策略可以通过指定.spec.updateStrategy.rollingUpdate.partition来进行分区。如果指定了分区,当StatefulSet的.spec.template被更新时,所有序数大于或等于分区的Pod将被更新。所有序号小于分区的Pod将不会被更新,即使它们被删除,也会以以前的版本重新创建。如果一个 StatefulSet 的 .spec.updateStrategy.rollingUpdate.partition 大于其 .spec.replicas,对其 .spec.template 的更新将不会被传播到其 Pods。在大多数情况下,你不需要使用分区,但如果你想进行阶段性更新、推出金丝雀或执行分阶段推出,它们是有用的。

如此看来,分区更新能力会保护分区序号以内的连续的 Pod 保持原样,和需求中提到的随时分配情况还是颇有不同的。在我看来,更好的做法是效仿 KubeDB 系列的产品,自行控制更新行为——当然,对甲方提出这种非分要求是不合适的。既然这个需求如此的不云原生,那么先看看 Open Kruise 总不会错的。经过对其文档的阅读,有两个发现:

  • Partition: 和 Statefulset 不同,它的 Partition 可以使用整数和百分比两种方式
  • 可以使用标签的方式指定升级时候的优先级。

如果这两个方法能够同时生效,这个需求就有望完成了,设计要点如下:

  1. 从仲裁服务中,获得工作和空闲副本的情况
  2. 刷新 Statefulset 中的 Pod 标签,用于指示当前工作状态。
  3. 设置 Partition,将 Partition 数量设置为等于工作中的副本数量进行保护。

由此可以编写一个 Advanced Statefulset,示例如下:

代码语言:javascript
复制
apiVersion: apps.kruise.io/v1beta1
kind: StatefulSet
metadata:
  name: sample
spec:
  replicas: 5
  serviceName: fake-service
  selector:
    matchLabels:
      app: sample
  template:
    metadata:
      labels:
        app: sample
        working: "false"
    spec:
      readinessGates:
      - conditionType: InPlaceUpdateReady
      containers:
      - name: main
        image: alpine:3.18.2
        command: ['sleep', '3600']
  podManagementPolicy: Parallel
  updateStrategy:
    rollingUpdate:
      partition: 3
      unorderedUpdate:
        priorityStrategy:
          weightPriority:
          - weight: 30
            matchSelector:
              matchLabels:
                working: "true"
          - weight: 50
            matchSelector:
              matchLabels:
                working: "false"

这里的定义有几个需要关注的点:

  1. Pod 模版中加入了 working 标签,用于指示每个 Pod 当前的工作状态。
  2. unorderedUpdate.priorityStrategy.weightPriority: 这里指定了非工作状态的 Pod 会有更高优先级。
  3. partition 设置为 3: 这里我们假设工作中的副本有 3 个。
  4. 这里镜像使用 alpine:3.18.2,作为我们的工作负载。

安装 Open Kruise

传统的 Helm 三部曲:

  • helm repo add openkruise https://openkruise.github.io/charts/
  • helm update
  • helm install kruise openkruise/kruise --version 1.4.0

部署应用

部署前面的 Advanced Statefulset:

代码语言:javascript
复制
$ kubectl apply -f statefulset.yaml
statefulset.apps.kruise.io/sample created

查看当前工作负载的镜像:

代码语言:javascript
复制
$  kubectl images
[Summary]: 1 namespaces, 5 pods, 5 containers and 1 different images
+----------+-----------+---------------+
|   Pod    | Container |     Image     |
+----------+-----------+---------------+
| sample-0 | main      | alpine:3.18.2 |
+----------+           +               +
| sample-1 |           |               |
+----------+           +               +
| sample-2 |           |               |
+----------+           +               +
| sample-3 |           |               |
+----------+           +               +
| sample-4 |           |               |
+----------+-----------+---------------+

可以看到五个副本用的都是 alpine:3.18.2

标识工作负载

我们使用标签,把第 024 三个 Pod 的 working 标签设置为 true

代码语言:javascript
复制
$ kubectl label pods sample-0 working=true --overwrite
pod/sample-0 labeled
$ kubectl label pods sample-2 working=true --overwrite
pod/sample-2 labeled
$ kubectl label pods sample-4 working=true --overwrite
pod/sample-4 labeled

更新镜像

替换镜像为 alpine:3.18.0,然后 apply

代码语言:javascript
复制
$ kubectl apply -f statefulset.yaml
statefulset.apps.kruise.io/sample configured

验证结果

查看 Pod 状态:

代码语言:javascript
复制
$ kubectl get pods
NAME       READY   STATUS    RESTARTS   AGE
sample-0   1/1     Running   0          9m27s
sample-1   1/1     Running   0          5s
sample-2   1/1     Running   0          9m27s
sample-3   1/1     Running   0          39s
sample-4   1/1     Running   0          9m27s

可以看到,workingfalse 的 Pod 已经被更新。

查询一下所用的镜像:

代码语言:javascript
复制
$ 1 namespaces, 5 pods, 5 containers and 2 different images
+----------+-----------+---------------+
|   Pod    | Container |     Image     |
+----------+-----------+---------------+
| sample-0 | main      | alpine:3.18.2 |
+----------+           +---------------+
| sample-1 |           | alpine:3.18.0 |
+----------+           +---------------+
| sample-2 |           | alpine:3.18.2 |
+----------+           +---------------+
| sample-3 |           | alpine:3.18.0 |
+----------+           +---------------+
| sample-4 |           | alpine:3.18.2 |
+----------+-----------+---------------+

这里就看得出,工作状态的 Pod 保持原样,而非工作状态的 Pod 已经被更新。

继续推动

如果此时再次更新,应该让更新后的实例进入工作状态,把原有工作实例设为空闲,并减小 Partition 数量,所以把 1 号 Pod 设置为工作状态,同时把 4 号 Pod 设置为空闲状态,最后把分区数量缩减为 2,看看会发生什么:

代码语言:javascript
复制
$ kubectl images
[Summary]: 1 namespaces, 5 pods, 5 containers and 2 different images
+----------+-----------+---------------+
|   Pod    | Container |     Image     |
+----------+-----------+---------------+
| sample-0 | main      | alpine:3.18.2 |
+----------+           +---------------+
| sample-1 |           | alpine:3.18.0 |
+----------+           +---------------+
| sample-2 |           | alpine:3.18.2 |
+----------+           +---------------+
| sample-3 |           | alpine:3.18.0 |
+----------+           +               +
| sample-4 |           |               |
+----------+-----------+---------------+

这里看到,只有 sample-0sample-2 还在使用 3.18.2 版本,其它副本都成功变更为 3.18.0 的镜像。

其实不难看出,要把上述功能实现到自动化流程里,还是需要编写一些控制逻辑的——以及引进一个三方软件的成本,活罪难逃不是?

本文参与 腾讯云自媒体分享计划,分享自微信公众号。
原始发表:2023-06-17,如有侵权请联系 cloudcommunity@tencent.com 删除

本文分享自 伪架构师 微信公众号,前往查看

如有侵权,请联系 cloudcommunity@tencent.com 删除。

本文参与 腾讯云自媒体分享计划  ,欢迎热爱写作的你一起参与!

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 安装 Open Kruise
  • 部署应用
  • 标识工作负载
  • 更新镜像
  • 验证结果
  • 继续推动
领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档