Kustomize 和 Helm 之间,我为什么选择了 Kustomize?

本文将记录为什么最终没有采用 Helm 而是选择了 Kustomize 作为 Kubernetes 应用的部署工具。

使用各种项目管理之前的情况

首先说说之前的痛点。我们虽然不是个大公司,可是这代码也是越敲越多,服务也是越做越全。零零总总也有十几个项目要管理了。然后我们同样有多套部署环境:内网环境,预生产环境,生产环境。那么针对每一个环境几乎都要有一套 Kubernetes 的 YAML 文件,但是各个仅仅是稍有不同。

然后我们自己的 CI 是将构建好的 Docker 镜像放到 Registry 里面。

那么,每次更新的镜像之后就是通过人手工去部署一下,绝大多数情况就是修改一下镜像的 Tag,但是由于每个环境的 YAML 略有区别,那么如果我需要在不同环境切换的时候就需要来回修改这些 YAML 文件,一不小心写错了就只能怪自己手残。然而这种部署方式虽然在 Kubernetes 之下就是改改 YAML 就好了,但是依然感觉很是原始。

希望有什么改善

仔细想想,自己的需求就是这么几个:

  1. 有一个统一的模板可以管理一个项目的 Kubernetes 部署结构。
  2. 有某种方式可以管理不同环境之间微小的差异。
  3. 每次更新基本就是修改镜像的标签然后部署,那么有没有什么简单的办法实现之,而不是让我每次都去修改 YAML 文件。

针对 Helm 的调研

既然都说 HelmKubernetes 的包管理工具,那么我就先去尝试了一下 Helm

Helm 是 Deis 开发的一个用于 Kubernetes 应用的包管理工具,主要用来管理 Charts。有点类似于 Ubuntu 中的 APT 或 CentOS 中的 YUM。 Helm Chart 是用来封装 Kubernetes 原生应用程序的一系列 YAML 文件。可以在你部署应用的时候自定义应用程序的一些 Metadata,以便于应用程序的分发。 对于应用发布者而言,可以通过 Helm 打包应用、管理应用依赖关系、管理应用版本并发布应用到软件仓库。 对于使用者而言,使用 Helm 后不用需要编写复杂的应用部署文件,可以以简单的方式在 Kubernetes 上查找、安装、升级、回滚、卸载应用程序。

更多 Helm 的介绍可参考 「Helm 入门指南」 一文。

简单的看了看,Helm 给我一种大而无当的感觉:它真的是一个做包管理工具的,复杂的 Go Template 体系以及需要单独存放的 Charts 让我感觉其更适合对标 UbuntuAPT 或者 macOSBrew。它更像是对外提供一个复杂的可以依据各种配置信息生成适合于不同环境的软件发布包,而不是用于我们这种轻量级的部署配置管理的。所以我就放弃使用 Helm 了。

针对 Kustomize 的调研

在这个时候我想起来了在之前 Github Trending 看到的另外一个用户做 Kubernetes 配置的工具 Kustomize。简单的说,它就是一个简化 Kubernetes YAML 编写的工具。它提供了两个重要的功能恰好满足了我的需求。

Kustomize 是一个新晋选手,只有一个 CLI 工具。在 Kubernetes 1.14 之后,甚至这唯一的工具也成为 kubectl 的一部分。 Kustomize 放弃了对模板的要求,改用 Base + Overlay 的方式对应用的原始 YAML 进行派生。Overlay,顾名思义,就是覆盖。Kustomize 的 Overlay 可以在 Base 的基础上,通过对 resource、generator、transformer 等的定义,形成新的应用定义,不论 Base 还是 Overlay,都可以通过 kustomize build 生成有效的 YAML。

Kustomize 的特色

  1. 功能简单清晰,kubectl 直接支持。
  2. 不考虑派生,仅作为应用的 YAML 组织方式也很有帮助。
  3. 自身支持插件。

继承和 Patch

Kustomize 可以设置如下的层次:

├── base  │   ├── deployment.yaml  │   ├── kustomization.yaml  │   └── service.yaml  └── overlays      └── stg          ├── ingress.yaml          └── kustomization.yaml

