本文将记录为什么最终没有采用 Helm
而是选择了 Kustomize
作为 Kubernetes
应用的部署工具。
首先说说之前的痛点。我们虽然不是个大公司,可是这代码也是越敲越多,服务也是越做越全。零零总总也有十几个项目要管理了。然后我们同样有多套部署环境:内网环境,预生产环境,生产环境。那么针对每一个环境几乎都要有一套 Kubernetes
的 YAML 文件,但是各个仅仅是稍有不同。
然后我们自己的 CI
是将构建好的 Docker
镜像放到 Registry
里面。
那么,每次更新的镜像之后就是通过人手工去部署一下,绝大多数情况就是修改一下镜像的 Tag
,但是由于每个环境的 YAML 略有区别,那么如果我需要在不同环境切换的时候就需要来回修改这些 YAML 文件,一不小心写错了就只能怪自己手残。然而这种部署方式虽然在 Kubernetes
之下就是改改 YAML 就好了,但是依然感觉很是原始。
仔细想想,自己的需求就是这么几个:
Kubernetes
部署结构。
既然都说 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
了。
在这个时候我想起来了在之前 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
可以设置如下的层次:
├── 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
之后就可以将这部分覆盖默认的配置。
Kustomize
提供了一个命令行方法对镜像 Tag 进行修改:
$ kustomize edit set imagetag xxx:94c269ec
如果想更方便的使用,你还可以这么做:
$ export NEWTAG=94c269ec
$ kustomize edit set imagetag xxx:$NEWTAG
那么每次都去 ctrl-r
修改这个 export
然后再 ctrl-r
找到第二条命令执行一下就好了。虽然它还是修改了 kustomization.yaml 但是我觉得比打开编辑器改要舒服一些。
相对 Helm
,Kustomize
依然保留了对 kubectl apply -f
命令的支持,仅仅作为一个命令行工具;不像 Helm
还需要在 K8s
里面部署一个 Tiller
可谓是非常的轻量级了。
分别举例说明:
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
secretGenerator
和 configMapGenerator
可以以更灵活的方式生成 configmap
和 secret
,相对来说更方便吧。
然后注意看我 configMapGenerator
的例子,echo -n $xxx
是会有问题的,一定要使用 "bash -c 'echo -n $SHORT_MESSAGE_API_KEY'"
的命令。
我认为他们的区别主要在工作流程上:
例如:我们定义了一个很基础的应用,由 Deployment + Service 组成,如果后续部署中需要完成两个变更:新建 Ingress 对象和修改镜像地址/名称/TAG。
要公开发布一个较为复杂的应用,编写良好的 Chart 能给用户很大帮助,用户通过对 values.yaml 的阅读,就能对这种复杂的部署产生一个较为深入的认识。
如果是常见的业务应用,因为不同部署之间的差异不大,用 Kustomize 可能会是一个更好的选择。