在Kubernetes里使用openkruise实现服务原地升级功能

为什么需要原地升级?

在Kubernetes里原生的deployment在升级的时候都是先创建新的Pod,然后删除旧的Pod;而StatefulSet则是先删除旧的Pod,然后创建同名的新的Pod。如果副本数较多,那么在这个过程中就存在多次Pull镜像、多次调度、多次分配网络、挂载PV,如果采用原地升级的方式进行应用的更新,将会大大提升应用的发布效率。

OpenKruise安装

OpenKruise 要求 Kubernetes 版本高于 1.13+,注意在 1.13 和 1.14 版本中必须先在 kube-apiserver 中打开 CustomResourceWebhookConversion feature-gate。

根据官方文档,采用Helm方式安装:

# Kubernetes 1.13 或 1.14 版本
helm install kruise https://github.com/openkruise/kruise/releases/download/v0.9.0/kruise-chart.tgz --disable-openapi-validation

# Kubernetes 1.15 和更新的版本
helm install kruise https://github.com/openkruise/kruise/releases/download/v0.9.0/kruise-chart.tgz

镜像加速的方法,可加上参数:--set  manager.image.repository=openkruise-registry.cn-hangzhou.cr.aliyuncs.com/openkruise/kruise-manager

安装的时候支持一些特殊配置,可以查阅官方文档

升级方法:

# Kubernetes 1.13 and 1.14
helm upgrade kruise https://github.com/openkruise/kruise/releases/download/v0.9.0/kruise-chart.tgz --disable-openapi-validation

# Kubernetes 1.15 and newer versions
helm upgrade kruise https://github.com/openkruise/kruise/releases/download/v0.9.0/kruise-chart.tgz

卸载方法:

$ helm uninstall kruise
release "kruise" uninstalled

原地升级配置

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

Openkruise提供了三种升级方式,默认为 ReCreate:

  • ReCreate: 控制器会删除旧 Pod 和它的 PVC,然后用新版本重新创建出来。

  • InPlaceIfPossible: 控制器会优先尝试原地升级 Pod,如果不行再采用重建升级。目前只有修改 spec.template.metadata.* 和spec.template.spec.containers[x].image 这些字段才可以走原地升级。

  • InPlaceOnly: 控制器只允许采用原地升级。因此,用户只能修改上一条中的限制字段,如果尝试修改其他字段会被 Kruise 拒绝。

其他的一些常见参数简单说明:

  • gracePeriodSeconds:控制器在原地升级的过程中会先把 Pod status 改为 not-ready,然后等一段时间(gracePeriodSeconds),最后再去修改 Pod spec 中的镜像版本。 这样,就为 endpoints-controller 这些控制器留出了充足的时间来将 Pod 从 endpoints 端点列表中去除

  • partition:如果是数字,控制器会将 (replicas - partition) 数量的 Pod 更新到最新版本。如果是百分比,控制器会将 (replicas * (100% - partition)) 数量的 Pod 更新到最新版本。注意:在Advanced StatefulSet里这个是表示order序号。

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

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

一个支持原地升级的CloneSet的yaml文件如下:

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
  labels:
    app: sample
  name: sample
spec:
  replicas: 5
  selector:
    matchLabels:
      app: sample
  updateStrategy:
    type: InPlaceIfPossible
    inPlaceUpdateStrategy:
      gracePeriodSeconds: 10
    partition: 3
    maxUnavailable: 20%        
  template:
    metadata:
      labels:
        app: sample
    spec:
      containers:
      - name: nginx
        image: nginx:1.20

注意下:若首次执行部署上面的yaml,将会全量部署,只有升级过程才执行原地升级机制。

使用上面的yaml进行nginx的版本原地升级,将会只有2个(replicas-partition)Pod执行了升级,并且旧的Pod没有被重建,达到了预期的效果。

这里有些问题需要注意下:

  • 原地升级只有修改 spec.template.metadata.* 和spec.template.spec.containers[x].image 这些字段才可以走原地升级

  • 如果镜像的hash值没有改变也是无法触发原地升级机制

  • 可以基于控制partition参数来达到分批升级的机制

同时openkruise也提供了新镜像预热功能,需要在安装的时候开启PreDownloadImageForInPlaceUpdate,默认是未开启的。开启这个特性后将在节点上创建NodeImage,用户创建ImagePullJob来做镜像预热详细说明可以参考ImagePulljob


版权所有原创文章,转载请保留或注明出处:http://www.5bug.wang/post/122.html