<article class=“article fmt article-content”><blockquote><em>Helm和Kustomize都是风行的Kubernetes集群部署管理工具,本文比拟了两者的优缺点,不便读者依据我的项目理论状况采纳适宜的计划。原文: Helm vs Kustomize: why, when, and how</em></blockquote><p></p><h4>挑战</h4><p>开始探讨之前,先来看看为什么要应用 Helm 或 Kustomize。</p><p><strong>这么多环境,这么多 YAML 文件!</strong></p><p>Kubernetes 帮忙咱们非常容易的为不同用例创立不同的环境,能够在同一个集群甚至多个集群上应用命名空间,能够托管开发、测试、QA、UAT、预发、生产……等等不同的环境。但问题是:如何治理所有这些环境?</p><p>第一种也是最间接的办法是创立雷同manifest的正本,并为每个正本命名。也就是说,把源文件复制粘贴到每个环境上。</p><p></p><p>对于只需对每个环境做出极少改变的简略我的项目,上述办法可能很实用。例如,除了镜像外,所有 YAML 清单都完全相同。能够关上每个目录中的 <code>deployment.yaml</code> 文件进行更改,保留后运行 <code>kubectl apply -f .</code>,就功败垂成了。</p><p>然而,在大多数状况下,环境之间的差别并不那么简略。请看上面的例子:</p><ul><li>开发环境通过某些容器命令参数进行调试,而这些参数在 QA 或生产环境中不可用。</li><li>QA 部署了一些边车,用于运行测试,开发和生产环境不具备这种能力。</li><li>出于不言而喻的起因,生产环境的 RBAC 比其余两个环境的限制性更强。</li></ul><p>还有其余更多的可能性:</p><ul><li>利用变得越来越大,须要其余依赖服务。例如,MySQL 后端和 Redis 缓存服务器。每个服务都有本人的清单、配置设置和环境差别。</li><li>须要施行 CI/CD 流水线,将应用程序(连同其依赖项)测试、构建和部署到多个环境中。</li></ul><p>如你所见,独自应用 <code>kubectl</code> 会变成一场噩梦,这就是咱们开始摸索更高级工具(特指 Helm 和 Kustomize)的起因。让咱们先来探讨一下它们各自是如何应答上述挑战的。</p><h4>Helm</h4><p>作为 Kubernetes 的包管理器,Helm 提供了一种以"图表(charts)“模式打包、散发和管理应用程序的办法。Helm chart由模板(template)和值(value)文件汇合组成,其中模板定义 Kubernetes 资源(如Deployment、Service、ConfigMap),值文件容许自定义模板值。</p><p>这样就能够领有一组模板,为在不同部署(或环境)中发生变化的参数提供占位符。例如,上面是一个 Helm 部署模板,它从值文件中获取正本数量、镜像名称和标签、容器端口和容器启动参数:</p><pre><code class=“yaml”>apiVersion: apps/v1kind: Deploymentmetadata: name: {{ .Release.Name }}-deploymentspec: 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 }}</code></pre><p><code>{{</code> 和 <code>}}</code> 之间的内容都是动静的。也就是说,在chart部署时,它们会被理论值取代。相应的值文件如下所示:</p><pre><code>replicaCount: 3image: repository: myapp/image tag: v1.0.0containerPort: 8080startupArguments: arg1 arg2 arg3</code></pre><p><strong>留神:</strong> <code>.Release.Name</code> 和 <code>.Chart.Name</code> 变量取自 <code>Chart.yaml</code>,可视为另一个参数起源,用于为集群中的 Kubernetes 组件赋予惟一的名称,这样咱们就能在同一个集群中部署同一chart的多个版本。</p><p>当 Helm 利用于集群时,Kubernetes API 服务器会收到这些信息:</p><pre><code class=“yaml”>apiVersion: apps/v1kind: Deploymentmetadata: name: myapp-deploymentspec: 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</code></pre><p>这样就能够为每种环境/用例设置不同的值文件。</p><p>对于整个环境的更改,只需批改一次源模板。而对于特定环境的更改,能够利用每个环境对应的值文件。</p><p></p><h4>Kustomize</h4><p>Kustomize 的指标是一样的,但不应用模板。相同,它在一个目录中保留<strong>残缺</strong>版本的 YAML 文件。依照常规,这个文件被称为 <code>base</code>,但也能够依据本人的爱好给它命名。而后能够为每个环境/场景/用例创立一个目录(或目录树),每个目录都须要一个名为 <code>kustomization.yaml</code> 的 YAML 文件,该文件的目标是告知 Kustomize 应该思考哪些 manifest 文件,以及须要对这些文件进行哪些批改。上面通过例子来阐明这,看看如何应用 Kustomize 得出与 Helm 雷同的后果。</p><p>首先创立一个目录构造:</p><pre><code>myapp/├── kustomization.yaml├── base│ └── deployment.yaml└── overlay └── deployment.yaml</code></pre><p><code>myapp/kustomization.yaml</code> 的内容如下:</p><pre><code class=“yaml”>apiVersion: kustomize.config.k8s.io/v1beta1kind: Kustomizationresources: - base/deployment.yamlpatchesStrategicMerge: - overlay/deployment.yaml</code></pre><p><code>base/deployment.yaml</code> 看起来像这样:</p><pre><code class=“yaml”>apiVersion: apps/v1kind: Deploymentmetadata: name: myapp-deploymentspec: replicas: 3 template: spec: containers: - name: myapp image: myapp/image:v1.0.0 ports: - containerPort: 8080</code></pre><p>请留神,这是一个齐全无效的 YAML,如果须要,也能够按原样利用。</p><p>要更改该部署以适应环境需要,能够应用 <code>overlay/deployment.yaml</code> 文件:</p><pre><code class=“yaml”>apiVersion: apps/v1kind: Deploymentmetadata: name: myapp-deploymentspec: template: spec: containers: - name: myapp args: - arg1 - arg2 - arg3</code></pre><p>这样,发送到 Kubernetes API 服务器的文件就变成了</p><pre><code class=“yaml”>apiVersion: apps/v1kind: Deploymentmetadata: name: myapp-deploymentspec: replicas: 3 template: spec: containers: - name: myapp image: myapp/image:v1.0.0 ports: - containerPort: 8080 args: - arg1 - arg2 - arg3</code></pre><p>把同样的机制利用到三个环境中,目录构造能够是这样的:</p><pre><code>myapp/├── kustomization.yaml├── base│ └── deployment.yaml├── overlays│ ├── dev│ │ └── kustomization.yaml│ ├── qa│ │ └── kustomization.yaml│ └── prod│ └── kustomization.yaml└── patches └── deployment-patch.yaml</code></pre><p>如果须要对整个环境进行更改,只需在 <code>base/deployment</code> 文件中进行一次更改,就会流传到所有中央。针对特定环境的更改在相应环境的自定义文件中实现。</p><p></p><p>当初咱们晓得了每种工具是如何应答挑战的,上面来看看其优缺点。</p><p></p><h4>第1回合:装置和设置</h4><p>须要在服务器上安装 Helm,请参阅Five ways to install Helm。</p><p>尽管能够从 https://kubectl.docs.kubernetes.io/installation/kustomize/ 下载独自的 Kustomize 软件包,但从 1.14 版开始,就曾经与 kubectl 捆绑在一起了。因而,除非你的零碎中没有(或不须要)kubectl,否则只需运行 <code>kubectl -k</code> 即可调用 Kustomize。</p><p><em>优胜者:Kustomize</em></p><h4>第2回合:软件包治理</h4><p>因为 Helm 顾名思义是软件包管理器,它提供的软件仓库能够搜寻和下载特定版本的chart,也能够在同一集群中同时装置多个版本的chart。Kustomize 不会将文件打包成可部署的单元,不过咱们能够通过 Kustomize 手动实现同样的成果(Git 公布是其中一种抉择)。不过,Helm 提供了开箱即用的性能。</p><p><em>优胜者:Helm</em></p><h4>第3回合:模板化能力</h4><p>Helm 齐全依赖 Go 模板,此外还从 Sprig库中借用了一些函数,使模板性能更加多样化。Kustomize 齐全不应用模板,而是在将 YAML 清单利用到集群之前,应用overlay和patch对其进行即时批改。</p><p>Go 是一种成熟的编程语言,提供了弱小的文本操作技术。例如</p><ul><li>循环和条件式,如(<code>range</code>)和条件式(<code>if</code>、<code>else</code>、<code>with</code>),这在生成反复资源或依据用户提供的值进行决策时十分有用。</li><li>模板性能通过 Sprig 库实现,该库提供了各种性能,如<code>default</code>、<code>pick</code>、<code>omit</code>、<code>trim</code>、<code>upper</code>、<code>lower</code>、<code>quote</code>等。</li></ul><p>而 Kustomize 却无奈做到这一点。不过,它也有一些小技巧。例如</p><ul><li>ConfigMaps 和 Secrets 的生成器。这些都是申明式指定的,Kustomize 会在构建最终 YAML 时生成资源。</li><li>Variants(变体):Kustomize 应用overlay层来治理同一应用程序的不同变体,这有助于治理不同的环境(开发、预发、生产)。</li><li>用于更新资源字段的转换器(transformers)。常见的转换器包含为资源名称增加前缀/后缀、更新标签和正文以及更新命名空间。转换器能够有抉择的利用于不同的资源,从而提供高度的管制。</li></ul><p><em>优胜者:不定(取决于所谋求的定制化水平)</em></p><h4>第4回合:调试</h4><p>很显著,在将 YAML 文件利用到群集之前,须要测试这些文件是否存在谬误。YAML 应用空格和缩进来定义对象、列表和其余组件,一个不正确的缩进可能会毁掉整个部署。Helm 和 Kustomize 都容许咱们在将 YAML 清单利用到群集之前就"查看"这些清单。</p><p>Kustomize 有<code>build</code>命令,在将所有patch、overlay、转换器(transformers)等利用到一个蕴含整个无效负载的大文件后,会生成最终的清单。不过,也能够运行 <code>kubectl apply -k –dry-run</code> 来依赖 API 服务器验证 YAML 清单。</p><p>Helm有几种办法能够做同样的事件:</p><p>能够应用 <code>helm template</code> 在 YAML 清单发送到 API 服务器之前对其进行渲染,还能够应用 <code>helm lint</code> 依据最佳实际查看chart。</p><p>应用 <code>helm install –dry-run</code> (或 <code>helm upgrade</code> )还能够针对 API 服务器测试清单。也就是说,即便 YAML 在语法上是正确的,API 服务器也可能因为其余起因而拒绝接受(例如,短少 CRD 或接入控制器)。Helm 容许咱们在将无效负载利用到 Kubernetes 之前捕捉这些谬误,从而防止卸载和重新安装有问题的chart。</p><p><em>优胜者:不定</em></p><h4>第5回合:版本控制和回滚</h4><p>如前所述,Helm 可能同时在同一集群中部署同一chart的多个版本。Helm 将部署版本称为<code>revision</code>(修订版),并保留了部署到群集的revision版本历史记录,容许咱们在须要时回滚到之前的revision版本。尽管 Kustomize 也能够做同样的事件,但过程简单且容易出错。</p><p><em>优胜者:Helm</em></p><h4>第6回合:Secrets治理</h4><p>许多状况下,咱们须要存储一些敏感信息,作为应用程序部署的一部分。比方 API 密钥、用户凭证、令牌等。在所有状况下,Kubernetes 都提供了 Secret 对象,能够在其中保留机密信息。让咱们看看每个工具是如何解决 Secret 创立的:</p><h5>Helm</h5><p>将隐衷数据存储在 <code>values.yaml</code> 文件中,并应用 <code>b64enc</code> 函数在Secret YAML 清单中将其即时转换为 base64。例如</p><pre><code class=“yaml”># values.yamldatabase: username: admin password: secret</code></pre><p>以及</p><pre><code class=“yaml”># templates/secrets.yamlapiVersion: v1kind: Secretmetadata: name: db-secrettype: Opaquedata: username: {{ .Values.database.username | b64enc }} password: {{ .Values.database.password | b64enc }}</code></pre><p>由此产生的 YAML 能够是这样的</p><pre><code class=“yaml”>—# Source: my-chart/templates/secrets.yamlapiVersion: v1kind: Secretmetadata: name: db-secrettype: Opaquedata: username: YWRtaW4= password: c2VjcmV0</code></pre><p>这里的问题不言而喻: 须要将 Values 文件(其中蕴含纯文本证书)提交到版本控制中。一个可行的解决方案是创立独自的 Values 文件来存储敏感信息,并通过将其增加到 <code>.gitignore</code> 文件来防止将其蕴含在 git 仓库中。不过这样须要治理多个Values文件,又减少了复杂性。</p><h5>Kustomize</h5><p>能够应用 Kustomize <code>secretGenerator</code> 主动从纯文件创建Secret YAML。例如,能够创立如下凭证文件:</p><pre><code># Create the secret fileecho -n ‘admin’ > ./username.txtecho -n ‘secret’ > ./password.txt</code></pre><p>Kustomization 文件看起来会像这样:</p><pre><code class=“yaml”># kustomization.yamlsecretGenerator:- name: db-secret files: - username.txt - password.txt</code></pre><p>由此产生的清单将是</p><pre><code class=“yaml”>apiVersion: v1kind: Secretmetadata: name: db-secret-8h5h97g6k8type: Opaquedata: username.txt: YWRtaW4= password.txt: c2VjcmV0</code></pre><p>尽管 <code>username.txt</code> 和 <code>password.txt</code> 也会被增加到 <code>.gitignore</code>,但除非想批改凭据,否则无需在每次部署时都从新创立它们(在运行 <code>git clone</code> 或 <code>git pull</code> 后)。</p><p>显然,用 Base64 存储敏感信息和应用纯文本是一样的,因为 Base64 是一种编码格局,而不是加密办法。也就是说,任何人都能够应用命令行工具将 Base64 字符串转换为原始格局。因而,最佳实际要求咱们对secret数据进行加密。Helm 和 Kustomize 都能够应用第三方插件实现这一性能。</p><p>例如,如果应用 Kustomize,能够应用 kustomize-secret-generator 插件,它能让你从 Google Cloud Secret Manager、AWS Secrets Manager 或 HashiCorp 获取secret。这样做的目标是将secret以加密模式存储在其中某个反对的平台中。须要时,用户能够依附插件获取secret、解密并将其利用于群集。上面演示了 Kustomize 如何利用 HashiCorp 的 Vault 实现这一性能:</p><pre><code class=“yaml”># kustomization.yamlsecretGenerator:- name: db-secret kvSources: - pluginType: vault name: my-vault namespace: default path: secret/data/my-service key: db-password</code></pre><p>尽管 Helm 有 Helm-Secrets 插件,但不提供从其余平台获取secret的本地反对。相同,它应用 Mozilla SOPS 进行加密。密钥自身能够存储在各种密钥管理系统中,如 AWS KMS、GCP KMS、Azure Key Vault 和 PGP。例如</p><pre><code class=“bash”>helm secrets enc secrets.yaml</code></pre><p>上述命令对 Secret 模板进行了动态加密,而后能够间接提交到 Git。当咱们在另一台机器上从新获取时,须要先解密,而后再将其利用到 Kubernetes:</p><pre><code class=“bash”>helm secrets dec secrets.yaml</code></pre><p><em>优胜者:Kustomize</em></p><h4>第7回合:解决超大型应用程序</h4><p>如果应用程序有数百个清单,蕴含数千行内容,那么应用 Helm 模板解决这些清单很快就会变得力不从心,这里 Kustomize 可能是更好的抉择。</p><p>例如驰名的基于 Kubernetes 的机器学习平台 Kubeflow,正在应用 Kustomize 作为部署工具。起因是该平台过于宏大,而且有许多依赖项须要按特定程序部署。为了解释的更分明,这是须要部署的资源的一个子集(咱们甚至还没有思考patch或overlay):</p><p></p><p><em>优胜者:Kustomize</em></p><h4>第8回合:与 CI/CD 工具集成</h4><p>Helm 已被宽泛采纳,被许多 CI/CD 工具所反对。对 Kustomize 的反对也在减少,但并不宽泛。</p><p><em>优胜者:Helm</em></p><h4>第9回合(最初一轮):次级组成部分和依赖关系</h4><p>Helm 内置反对依赖关系解决。如果chart须要一些先决条件(数据库、缓存服务器、OAuth 服务等),能够轻松的在 <code>Chart.yaml</code> 文件中将它们增加为<code>dependencies</code>(依赖项)。Helm 将确保在运行主chart前下载并提供这些先决条件,并且能够抉择所需版本。而 Kustomize 则齐全由用户手动解决。</p><p><em>优胜者:Helm</em></p><p><strong>获胜者是</strong></p><p></p><p><strong>Helm!</strong></p><p>不过,这里没有输赢之分。每种工具都有本人的优缺点,齐全取决于我的项目的指标、规模、须要部署的环境数量以及复杂程度。这场"对决"的目标只是展现这两种工具之间的区别,而不是宣扬其中一种优于另一种。</p><p>尽管如此,许多我的项目事实上会在同一个代码库中同时应用这两种工具。不过,本文篇幅过长,无奈探讨 Kustomize 的这一性能。不过,能够通过以下链接查看文档:https://github.com/kubernetes-sigs/kustomize/blob/master/examples/chart.md</p><h4>论断</h4><p>Helm 和 Kustomize 的指标是统一的:以 DevOps 的形式更轻松的部署蕴含许多相互依赖的 YAML 清单的大型应用程序。不过,每种工具都有其优于其余工具的用例。在本文中,咱们试图让这两种工具面对面比拟,看看它们的优缺点。在下一个我的项目中抉择应用 Helm 还是 Kustomize 很大水平上取决于多个因素,但咱们心愿本文能帮忙你做出正确的决定。</p><p></p><p>心愿这篇对于 Helm 和 Kustomize 的文章对你有所帮忙。如果深刻理解并精通 Helm,强烈推荐 Udemy 上的课程:Helm - Kubernetes 包管理器实际。该课程适宜各种程度的学习者,蕴含大量实际示例和精辟技巧。</p><hr/><blockquote>你好,我是俞凡,在Motorola做过研发,当初在Mavenir做技术工作,对通信、网络、后端架构、云原生、DevOps、CICD、区块链、AI等技术始终保持着浓重的趣味,平时喜爱浏览、思考,置信继续学习、一生成长,欢送一起交流学习。为了不便大家当前能第一工夫看到文章,请敌人们关注公众号"DeepNoMind”,并设个星标吧,如果能一键三连(转发、点赞、在看),则能给我带来更多的反对和能源,激励我继续写下去,和大家独特成长提高!</blockquote><p>本文由mdnice多平台公布</p></article>