Helm和Kustomize都是流行的Kubernetes集群部署管理工具,本文比较了两者的优缺点,方便读者根据项目实际情况采用适合的方案。原文: Helm vs Kustomize: why, when, and how[1]

挑战
开始讨论之前,先来看看为什么要使用 Helm 或 Kustomize。
这么多环境,这么多 YAML 文件!
Kubernetes 帮助我们非常容易的为不同用例创建不同的环境,可以在同一个集群甚至多个集群上使用命名空间,可以托管开发、测试、QA、UAT、预发、生产……等等不同的环境。但问题是:如何管理所有这些环境?
第一种也是最直接的方法是创建相同manifest的副本,并为每个副本命名。也就是说,把源文件复制粘贴到每个环境上。

对于只需对每个环境做出极少改动的简单项目,上述方法可能很适用。例如,除了镜像外,所有 YAML 清单都完全相同。可以打开每个目录中的 deployment.yaml
文件进行更改,保存后运行 kubectl apply -f .
,就大功告成了。
然而,在大多数情况下,环境之间的差异并不那么简单。请看下面的例子:
-
开发环境通过某些容器命令参数进行调试,而这些参数在 QA 或生产环境中不可用。 -
QA 部署了一些边车,用于运行测试,开发和生产环境不具备这种能力。 -
出于显而易见的原因,生产环境的 RBAC 比其他两个环境的限制性更强。
还有其他更多的可能性:
-
应用变得越来越大,需要其他依赖服务。例如,MySQL 后端和 Redis 缓存服务器。每个服务都有自己的清单、配置设置和环境差异。 -
需要实施 CI/CD 流水线,将应用程序(连同其依赖项)测试、构建和部署到多个环境中。
如你所见,单独使用 kubectl
会变成一场噩梦,这就是我们开始探索更高级工具(特指 Helm 和 Kustomize)的原因。让我们先来探讨一下它们各自是如何应对上述挑战的。
Helm
作为 Kubernetes 的包管理器,Helm 提供了一种以"图表(charts)"形式打包、分发和管理应用程序的方法。Helm chart由模板(template)和值(value)文件集合组成,其中模板定义 Kubernetes 资源(如Deployment、Service、ConfigMap),值文件允许自定义模板值。
这样就可以拥有一组模板,为在不同部署(或环境)中发生变化的参数提供占位符。例如,下面是一个 Helm 部署模板,它从值文件中获取副本数量、镜像名称和标签、容器端口和容器启动参数:
apiVersion: apps/v1
kind: Deployment
metadata:
name: {
{
.Release.Name }}-deployment
spec:
replicas: {
{
.Values.replicaCount }}
selector:
matchLabels:
app: {
{
.Release.Name }}
template:
metadata:
labels:
app: {
{
.Release.Name }}
spec:
containers:
- name: {
{
.Chart.Name }}
image: {
{
.Values.image.repository }}:{
{
.Values.image.tag }}
ports:
- containerPort: {
{
.Values.containerPort }}
args:
- {
{
.Values.startupArguments }}
{
{
和 }}
之间的内容都是动态的。也就是说,在chart部署时,它们会被实际值取代。相应的值文件如下所示:
replicaCount: 3
image:
repository: myapp/image
tag: v1.0.0
containerPort: 8080
startupArguments: arg1 arg2 arg3
注意: .Release.Name
和 .Chart.Name
变量取自 Chart.yaml
,可视为另一个参数来源,用于为集群中的 Kubernetes 组件赋予唯一的名称,这样我们就能在同一个集群中部署同一chart的多个版本。
当 Helm 应用于集群时,Kubernetes API 服务器会收到这些信息:
apiVersion: apps/v1
kind: Deployment
metadata:
name: myapp-deployment
spec:
replicas: 3
selector:
matchLabels:
app: myapp
template:
metadata:
labels:
app: myapp
spec:
containers:
- name: myapp
image: myapp/image:v1.0.0
ports:
- containerPort: 8080
args:
- arg1
- arg2
- arg3
这样就可以为每种环境/用例设置不同的值文件。
对于整个环境的更改,只需修改一次源模板。而对于特定环境的更改,可以应用每个环境对应的值文件。