---
slug: openkruise-1.0
title: OpenKruise v1.0：云原生应用自动化达到新的高峰
authors: [FillZpp]
tags: [release]
---

云原生应用自动化管理套件、CNCF Sandbox 项目 -- OpenKruise，近期发布了 v1.0 大版本。

[OpenKruise](https://openkruise.io) 是针对 Kubernetes 的增强能力套件，聚焦于云原生应用的部署、升级、运维、稳定性防护等领域。所有的功能都通过 CRD 等标准方式扩展，可以适用于 1.16 以上版本的任意 Kubernetes 集群。单条 helm 命令即可完成 Kruise 的一键部署，无需更多配置。

![openkruise-features|center|450x400](/img/blog/2021-12-13-release-1.0/features-zh.png)

总得来看，目前 OpenKruise 提供的能力分为几个领域：

- **应用工作负载**：面向无状态、有状态、daemon 等多种类型应用的高级部署发布策略，例如原地升级、灰度流式发布等。
- **Sidecar 容器管理**：支持独立定义 sidecar 容器，完成动态注入、独立原地升级、热升级等功能。
- **增强运维能力**：包括容器原地重启、镜像预拉取、容器启动顺序保障等。
- **应用分区管理**：管理应用在多个分区（可用区、不同机型等）上的部署比例、顺序、优先级等。
- **应用安全防护**：帮助应用在 Kubernetes 之上获得更高的安全性保障与可用性防护。

## 版本解析

在 v1.0 大版本中，OpenKruise 带来了多种新的特性，同时也对不少已有功能做了增强与优化。

首先要说的是，从 v1.0 开始 OpenKruise 将 CRD/WehhookConfiguration 等资源配置的版本从 `v1beta1` 升级到 `v1`，因此可以**支持 Kubernetes v1.22 及以上版本的集群，但同时也要求 Kubernetes 的版本不能低于 v1.16**。

以下对 v1.0 的部分功能做简要介绍，详细的 ChangeLog 列表请查看 OpenKruise Github 上的 release 说明以及官网文档。

### 1. 支持环境变量原地升级

*Author: [@FillZpp](https://github.com/FillZpp)*

OpenKruise 从早期版本开始就支持了 “原地升级” 功能，主要应用于 CloneSet 与 Advanced StatefulSet 两种工作负载上。简单来说，原地升级使得应用在升级的过程中，不需要删除、新建 Pod 对象，而是通过对 Pod 中容器配置的修改来达到升级的目的。

![inplace-update-comparation|center|450x400](/img/docs/core-concepts/inplace-update-comparation.png)

如上图所示，原地升级过程中只修改了 Pod 中的字段，因此：

1. 可以避免如 *调度*、*分配 IP*、*分配、挂载盘* 等额外的操作和代价。
2. 更快的镜像拉取，因为可以复用已有旧镜像的大部分 layer 层，只需要拉取新镜像变化的一些 layer。
3. 当一个容器在原地升级时，Pod 的网络、挂载盘、以及 Pod 中的其他容器不会受到影响，仍然维持运行。

然而，OpenKruise 过去只能对 Pod 中 image 字段的更新做原地升级，对于其他字段仍然只能采用与 Deployment 相似的重建升级。一直以来，我们收到很多用户反馈，希望支持对 env 等更多字段的原地升级 -- 由于受到 kube-apiserver 的限制，这是很难做到的。

经过我们的不懈努力，OpenKruise 终于在 v1.0 版本中，支持了通过 Downward API 的方式支持了 env 环境变量的原地升级。例如对以下CloneSet YAML，用户将配置定义在 annotation 中并关联到对应 env 中。后续在修改配置时，只需要更新 annotation value 中的值，Kruise 就会对 Pod 中所有 env 里引用了这个 annotation 的容器触发原地重建，从而生效这个新的 value 配置。

```yaml
apiVersion: apps.kruise.io/v1alpha1
kind: CloneSet
metadata:
  ...
spec:
  replicas: 1
  template:
    metadata:
      annotations:
        app-config: "... the real env value ..."
    spec:
      containers:
      - name: app
        env:
        - name: APP_CONFIG
          valueFrom:
            fieldRef:
              fieldPath: metadata.annotations['app-config']
  updateStrategy:
    type: InPlaceIfPossible
```

*与此同时，我们在这个版本中也去除了过去对镜像原地升级的`imageID`限制，即支持相同imageID的两个镜像替换升级。*

具体使用方式请参考[文档](/docs/core-concepts/inplace-update)。

### 2. 配置跨命名空间分发

*Author: [@veophi](https://github.com/veophi)*

在对 Secret、ConfigMap 等 namespace-scoped 资源进行跨 namespace 分发及同步的场景中，原生 kubernetes 目前只支持用户 one-by-one 地进行手动分发与同步，十分地不方便。

典型的案例有：
- 当用户需要使用 SidecarSet 的 imagePullSecrets 能力时，要先重复地在相关 namespaces 中创建对应的 Secret，并且需要确保这些 Secret 配置的正确性和一致性。
- 当用户想要采用 ConfigMap 来配置一些**通用**的环境变量时，往往需要在多个 namespaces 做 ConfigMap 的下发，并且后续的修改往往也要求多 namespaces 之间保持同步。

因此，面对这些需要跨 namespaces 进行资源分发和**多次同步**的场景，我们期望一种更便捷的分发和同步工具来自动化地去做这件事，为此我们设计并实现了一个新的CRD --- **ResourceDistribution**。

ResourceDistribution 目前支持 **Secret** 和 **ConfigMap** 两类资源的分发和同步。

```yaml
apiVersion: apps.kruise.io/v1alpha1
kind: ResourceDistribution
metadata:
  name: sample
spec:
  resource:
    apiVersion: v1
    kind: ConfigMap
    metadata:
      name: game-demo
    data:
      ...
  targets:
  	namespaceLabelSelector:
      ...
    # or includedNamespaces, excludedNamespaces
```

如上述 YAML 所示，ResourceDistribution是一类 **cluster-scoped** 的 CRD，其主要由 **`resource`** 和 **`targets`** 两个字段构成，其中 **`resource`** 字段用于描述用户所要分发的资源，**`targets`** 字段用于描述用户所要分发的目标命名空间。

具体使用方式请参考[文档](/docs/user-manuals/resourcedistribution)。

### 3. 容器启动顺序控制

*Author: [@Concurrensee](https://github.com/Concurrensee)*

对于 Kubernetes 的一个 Pod，其中的多个容器可能存在依赖关系，比如 容器B 中应用进程的运行依赖于 容器A 中的应用。因此，多个容器之间存在顺序关系的需求：
- 容器A 先启动，启动成功后才可以启动 容器B
- 容器B 先退出，退出完成后才可以停止 容器A

通常来说 Pod 容器的启动和退出顺序是由 Kubelet 管理的。Kubernetes 曾经有一个 KEP 计划在 container 中增加一个 type 字段来标识不同类型容器的启停优先级。但是由于 sig-node 考虑到对现有代码架构的改动太大，目前这个 KEP 已经被拒绝了。

因此，OpenKruise 在 v1.0 中提供了名为 **Container Launch Priority** 的功能，用于控制一个 Pod 中多个容器的强制启动顺序：

1. 对于任意一个 Pod 对象，只需要在 annotations 中定义 `apps.kruise.io/container-launch-priority: Ordered`，则 Kruise 会按照 Pod 中 `containers` 容器列表的顺序来保证其中容器的串行启动。
2. 如果要自定义 `containers` 中多个容器的启动顺序，则在容器 env 中添加 `KRUISE_CONTAINER_PRIORITY` 环境变量，value 值是范围在 `[-2147483647, 2147483647]` 的整数。一个容器的 priority 值越大，会保证越先启动。

具体使用方式请参考[文档](/docs/user-manuals/containerlaunchpriority)。

### 4. `kubectl-kruise` 命令行工具

*Author: [@hantmac](https://github.com/hantmac)*

过去 OpenKruise 是通过 kruise-api、client-java 等仓库提供了 Go、Java 等语言的 Kruise API 定义以及客户端封装，可供用户在自己的应用程序中引入使用。但仍然有不少用户在测试环境下需要灵活地用命令行操作 workload 资源。

然而原生 `kubectl` 工具提供的 `rollout`、`set image` 等命令只能适用于原生的 workload 类型，如 Deployment、StatefulSet，并不能识别 OpenKruise 中扩展的 workload 类型。

因此，OpenKruise 最新提供了 `kubectl-kruise` 命令行工具，它是 `kubectl` 的标准插件，提供了许多适用于 OpenKruise workload 的功能。

```bash
# rollout undo cloneset
$ kubectl kruise rollout undo cloneset/nginx

#  rollout status advanced statefulset
$ kubectl kruise rollout status statefulsets.apps.kruise.io/sts-demo

# set image of a cloneset
$ kubectl kruise set image cloneset/nginx busybox=busybox nginx=nginx:1.9.1
```

具体使用方式请参考[文档](/docs/cli-tool/kubectl-plugin)。

### 5. 其余部分功能改进与优化

**CloneSet:**
- 通过 `scaleStrategy.maxUnavailable` 策略支持流式扩容
- Stable revision 判断逻辑变化，当所有 Pod 版本与 updateRevision 一致时则标记为 currentRevision

**WorkloadSpread:**
- 支持接管存量 Pod 到匹配的 subset 分组中
- 优化 webhook 在 Pod 注入时的更新与重试逻辑

**Advanced DaemonSet:**
- 支持对 Daemon Pod 做原地升级
- 引入 progressive annotation 来选择是否按 partition 限制 Pod 创建

**SidecarSet:**
- 解决 SidecarSet 过滤屏蔽 inactive Pod
- 在 `transferenv` 中新增 `SourceContainerNameFrom` 和 `EnvNames` 字段，来解决 container name 不一致与大量 env 情况下的冗余问题

**PodUnavailableBudget:**
- 新增 “跳过保护” 标识
- PodUnavailableBudget controller 关注 workload 工作负载的 replicas 变化

**NodeImage:**
- 加入 `--nodeimage-creation-delay` 参数，并默认等待新增 Node ready 一段时间后同步创建 NodeImage

**UnitedDeployment:**
- 解决 `NodeSelectorTerms` 为 nil 情况下 Pod `NodeSelectorTerms` 长度为 0 的问题

**Other optimization:**
- kruise-daemon 采用 protobuf 协议操作 Pod 资源
- 暴露 cache resync 为命令行参数，并在 chart 中设置默认值为 0
- 解决 certs 更新时的 http checker 刷新问题
- 去除对 forked controller-tools 的依赖，改为使用原生 controller-tools 配合 markers 注解

## 社区参与

非常欢迎你通过 Github/Slack/钉钉/微信 等方式加入我们来参与 OpenKruise 开源社区。
你是否已经有一些希望与我们社区交流的内容呢？
可以在我们的[社区双周会](https://shimo.im/docs/gXqmeQOYBehZ4vqo)上分享你的声音，或通过以下渠道参与讨论：

- 加入社区 [Slack channel](https://kubernetes.slack.com/channels/openkruise) (English)
- 加入社区钉钉群：搜索群号 `23330762` (Chinese)
- 加入社区微信群：添加用户 `openkruise` 并让机器人拉你入群 (Chinese)