其中 base 里保存各个环境所有的公有配置 base/kustomization.yaml:

resources:  - deployment.yaml  - service.yaml

然后在 overlays 中可以定义子环境 overlays/stg/kustomization.yaml:

bases:  - ../../base    resources:  - ingress.yaml

可以看到 stg 下继承了 base 的配置,并且添加了 ingress.yaml 配置。同时,Kustomize 不仅仅支持文件级别的 patch,还支持对一个文件某些字段的 patch。

如下图所示,replica_count.yaml 只包含了有关 replicas 的部分即可,在执行 kustomize build 之后就可以将这部分覆盖默认的配置。

edit 命令

Kustomize 提供了一个命令行方法对镜像 Tag 进行修改:

$ kustomize edit set imagetag xxx:94c269ec

如果想更方便的使用,你还可以这么做:

$ export NEWTAG=94c269ec  $ kustomize edit set imagetag xxx:$NEWTAG

那么每次都去 ctrl-r 修改这个 export 然后再 ctrl-r 找到第二条命令执行一下就好了。虽然它还是修改了 kustomization.yaml 但是我觉得比打开编辑器改要舒服一些。

Kustomize 额外加分项

轻量级

相对 HelmKustomize 依然保留了对 kubectl apply -f 命令的支持,仅仅作为一个命令行工具;不像 Helm 还需要在 K8s 里面部署一个 Tiller 可谓是非常的轻量级了。

对 Secret 和 Configmap 的支持

分别举例说明:

bases:  - ../../base    configMapGenerator:  - literals:    - STORAGE.DATASETUPLOADURL=https://xxx/files/datasets    - STORAGE.CODEUPLOADURL=https://xxx/files/codes    - LIVELOG_PREFIX=https://xxx/jobs    name: storage-server    resources:  - ingress.yaml    imageTags:  - name: xxx    newTag: dc12c4d7
resources:  - deployment.yaml    secretGenerator:  - name: notification-service    commands:      SHORT_MESSAGE_API_KEY: "bash -c 'echo -n $SHORT_MESSAGE_API_KEY'"      MG_API_KEY: "bash -c 'echo -n $MG_API_KEY'"    type: Opaque    generatorOptions:    disableNameSuffixHash: true

secretGeneratorconfigMapGenerator 可以以更灵活的方式生成 configmapsecret,相对来说更方便吧。

然后注意看我 configMapGenerator 的例子,echo -n $xxx 是会有问题的,一定要使用 "bash -c 'echo -n $SHORT_MESSAGE_API_KEY'" 的命令。

Kustomize 和 Helm 的区别

我认为他们的区别主要在工作流程上:

  1. Helm 的基础流程比较瀑布:定义 Chart->填充->运行,在 Chart 中没有定义的内容是无法更改的;
  2. Kustomize 的用法比较迭代:Base 和 Overlay 都是可以独立运作的,增加新对象,或者对编写 Base 时未预料的内容进行变更,都不在话下。

例如:我们定义了一个很基础的应用,由 Deployment + Service 组成,如果后续部署中需要完成两个变更:新建 Ingress 对象和修改镜像地址/名称/TAG。

  1. 使用 Helm 你需要的步骤:
  • 在 Chart 中加入对 Ingress 的定义
  • 用变量控制 Ingress 是否进行渲染
  • Ingress 模板应该包含特定的主机名、注解等变量
  • 把镜像也定义成变量
  • 在 Values.yaml 中对这些变量进行赋值。
  1. 使用 Kustomize 你需要的步骤:
  • 无需对 Base 进行修改
  • 直接在新的 Overlay 中写入 Ingress Resource
  • 使用内置的 image transformer 替换原有镜像

结论

要公开发布一个较为复杂的应用,编写良好的 Chart 能给用户很大帮助,用户通过对 values.yaml 的阅读,就能对这种复杂的部署产生一个较为深入的认识。

如果是常见的业务应用,因为不同部署之间的差异不大,用 Kustomize 可能会是一个更好的选择。

参考文档

  1. https://www.google.com
  2. https://aisensiy.github.io/2018/11/27/helm-and-kustomize/
  3. https://blog.fleeto.us/post/helm-vs-kustomize/