• OpenKruise-CloneSet


    一、Yaml模板

    CloneSet 控制器提供了高效管理无状态应用的能力,它可以对标原生的 Deployment,但 CloneSet 提供了很多增强功能。

    按照 Kruise 的命名规范,CloneSet 是一个直接管理 Pod 的 Set 类型 workload。 一个简单的 CloneSet yaml 文件如下:

    1. apiVersion: apps.kruise.io/v1alpha1
    2. kind: CloneSet
    3. metadata:
    4. labels:
    5. app: sample
    6. name: sample
    7. spec:
    8. replicas: 5
    9. selector:
    10. matchLabels:
    11. app: sample
    12. template:
    13. metadata:
    14. labels:
    15. app: sample
    16. spec:
    17. containers:
    18. - name: nginx
    19. image: nginx:alpine

    二、扩缩容功能

    2.1 支持 PVC 模板

    CloneSet 允许用户配置 PVC 模板 volumeClaimTemplates,用来给每个 Pod 生成独享的 PVC,这是 Deployment 所不支持的。 如果用户没有指定这个模板,CloneSet 会创建不带 PVC 的 Pod。

    一些注意点:

    • 每个被自动创建的 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 会持续使用。

    以下是一个带有 PVC 模板的例子:

    1. apiVersion: apps.kruise.io/v1alpha1
    2. kind: CloneSet
    3. metadata:
    4. labels:
    5. app: sample
    6. name: sample-data
    7. spec:
    8. replicas: 2
    9. selector:
    10. matchLabels:
    11. app: sample
    12. template:
    13. metadata:
    14. labels:
    15. app: sample
    16. spec:
    17. containers:
    18. - name: nginx
    19. image: nginx
    20. volumeMounts:
    21. - name: data-vol
    22. mountPath: /usr/share/nginx/html
    23. volumeClaimTemplates:
    24. - metadata:
    25. name: data-vol
    26. spec:
    27. storageClassName: "nfs-storage"
    28. accessModes: [ "ReadWriteOnce" ]
    29. resources:
    30. requests:
    31. storage: 10Mi

    这样就实现了动态创建PVC

    1. [root@k8s-master][15:45:22][OK] ~/open-kruise
    2. #kubectl get clone
    3. NAME DESIRED UPDATED UPDATED_READY READY TOTAL AGE
    4. sample-data 2 2 2 2 2 16s
    5. [root@k8s-master][15:45:25][OK] ~/open-kruise
    6. #kubectl get pod
    7. NAME READY STATUS RESTARTS AGE
    8. sample-data-gfrkl 1/1 Running 0 21s
    9. sample-data-pp4zt 1/1 Running 0 21s
    10. [root@k8s-master][15:45:30][OK] ~/open-kruise
    11. #kubectl get pvc,pv
    12. NAME STATUS VOLUME CAPACITY ACCESS MODES STORAGECLASS AGE
    13. persistentvolumeclaim/data-vol-sample-data-gfrkl Bound pvc-eaca0822-9621-4cf7-97e9-ebbf8d70f34b 10Mi RWO nfs-storage 25s
    14. persistentvolumeclaim/data-vol-sample-data-pp4zt Bound pvc-dfb31f15-465a-4533-9802-bc4722d66ac4 10Mi RWO nfs-storage 25s
    15. NAME CAPACITY ACCESS MODES RECLAIM POLICY STATUS CLAIM STORAGECLASS REASON AGE
    16. persistentvolume/pvc-dfb31f15-465a-4533-9802-bc4722d66ac4 10Mi RWO Delete Bound web/data-vol-sample-data-pp4zt nfs-storage 25s
    17. persistentvolume/pvc-eaca0822-9621-4cf7-97e9-ebbf8d70f34b 10Mi RWO Delete Bound web/data-vol-sample-data-gfrkl nfs-storage 25s

    2.2 指定 Pod 缩容

    当一个 CloneSet 被缩容时,有时候用户需要指定一些 Pod 来删除。这对于 StatefulSet 或者 Deployment 来说是无法实现的,因为 StatefulSet 要根据序号来删除 Pod,而 Deployment/ReplicaSet 目前只能根据控制器里定义的排序来删除。

    CloneSet 允许用户在缩小 replicas 数量的同时,指定想要删除的 Pod 名字。参考下面这个例子:

    1. apiVersion: apps.kruise.io/v1alpha1
    2. kind: CloneSet
    3. spec:
    4. # ...
    5. replicas: 2
    6. scaleStrategy:
    7. podsToDelete:
    8. - sample-data-gfrkl

    指定容器缩容例子:

    1. #查看当前活跃的容器
    2. [root@k8s-master][15:49:30][OK] ~/open-kruise
    3. #kubectl get po
    4. NAME READY STATUS RESTARTS AGE
    5. sample-data-89vp6 1/1 Running 0 3m28s
    6. sample-data-xcqn2 1/1 Running 0 35s
    7. #修改clone配置
    8. 添加如下:
    9. replicas: 1 #将副本数由2缩容到1
    10. scaleStrategy:
    11. podsToDelete:
    12. - sample-data-xcqn2 #指定容器名进行缩容
    13. #再次查看
    14. [root@k8s-master][16:04:22][OK] /etc/kubernetes/manifests
    15. #kubectl get po
    16. NAME READY STATUS RESTARTS AGE
    17. sample-data-89vp6 1/1 Running 0 4m

    当控制器收到上面这个 CloneSet 更新之后,会确保 replicas 数量为 4。如果 podsToDelete 列表里写了一些 Pod 名字,控制器会优先删除这些 Pod。 对于已经被删除的 Pod,控制器会自动从 podsToDelete 列表中清理掉。

    如果你只把 Pod 名字加到 podsToDelete,但没有修改 replicas 数量,那么控制器会先把指定的 Pod 删掉,然后再扩一个新的 Pod。 另一种直接删除 Pod 的方式是在要删除的 Pod 上打 apps.kruise.io/specified-delete: true 标签。

    相比于手动直接删除 Pod,使用 podsToDelete 或 apps.kruise.io/specified-delete: true 方式会有 CloneSet 的 maxUnavailable/maxSurge 来保护删除, 并且会触发 PreparingDelete 生命周期 hook (见下文)。

    2.3 缩容顺序

    1. 未调度 < 已调度
    2. PodPending < PodUnknown < PodRunning
    3. Not ready < ready
    4. 较小 pod-deletion cost < 较大 pod-deletion cost
    5. 较大打散权重 < 较小
    6. 处于 Ready 时间较短 < 较长
    7. 容器重启次数较多 < 较少
    8. 创建时间较短 < 较长

    2.3.1 Pod deletion cost

    FEATURE STATE: Kruise v0.9.0

    controller.kubernetes.io/pod-deletion-cost 是从 Kubernetes 1.21 版本后加入的 annotation,Deployment/ReplicaSet 在缩容时会参考这个 cost 数值来排序。 CloneSet 从 Kruise v0.9.0 版本后也同样支持了这个功能。

    用户可以把这个 annotation 配置到 pod 上,值的范围在 [-2147483647, 2147483647]。 它表示这个 pod 相较于同个 CloneSet 下其他 pod 的 "删除代价",代价越小的 pod 删除优先级相对越高。 没有设置这个 annotation 的 pod 默认 deletion cost 是 0。

    2.3.2 Deletion by Spread Constraints

    FEATURE STATE: Kruise v0.10.0

    原始 proposal(设计文档)在这里

    目前,CloneSet 支持 按同节点打散 和 按 pod topolocy spread constraints 打散

    如果在 CloneSet template 中存在 Pod Topology Spread Constraints 规则定义,则 controller 在这个 CloneSet 缩容的时候会根据 spread constraints 规则来所打散并选择要删除的 pod。 否则,controller 默认情况下是按同节点打散来选择要缩容的 pod。

    2.4 短 hash

    默认情况下,CloneSet 在 Pod label 中设置的 controller-revision-hash 值为 ControllerRevision 的完整名字,比如

    1. apiVersion: v1
    2. kind: Pod
    3. metadata:
    4. labels:
    5. controller-revision-hash: demo-cloneset-956df7994

    它是通过 CloneSet 名字和 ControllerRevision hash 值拼接而成。 通常 hash 值长度为 8~10 个字符,而 Kubernetes 中的 label 值不能超过 63 个字符。 因此 CloneSet 的名字一般是不能超过 52 个字符的。

    因此 CloneSetShortHash 这个新的 feature-gate 被引入。 如果它被打开,CloneSet 会将 controller-revision-hash 的值只设置为 hash 值,比如 956df7994,因此 CloneSet 名字则不会有任何限制了。

    不用担心,即使打开了 CloneSetShortHash,CloneSet 仍然会识别和管理过去存量的 revision label 为完整格式的 Pod。

    从 Kruise v1.1.0 版本开始,CloneSet 还会给 Pod 中加入另一个 pod-template-hash 标签,它永远是短 hash 的形式。

    三、扩容功能

    3.1 流式扩容

    CloneSet 扩容时可以指定 ScaleStrategy.MaxUnavailable 来限制扩容的步长,以达到服务应用影响最小化的目的。 它可以设置为一个绝对值或者百分比,如果不填,则 Kruise 会设置为默认值为 nil,即表示不设限制。

    该字段可以配合 Spec.MinReadySeconds 字段使用, 例如:

    1. apiVersion: apps.kruise.io/v1alpha1
    2. kind: CloneSet
    3. spec:
    4. # ...
    5. minReadySeconds: 60
    6. scaleStrategy:
    7. maxUnavailable: 1

    上述配置能达到的效果是:在扩容时,只有当上一个扩容出的 Pod 已经 Ready 超过一分钟后,CloneSet 才会执行创建下一个 Pod 的操作。

    四、升级功能

    4.1 升级类型

    CloneSet 提供了 3 种升级方式,默认为 ReCreate

    • ReCreate: 控制器会删除旧 Pod 和它的 PVC,然后用新版本重新创建出来。
    • InPlaceIfPossible: 控制器会优先尝试原地升级 Pod,如果不行再采用重建升级。具体参考下方阅读文档。
    • InPlaceOnly: 控制器只允许采用原地升级。因此,用户只能修改上一条中的限制字段,如果尝试修改其他字段会被 Kruise 拒绝。

    我们还在原地升级中提供了 graceful period 选项,作为优雅原地升级的策略。用户如果配置了 gracePeriodSeconds 这个字段,控制器在原地升级的过程中会先把 Pod status 改为 not-ready,然后等一段时间(gracePeriodSeconds),最后再去修改 Pod spec 中的镜像版本。 这样,就为 endpoints-controller 这些控制器留出了充足的时间来将 Pod 从 endpoints 端点列表中去除。

    4.2 Template 和 revision

    spec.template 中定义了当前 CloneSet 中最新的 Pod 模板。 控制器会为每次更新过的 spec.template 计算一个 revision hash 值,比如针对开头的 CloneSet 例子, 控制器会为 template 计算出 revision hash 为 sample-744d4796cc 并上报到 CloneSet status 中。

    1. apiVersion: apps.kruise.io/v1alpha1
    2. kind: CloneSet
    3. metadata:
    4. generation: 1
    5. # ...
    6. spec:
    7. replicas: 5
    8. # ...
    9. status:
    10. observedGeneration: 1
    11. readyReplicas: 5
    12. replicas: 5
    13. currentRevision: sample-d4d4fb5bd
    14. updateRevision: sample-d4d4fb5bd
    15. updatedReadyReplicas: 5
    16. updatedReplicas: 5
    17. # ...

    这里是对 CloneSet status 中的字段说明:

    • status.replicas: Pod 总数
    • status.readyReplicasready Pod 数量
    • status.availableReplicasready and available Pod 数量 (满足 minReadySeconds, 且 lifecycle state 为 Normal)
    • status.currentRevision: 最近一次全量 Pod 推平版本的 revision hash 值
    • status.updateRevision: 最新版本的 revision hash 值
    • status.updatedReplicas: 最新版本的 Pod 数量
    • status.updatedReadyReplicas: 最新版本的 ready Pod 数量 FEATURE STATE: Kruise v1.2.0
    • status.expectedUpdatedReplicas: 需要升级到最新版本 Pod 的数量(包含已经升级的数量),该字段根据用户当前设置的 .spec.updateStrategy.partition 字段计算得到。

    4.3 Partition 分批灰度

    Partition 的语义是 保留旧版本 Pod 的数量或百分比,默认为 0。这里的 partition 不表示任何 order 序号。

    如果在发布过程中设置了 partition:

    • 如果是数字,控制器会将 (replicas - partition) 数量的 Pod 更新到最新版本。
    • 如果是百分比,控制器会将 (replicas * (100% - partition)) 数量的 Pod 更新到最新版本。

    FEATURE STATE: Kruise v1.2.0

    • 如果 partition 是百分比, 并且满足 partition < 100% && replicas > 1 , CloneSet 会保证 至少有一个 Pod 会被升级到最新版本
    • 用户可以使用 .status.updatedReplicas >= .status.ExpectedUpdatedReplicas 条件,来判断在当前 partition 字段的限制下,CloneSet 是否已经完成了预期数量 Pod 的版本升级。

    比如,我们将 CloneSet 例子的 image 更新为 nginx:mainline 并且设置 partition=3。过了一会,查到的 CloneSet 如下:

    1. apiVersion: apps.kruise.io/v1alpha1
    2. kind: CloneSet
    3. metadata:
    4. # ...
    5. generation: 2
    6. spec:
    7. replicas: 5
    8. template:
    9. metadata:
    10. labels:
    11. app: sample
    12. spec:
    13. containers:
    14. - image: nginx:mainline
    15. imagePullPolicy: Always
    16. name: nginx
    17. updateStrategy:
    18. partition: 3
    19. # ...
    20. status:
    21. observedGeneration: 2
    22. readyReplicas: 5
    23. replicas: 5
    24. currentRevision: sample-d4d4fb5bd
    25. updateRevision: sample-56dfb978d4
    26. updatedReadyReplicas: 2
    27. updatedReplicas: 2

    注意 status.updateRevision 已经更新为 sample-56dfb978d4 新的值。 由于我们设置了 partition=3,控制器只升级了 2 个 Pod。

    1. $ kubectl get pod -L controller-revision-hash
    2. NAME READY STATUS RESTARTS AGE CONTROLLER-REVISION-HASH
    3. sample-chvnr 1/1 Running 0 6m46s sample-d4d4fb5bd
    4. sample-j6c4s 1/1 Running 0 6m46s sample-d4d4fb5bd
    5. sample-ns85c 1/1 Running 0 6m46s sample-d4d4fb5bd
    6. sample-jnjdp 1/1 Running 0 10s sample-56dfb978d4
    7. sample-qqglp 1/1 Running 0 18s sample-56dfb978d4

    4.4 通过 partition 回滚

    默认情况下,partition 只控制 Pod 更新到 status.updateRevision 新版本。 也就是说以上面这个 CloneSet 来看,当 partition 5 -> 3 时,CloneSet 会升级 2 个 Pod 到 status.updateRevision 版本。 而当把 partition 3 -> 5 修改回去时,CloneSet 不会做任何事情。

    但是如果你启用了 CloneSetPartitionRollback 这个 feature-gate, 上面这个场景下 CloneSet 会把 2 个 status.updateRevision 版本的 Pod 重新回滚为 status.currentRevision 版本。

    4.5 MaxUnavailable 最大不可用数量

    MaxUnavailable 是 CloneSet 限制下属最多不可用的 Pod 数量。 它可以设置为一个绝对值或者百分比,如果不填 Kruise 会设置为默认值 20%

    1. apiVersion: apps.kruise.io/v1alpha1
    2. kind: CloneSet
    3. spec:
    4. # ...
    5. updateStrategy:
    6. maxUnavailable: 20%

    从 Kruise v0.9.0 版本开始,maxUnavailable 不仅会保护发布,也会对 Pod 指定删除生效。

    也就是说用户通过 podsToDelete 或 apps.kruise.io/specified-delete: true 来指定一个 Pod 期望删除, CloneSet 只会在当前不可用 Pod 数量(相对于 replicas 总数)小于 maxUnavailable 的时候才执行删除。

    4.6 MaxSurge 最大弹性数量

    MaxSurge 是 CloneSet 控制最多能扩出来超过 replicas 的 Pod 数量。 它可以设置为一个绝对值或者百分比,如果不填 Kruise 会设置为默认值 0

    如果发布的时候设置了 maxSurge,控制器会先多扩出来 maxSurge 数量的 Pod(此时 Pod 总数为 (replicas+maxSurge)),然后再开始发布存量的 Pod。 然后,当新版本 Pod 数量已经满足 partition 要求之后,控制器会再把多余的 maxSurge 数量的 Pod 删除掉,保证最终的 Pod 数量符合 replicas

    要说明的是,maxSurge 不允许配合 InPlaceOnly 更新模式使用。 另外,如果是与 InPlaceIfPossible 策略配合使用,控制器会先扩出来 maxSurge 数量的 Pod,再对存量 Pod 做原地升级。

    1. apiVersion: apps.kruise.io/v1alpha1
    2. kind: CloneSet
    3. spec:
    4. # ...
    5. updateStrategy:
    6. maxSurge: 3

    从 Kruise v0.9.0 版本开始,maxSurge 不仅会保护发布,也会对 Pod 指定删除生效。

    也就是说用户通过 podsToDelete 或 apps.kruise.io/specified-delete: true 来指定一个 Pod 期望删除, CloneSet 有可能会先创建一个新 Pod、等待它 ready 之后、再删除旧 Pod。这取决于当时的 maxUnavailable 和实际不可用 Pod 数量。

    比如:

    • 对于一个 CloneSet maxUnavailable=2, maxSurge=1 且有一个 pod-a 处于不可用状态, 如果你对另一个 pod-b 打标 apps.kruise.io/specified-delete: true 或将它的名字加入 podsToDelete, 那么 CloneSet 会立即删除它,然后创建一个新 Pod。
    • 对于一个 CloneSet maxUnavailable=1, maxSurge=1 且有一个 pod-a 处于不可用状态, 如果你对另一个 pod-b 打标 apps.kruise.io/specified-delete: true 或将它的名字加入 podsToDelete, 那么 CloneSet 会先新建一个 Pod、等待它 ready,最后再删除 pod-b
    • 对于一个 CloneSet maxUnavailable=1, maxSurge=1 且有一个 pod-a 处于不可用状态, 如果你对这个 pod-a 打标 apps.kruise.io/specified-delete: true 或将它的名字加入 podsToDelete, 那么 CloneSet 会立即删除它,然后创建一个新 Pod。
    • ...

    4.7 升级顺序

    当控制器选择 Pod 做升级时,默认是有一套根据 Pod phase/conditions 的排序逻辑: unscheduled < scheduled, pending < unknown < running, not-ready < ready。 在此之外,CloneSet 也提供了增强的 priority(优先级) 和 scatter(打散) 策略来允许用户自定义发布顺序。

    4.7.1 优先级策略

    这个策略定义了控制器计算 Pod 发布优先级的规则,所有需要更新的 Pod 都会通过这个优先级规则计算后排序。 目前 priority 可以通过 weight(权重) 和 order(序号) 两种方式来指定。

    • weight: Pod 优先级是由所有 weights 列表中的 term 来计算 match selector 得出。如下:
    1. apiVersion: apps.kruise.io/v1alpha1
    2. kind: CloneSet
    3. spec:
    4. # ...
    5. updateStrategy:
    6. priorityStrategy:
    7. weightPriority:
    8. - weight: 50
    9. matchSelector:
    10. matchLabels:
    11. test-key: foo
    12. - weight: 30
    13. matchSelector:
    14. matchLabels:
    15. test-key: bar
    • order: Pod 优先级是由 orderKey 的 value 决定,这里要求对应的 value 的结尾能解析为 int 值。比如 value "5" 的优先级是 5,value "sts-10" 的优先级是 10。
    1. apiVersion: apps.kruise.io/v1alpha1
    2. kind: CloneSet
    3. spec:
    4. # ...
    5. updateStrategy:
    6. priorityStrategy:
    7. orderPriority:
    8. - orderedKey: some-label-key

    4.7.2 打散策略

    这个策略定义了如何将一类 Pod 打散到整个发布过程中。 比如,针对一个 replica=10 的 CloneSet,我们在 3 个 Pod 中添加了 foo=bar 标签、并设置对应的 scatter 策略,那么在发布的时候这 3 个 Pod 会排在第 1、6、10 个发布。

    1. apiVersion: apps.kruise.io/v1alpha1
    2. kind: CloneSet
    3. spec:
    4. # ...
    5. updateStrategy:
    6. scatterStrategy:
    7. - key: foo
    8. value: bar

    注意:

    • 尽管 priority 和 scatter 策略可以一起设置,但我们强烈推荐同时只用其中一个。
    • 如果使用了 scatter 策略,我们强烈建议只配置一个 term (key-value)。否则,实际的打散发布顺序可能会不太好理解。

    最后要说明的是,使用上述发布顺序策略都要求对特定一些 Pod 打标,这是在 CloneSet 中没有提供的。

    4.8 发布暂停

    用户可以通过设置 paused 为 true 暂停发布,不过控制器还是会做 replicas 数量管理:

    1. apiVersion: apps.kruise.io/v1alpha1
    2. kind: CloneSet
    3. spec:
    4. # ...
    5. updateStrategy:
    6. paused: true

    4.9 原地升级自动预热

    如果你在安装或升级 Kruise 的时候启用了 PreDownloadImageForInPlaceUpdate feature-gate, CloneSet 控制器会自动在所有旧版本 pod 所在 node 节点上预热你正在灰度发布的新版本镜像。 这对于应用发布加速很有帮助。

    默认情况下 CloneSet 每个新镜像预热时的并发度都是 1,也就是一个个节点拉镜像。 如果需要调整,你可以通过 apps.kruise.io/image-predownload-parallelism annotation 来设置并发度。

    另外从 Kruise v1.1.0 开始,你可以使用 apps.kruise.io/image-predownload-min-updated-ready-pods 来控制在少量新版本 Pod 已经升级成功之后再执行镜像预热。它的值可能是绝对值数字或是百分比。

    1. apiVersion: apps.kruise.io/v1alpha1
    2. kind: CloneSet
    3. metadata:
    4. annotations:
    5. apps.kruise.io/image-predownload-parallelism: "10"
    6. apps.kruise.io/image-predownload-min-updated-ready-pods: "3"

    注意,为了避免大部分不必要的镜像拉取,目前只针对 replicas > 3 的 CloneSet 做自动预热。

    五、生命周期钩子

    每个 CloneSet 管理的 Pod 会有明确所处的状态,在 Pod label 中的 lifecycle.apps.kruise.io/state 标记:

    • Normal:正常状态
    • PreparingUpdate:准备原地升级
    • Updating:原地升级中
    • Updated:原地升级完成
    • PreparingDelete:准备删除

    而生命周期钩子,则是通过在上述状态流转中卡点,来实现原地升级前后、删除前的自定义操作(比如开关流量、告警等)。

    1. type LifecycleStateType string
    2. // Lifecycle contains the hooks for Pod lifecycle.
    3. type Lifecycle struct
    4. // PreDelete is the hook before Pod to be deleted.
    5. PreDelete *LifecycleHook `json:"preDelete,omitempty"`
    6. // InPlaceUpdate is the hook before Pod to update and after Pod has been updated.
    7. InPlaceUpdate *LifecycleHook `json:"inPlaceUpdate,omitempty"`
    8. }
    9. type LifecycleHook struct {
    10. LabelsHandler map[string]string `json:"labelsHandler,omitempty"`
    11. FinalizersHandler []string `json:"finalizersHandler,omitempty"`
    12. /********************** FEATURE STATE: 1.2.0 ************************/
    13. // MarkPodNotReady = true means:
    14. // - Pod will be set to 'NotReady' at preparingDelete/preparingUpdate state.
    15. // - Pod will be restored to 'Ready' at Updated state if it was set to 'NotReady' at preparingUpdate state.
    16. // Default to false.
    17. MarkPodNotReady bool `json:"markPodNotReady,omitempty"`
    18. /*********************************************************************/
    19. }

    示例:

    1. apiVersion: apps.kruise.io/v1alpha1
    2. kind: CloneSet
    3. spec:
    4. # 通过 finalizer 定义 hook
    5. lifecycle:
    6. preDelete:
    7. finalizersHandler:
    8. - example.io/unready-blocker
    9. inPlaceUpdate:
    10. finalizersHandler:
    11. - example.io/unready-blocker
    12. # 或者也可以通过 label 定义
    13. lifecycle:
    14. inPlaceUpdate:
    15. labelsHandler:
    16. example.io/block-unready: "true"

    5.1 升级/删除 Pod 前将其置为 NotReady

    FEATURE STATE: Kruise v1.2.0

    1. lifecycle:
    2. preDelete:
    3. markPodNotReady: true
    4. finalizersHandler:
    5. - example.io/unready-blocker
    6. inPlaceUpdate:
    7. markPodNotReady: true
    8. finalizersHandler:
    9. - example.io/unready-blocker
    • 如果设置 preDelete.markPodNotReady=true:
      • Kruise 将会在 Pod 进入 PreparingDelete 状态时,将 KruisePodReady 这个 Pod Condition 设置为 False, Pod 将变为 NotReady
    • 如果设置 inPlaceUpdate.markPodNotReady=true:
      • Kruise 将会在 Pod 进入 PreparingUpdate 状态时,将 KruisePodReady 这个 Pod Condition 设置为 False, Pod 将变为 NotReady
      • Kruise 将会尝试将 KruisePodReady 这个 Pod Condition 设置回 True

    用户可以利用这一特性,在容器真正被停止之前将 Pod 上的流量先行排除,防止流量损失。

    注意: 该特性仅在 Pod 被注入 KruisePodReady 这个 ReadinessGate 时生效。

    5.2 流转示意

    • 当 CloneSet 删除一个 Pod(包括正常缩容和重建升级)时:
      • 如果没有定义 lifecycle hook 或者 Pod 不符合 preDelete 条件,则直接删除
      • 否则,先只将 Pod 状态改为 PreparingDelete。等用户 controller 完成任务去掉 label/finalizer、Pod 不符合 preDelete 条件后,kruise 才执行 Pod 删除
      • 注意:PreparingDelete 状态的 Pod 处于删除阶段,不会被升级
    • 当 CloneSet 原地升级一个 Pod 时:
      • 升级之前,如果定义了 lifecycle hook 且 Pod 符合 inPlaceUpdate 条件,则将 Pod 状态改为 PreparingUpdate
      • 等用户 controller 完成任务去掉 label/finalizer、Pod 不符合 inPlaceUpdate 条件后,kruise 将 Pod 状态改为 Updating 并开始升级
      • 升级完成后,如果定义了 lifecycle hook 且 Pod 不符合 inPlaceUpdate 条件,将 Pod 状态改为 Updated
      • 等用户 controller 完成任务加上 label/finalizer、Pod 符合 inPlaceUpdate 条件后,kruise 将 Pod 状态改为 Normal 并判断为升级成功

    关于从 PreparingDelete 回到 Normal 状态,从设计上是支持的(通过撤销指定删除),但我们一般不建议这种用法。由于 PreparingDelete 状态的 Pod 不会被升级,当回到 Normal 状态后可能立即再进入发布阶段,对于用户处理 hook 是一个难题。

    5.3 用户 controller 逻辑示例

    按上述例子,可以定义:

    • example.io/unready-blocker finalizer 作为 hook
    • example.io/initialing annotation 作为初始化标记

    在 CloneSet template 模板里带上这个字段:

    1. apiVersion: apps.kruise.io/v1alpha1
    2. kind: CloneSet
    3. spec:
    4. template:
    5. metadata:
    6. annotations:
    7. example.io/initialing: "true"
    8. finalizers:
    9. - example.io/unready-blocker
    10. # ...
    11. lifecycle:
    12. preDelete:
    13. finalizersHandler:
    14. - example.io/unready-blocker
    15. inPlaceUpdate:
    16. finalizersHandler:
    17. - example.io/unready-blocker

    而后用户 controller 的逻辑如下:

    • 对于 Normal 状态的 Pod,如果 annotation 中有 example.io/initialing: true 并且 Pod status 中的 ready condition 为 True,则接入流量、去除这个 annotation
    • 对于 PreparingDelete 和 PreparingUpdate 状态的 Pod,切走流量,并去除 example.io/unready-blocker finalizer
    • 对于 Updated 状态的 Pod,接入流量,并打上 example.io/unready-blocker finalizer
  • 相关阅读:
    multi-gneration lru系列 - 怎么决定回收anon还是file
    SDN实战团技术分享(三十八):DPDK助力NFV与云计算
    Windows下安装配置Nginx
    mysql 使用id in(‘1,2‘) 的时候,只能查到id=1的数据的解决方法
    面试:SurfaceView 和 TextureView
    shell正则表达式,三剑客grep命令
    设计模式(六)——代理模式详解
    5年没发paper,学术论文写到头秃...
    MySQL高级篇之索引分类
    本地配置免费的https咋做?
  • 原文地址:https://blog.csdn.net/zfw_666666/article/details/126726721