加载中...

OpenKruise详解


SidecarSet

这个控制器支持通过 admission webhook 来自动为集群中创建的符合条件的 Pod 注入 sidecar 容器。 这个注入过程和 istio 的自动注入方式很类似。 除了在 Pod 创建时候注入外,SidecarSet 还提供了为运行时 Pod 原地升级其中已经注入的 sidecar 容器镜像的能力。
简单来说,SidecarSet 将 sidecar 容器的定义和生命周期与业务容器解耦。 它主要用于管理无状态的 sidecar 容器,比如监控、日志等 agent。

范例

apiVersion: apps.kruise.io/v1alpha1
kind: SidecarSet
metadata:
  name: test-sidecarset
spec:
  containers:
  - command:
    - sleep
    - 999d
    image: centos:6.7
    imagePullPolicy: Always
    name: tools
    podInjectPolicy: BeforeAppContainer
    resources:
      limits:
        cpu: 50m
        memory: 100Mi
      requests:
        cpu: 50m
        memory: 100Mi
    shareVolumePolicy:
      type: enabled
    terminationMessagePath: /dev/termination-log
    terminationMessagePolicy: File
    upgradeStrategy:
      upgradeType: ColdUpgrade
  injectionStrategy: {}
  namespace: default
  revisionHistoryLimit: 10
  selector:
    matchExpressions:
    - key: app
      operator: Exists
  updateStrategy:
    maxUnavailable: 1
    partition: 0%
    paused: true
    type: RollingUpdate
  • spec.selector 通过label的方式选择需要注入、更新的pod,支持matchLabels、MatchExpressions两种方式,详情请参考:https://kubernetes.io/docs/concepts/overview/working-with-objects/labels/
  • spec.containers 定义需要注入、更新的pod.spec.containers容器,支持完整的k8s container字段,详情请参考:https://kubernetes.io/docs/concepts/containers/
  • spec.initContainers 定义需要注入的pod.spec.initContainers容器,支持完整的k8s initContainer字段,详情请参考:https://kubernetes.io/docs/concepts/workloads/pods/init-containers/
    • 注入initContainers容器默认基于container name升级排序
    • initContainers只支持注入,不支持pod原地升级
  • spec.updateStrategy sidecarSet更新策略,type表明升级方式:
    • NotUpdate 不更新,此模式下只会包含注入能力
    • RollingUpdate 注入+滚动更新,包含了丰富的滚动更新策略,后面会详细介绍
  • spec.namespace sidecarset默认在k8s整个集群范围内生效,即对所有的命名空间生效(除了kube-system, kube-public),当设置该字段时,只对该namespace的pod生效
  • podInjectPolicy 定义container注入到pod.spec.containers中的位置
    • BeforeAppContainer(默认) 注入到pod原containers的前面
    • AfterAppContainer 注入到pod原containers的后面
  • 数据卷共享
    • 共享指定卷:通过 spec.volumes 来定义 sidecar 自身需要的 volume,详情请参考:https://kubernetes.io/docs/concepts/storage/volumes/
    • 共享所有卷:通过 spec.containers[i].shareVolumePolicy.type = enabled | disabled 来控制是否挂载pod应用容器的卷,常用于日志收集等 sidecar,配置为 enabled 后会把应用容器中所有挂载点注入 sidecar 同一路经下(sidecar中本身就有声明的数据卷和挂载点除外)
  • 环境变量共享
    可以通过 spec.containers[i].transferEnv 来从别的容器获取环境变量,会把名为 sourceContainerName 容器中名为 envName 的环境变量拷贝到本容器

创建pod测试注入是否生效

apiVersion: v1
kind: Pod
metadata:
  labels:
    app: nginx # matches the SidecarSet's selector
  name: test-pod
spec:
  containers:
  - name: app
    image: nginx:1.15.1

确认是否注入

kubectl get po | grep test-pod
test-pod                  2/2     Running   0          82s

CloneSet

CloneSet 控制器提供了高效管理无状态应用的能力,它可以对标原生的 Deployment,但 CloneSet 提供了很多增强功能。
按照 Kruise 的命名规范,CloneSet 是一个直接管理 Pod 的 Set 类型 workload。

例如

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
  name: sample
  labels:
    app: sample
spec:
  replicas: 5
  selector:
    matchLabels:
      app: sample
  template:
    metadata:
      labels:
        app: sample
    spec:
      containers:
      - name: nginx
        image: nginx:alpine

扩缩容功能

支持pvc模板

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

注意:

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

例如:

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
  name: sample-data
  namespace: ops
  labels:
    app: sample
spec:
  replicas: 5
  selector:
    matchLabels:
      app: sample
  template:
    metadata:
      labels:
        app: sample
    spec:
      containers:
      - name: nginx
        image: nginx:alpine
        volumeMounts:
        - name: cephfs-pvc-demo
          mountPath: /usr/share/nginx/html
  volumeClaimTemplates:
    - metadata:
        name: cephfs-pvc-demo
      spec:
        accessModes: [ "ReadWriteOnce" ]
        resources:
          requests:
            storage: 1Gi
        storageClassName: ceph-storageclass

