本文将记录为什么最终没有采用 Helm
而是选择了 Kustomize
作为 Kubernetes
应用的部署工具。
使用各种项目管理之前的情况
首先说说之前的痛点。我们虽然不是个大公司,可是这代码也是越敲越多,服务也是越做越全。零零总总也有十几个项目要管理了。然后我们同样有多套部署环境:内网环境,预生产环境,生产环境。那么针对每一个环境几乎都要有一套 Kubernetes
的 YAML 文件,但是各个仅仅是稍有不同。
然后我们自己的 CI
是将构建好的 Docker
镜像放到 Registry
里面。
那么,每次更新的镜像之后就是通过人手工去部署一下,绝大多数情况就是修改一下镜像的 Tag
,但是由于每个环境的 YAML 略有区别,那么如果我需要在不同环境切换的时候就需要来回修改这些 YAML 文件,一不小心写错了就只能怪自己手残。然而这种部署方式虽然在 Kubernetes
之下就是改改 YAML 就好了,但是依然感觉很是原始。
希望有什么改善
仔细想想,自己的需求就是这么几个:
- 有一个统一的模板可以管理一个项目的
Kubernetes
部署结构 - 有某种方式可以管理不同环境之间微小的差异
- 每次更新基本就是修改镜像的标签然后部署,那么有没有什么简单的办法实现之,而不是让我每次都去修改 YAML 文件
针对 Helm 的调研
既然都说 Helm
是 Kubernetes
的包管理工具,那么我就先去尝试了一下 Helm
。
Helm 是 Deis 开发的一个用于 Kubernetes 应用的包管理工具,主要用来管理 Charts。有点类似于 Ubuntu 中的 APT 或 CentOS 中的 YUM。
Helm Chart 是用来封装 Kubernetes 原生应用程序的一系列 YAML 文件。可以在你部署应用的时候自定义应用程序的一些 Metadata,以便于应用程序的分发。
对于应用发布者而言,可以通过 Helm 打包应用、管理应用依赖关系、管理应用版本并发布应用到软件仓库。
对于使用者而言,使用 Helm 后不用需要编写复杂的应用部署文件,可以以简单的方式在 Kubernetes 上查找、安装、升级、回滚、卸载应用程序。
更多 Helm
的介绍可参考 「Helm 入门指南」 一文。
简单的看了看,Helm
给我一种大而无当的感觉:它真的是一个做包管理工具的,复杂的 Go Template
体系以及需要单独存放的 Charts
让我感觉其更适合对标 Ubuntu
的 APT
或者 macOS
的 Brew
。它更像是对外提供一个复杂的可以依据各种配置信息生成适合于不同环境的软件发布包,而不是用于我们这种轻量级的部署配置管理的。所以我就放弃使用 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 的特色
- 功能简单清晰,kubectl 直接支持。
- 不考虑派生,仅作为应用的 YAML 组织方式也很有帮助。
- 自身支持插件。
继承和 Patch
Kustomize
可以设置如下的层次:
1 | ├── base |
其中 base 里保存各个环境所有的公有配置 base/kustomization.yaml
:
1 | resources: |
然后在 overlays 中可以定义子环境 overlays/stg/kustomization.yaml
:
1 | bases: |
可以看到 stg 下继承了 base 的配置,并且添加了 ingress.yaml 配置。同时,Kustomize
不仅仅支持文件级别的 patch,还支持对一个文件某些字段的 patch。
如下图所示,replica_count.yaml 只包含了有关 replicas 的部分即可,在执行 kustomize build
之后就可以将这部分覆盖默认的配置。
edit 命令
Kustomize
提供了一个命令行方法对镜像 Tag 进行修改:
1 | $ kustomize edit set imagetag xxx:94c269ec |
如果想更方便的使用,你还可以这么做:
1 | $ export NEWTAG=94c269ec |
那么每次都去 ctrl-r
修改这个 export
然后再 ctrl-r
找到第二条命令执行一下就好了。虽然它还是修改了 kustomization.yaml 但是我觉得比打开编辑器改要舒服一些。
Kustomize 额外加分项
轻量级
相对 Helm
,Kustomize
依然保留了对 kubectl apply -f
命令的支持,仅仅作为一个命令行工具;不像 Helm
还需要在 K8s
里面部署一个 Tiller
可谓是非常的轻量级了。
对 Secret 和 Configmap 的支持
分别举例说明:
1 | bases: |
1 | resources: |
secretGenerator
和 configMapGenerator
可以以更灵活的方式生成 configmap
和 secret
,相对来说更方便吧。
然后注意看我 configMapGenerator
的例子,echo -n $xxx
是会有问题的,一定要使用 "bash -c 'echo -n $SHORT_MESSAGE_API_KEY'"
的命令。
Kustomize 和 Helm 的区别
我认为他们的区别主要在工作流程上:
-
Helm 的基础流程比较瀑布:定义 Chart->填充->运行,在 Chart 中没有定义的内容是无法更改的;
-
Kustomize 的用法比较迭代:Base 和 Overlay 都是可以独立运作的,增加新对象,或者对编写 Base 时未预料的内容进行变更,都不在话下。
例如:我们定义了一个很基础的应用,由 Deployment + Service 组成,如果后续部署中需要完成两个变更:新建 Ingress 对象和修改镜像地址/名称/TAG。
- 使用 Helm 你需要的步骤:
- 在 Chart 中加入对 Ingress 的定义
- 用变量控制 Ingress 是否进行渲染
- Ingress 模板应该包含特定的主机名、注解等变量
- 把镜像也定义成变量
- 在 Values.yaml 中对这些变量进行赋值。
- 使用 Kustomize 你需要的步骤:
- 无需对 Base 进行修改
- 直接在新的 Overlay 中写入 Ingress Resource
- 使用内置的 image transformer 替换原有镜像
结论
要公开发布一个较为复杂的应用,编写良好的 Chart 能给用户很大帮助,用户通过对 values.yaml 的阅读,就能对这种复杂的部署产生一个较为深入的认识。
如果是常见的业务应用,因为不同部署之间的差异不大,用 Kustomize 可能会是一个更好的选择。