创建后可以看到每个pod都有自己的pvc

kubectl get pvc -n ops 
NAME                                STATUS   VOLUME                                     CAPACITY   ACCESS MODES   STORAGECLASS        AGE
cephfs-pvc-demo-sample-data-4v6wb   Bound    pvc-ba67e462-deed-4153-803d-ad52b9e6d89f   1Gi        RWO            ceph-storageclass   4m3s
cephfs-pvc-demo-sample-data-6wz8m   Bound    pvc-be4c9711-3f18-4153-be65-2b0a495893b1   1Gi        RWO            ceph-storageclass   4m2s
cephfs-pvc-demo-sample-data-f7cxs   Bound    pvc-4c4fc404-88e6-4320-945e-914882375749   1Gi        RWO            ceph-storageclass   4m2s
cephfs-pvc-demo-sample-data-k2rd6   Bound    pvc-ceb78d1f-99e5-4011-b87f-dd18ebebbc28   1Gi        RWO            ceph-storageclass   4m2s
cephfs-pvc-demo-sample-data-ql7bn   Bound    pvc-cedf91b0-eac9-437e-a193-7b53c9dd437c   1Gi        RWO            ceph-storageclass   4m2s
指定pod缩容

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

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

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
spec:
  #...
  replicas: 3
  revisionHistoryLimit: 10
  scaleStrategy: 
    podsToDelete:
    - sample-data-6wz8m

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

注意:如果你只把 Pod 名字加到 podsToDelete,但没有修改 replicas 数量,那么控制器会先把指定的 Pod 删掉,然后再扩一个新的 Pod。
如果不指定 podsToDelete,控制器会按照默认顺序来选择 Pod 删除:not-ready < ready, unscheduled < scheduled, pending < running。

升级功能

原地升级

CloneSet 提供了和 Advanced StatefulSet 相同的 3 个升级方式,默认为 ReCreate

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

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

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

当一个 Pod 被原地升级时,控制器会先利用 readinessGates 把 Pod status 中修改为 not-ready 状态,然后再更新 Pod spec 中的 image 字段来触发 Kubelet 重建对应的容器。不过这样可能存在的一个风险:有时候 Kubelet 重建容器太快,还没等到其他控制器如 endpoints-controller 感知到 Pod not-ready,可能会导致流量受损。
因此又在原地升级中提供了 graceful period 选项,作为优雅原地升级的策略。用户如果配置了 gracePeriodSeconds 这个字段,控制器在原地升级的过程中会先把 Pod status 改为 not-ready,然后等一段时间(gracePeriodSeconds),最后再去修改 Pod spec 中的镜像版本。这样,就为 endpoints-controller 这些控制器留出了充足的时间来将 Pod 从 endpoints 端点列表中去除。

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
spec:
  # ...
  updateStrategy:
    inPlaceUpdateStrategy:
      gracePeriodSeconds: 10
    maxSurge: 0
    maxUnavailable: 20%
    partition: 0
    type: InPlaceIfPossible

配置完成后修改镜像测试

Normal   Killing                 2m35s                kubelet, dev-k8s     Container nginx definition changed, will be restarted
  Normal   Pulling                 2m35s                kubelet, dev-k8s     Pulling image "nginx:1.17"
  Normal   Created                 2m17s (x2 over 49m)  kubelet, dev-k8s     Created container nginx
  Normal   Started                 2m17s (x2 over 49m)  kubelet, dev-k8s     Started container nginx
  Normal   Pulled                  2m17s                kubelet, dev-k8s     Successfully pulled image "nginx:1.17" in 18.297840376s

查看pod发现镜像更新 但是pod没有重新创建而是重启了

kubectl get po -n ops
sample-data-f7cxs   1/1     Running            1          50m
sample-data-k2rd6   1/1     Running            1          50m
Partition 分批灰度

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

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

如果是数字,控制器会将 (replicas - partition) 数量的 Pod 更新到最新版本;

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

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

apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
  # ...
  generation: 2
spec:
  replicas: 5
  template:
    metadata:
      labels:
        app: sample
    spec:
      containers:
      - image: nginx:mainline
        imagePullPolicy: Always
        name: nginx
  updateStrategy:
    maxSurge: 0
    maxUnavailable: 20%
    partition: 2
    type: ReCreate

因为partition: 2所以会更新三个pod

sample-data-8p6gx   1/1     Running   1          106m    sample-data-7656fc4998
sample-data-8rzcr   1/1     Running   0          3m1s    sample-data-78479f6458
sample-data-9qq4j   1/1     Running   0          103m    sample-data-7656fc4998
sample-data-dc7qz   1/1     Running   0          2m25s   sample-data-78479f6458
sample-data-ql7bn   1/1     Running   1          104m    sample-data-7656fc4998

文章作者: huhuhahei
版权声明: 本博客所有文章除特別声明外,均采用 CC BY 4.0 许可协议。转载请注明来源 huhuhahei !
评论
  目录