使用 Kustomize 修改您的 Kubernetes 清单

修改您的 Kubernetes 清单,而不会失去对原始版本内容的控制。
45 位读者喜欢此文。
Ship captain sailing the Kubernetes seas

准备在 Kubernetes 中运行一个新的(或转换一个现有的)应用程序需要大量工作。使用 Kubernetes 需要为您应用程序中不同类型的对象定义和创建多个“清单”。即使是一个简单的微服务也可能需要 deployment.yaml、service.yaml、configmap.yaml 和其他文件。这些 Kubernetes 的声明式 YAML 文件通常被称为“清单”。您可能还需要设置密钥、入口、持久卷和其他支持部分。

一旦创建了这些,您就完成了清单的管理,对吧?嗯,这取决于情况。如果其他人需要使用您的清单,但需要一个略微(或显着)不同的版本会发生什么?或者如果有人想为不同的阶段或环境利用您的清单会发生什么?您需要处理不同用例的重用和更新,而不会丢失原始版本的跟踪。

重用清单的典型方法

重用清单的方法通常相当粗暴。您制作一个副本,以任何适当的方式修改它,并使用不同的名称或位置保存它。此过程适用于直接用例,但事情可能会很快失去同步或变得难以管理。

复制方法

假设您想更改清单以添加新资源或更新清单副本中的值。某人或某事必须监视原始清单,找出差异,然后将它们合并到副本中。

如果其他人制作了自己的副本并更改它们以适应他们的特定用例,问题会变得更糟。内容会很快出现分歧。人们可能会错过对原始清单的重要或重大更新,并且他们最终可能会使用类似文件的令人困惑的变体。

随着时间的推移,情况可能会恶化,并且可能会花费大量时间来尝试保持事物更新。如果制作了副本的副本,您最终可能会得到与原始副本显着不同的东西,甚至会丢失原始副本中的内容。反过来,这会极大地影响可用性和可维护性。

参数化方法

另一种方法是从文件中创建参数化模板。也就是说,通过用可以填充任何值的占位符替换静态、硬编码的值,将清单制作成通用“模板”。值通常在部署时提供,占位符由从命令行传入或从数据文件中读取的值替换。生成的带有填充值的模板被呈现为 Kubernetes 的有效清单。

这是众所周知的工具 Helm 采用的方法。但是,这也存在挑战。删除值并使用占位符从根本上改变了清单,并增加了复杂性,这些清单现在是模板。它们不再可以自己使用;它们需要像 Helm 这样的应用程序或进程来查找或派生并填充值。并且,作为模板,原始文件不再容易被任何查看它们的人解析。

这些模板仍然容易受到文件副本所具有的问题的影响。事实上,当使用模板时,由于副本有更多的占位符和单独存储在其他地方的数据值,问题可能会变得更加复杂。还可以添加连接函数和管道的函数。在某种程度上,这可以将模板变成某种“编程 YAML”文件。在极端情况下,这可能会使文件无法使用且无法读取,除非您使用 Helm 将它们与数据值一起呈现为人们(和 Kubernetes)可以理解和使用的形式。

Kustomize 的替代方法

理想情况下,您应该能够继续以其原始形式使用现有文件,并生成变体,而无需进行永久更改或副本,这些副本很容易与原始副本和彼此发散。并且您会保持版本之间的差异尽可能小和简单。

这些是 Kustomize 方法的基本原则。它是一个 Apache 2.0 许可的工具,通过在现有清单之上“覆盖”声明式规范来生成清单的自定义版本。“声明式”是指在 Kubernetes 中描述资源的标准方式:声明您希望资源成为什么样子以及如何外观和行为,与“命令式”形成对比,“命令式”定义了创建它的过程。

“覆盖”描述了将单独的文件分层(或“堆叠在顶部”)在一起以创建更改版本的过程。Kustomize 将特定类型的覆盖应用于原始清单。要在呈现的版本中进行的更改在名为 kustomization.yaml 的单独专用文件中声明,同时保持原始文件不变。

Kustomize 读取 kustomization.yaml 文件以驱动其行为。kustomization.yaml 文件的一个部分,标题为 Resources,列出了原始清单的名称(以及可选的路径)作为更改的基础。加载资源后,Kustomize 应用覆盖并呈现结果。

您可以将其视为将指定的自定义“叠加到”原始清单的临时副本之上。这些操作会生成清单的“自定义”副本,如果需要,可以通过 kubectl apply 命令直接将其馈送到 Kubernetes 中。

Kustomize 中内置的函数类型通过一组简单的声明式规则“转换”您的 Kubernetes 清单。这些规则集称为“转换器”。

最简单的转换器将一个公共标识符应用于同一组资源,如图 1 所示。

A simple example

图 1:一个简单的例子 (Brent Laster, CC BY-SA 4.0)

此示例具有一个简单的目录,其中包含一组 YAML 文件,用于带有 MySQL 后端的 Web 应用程序。这些文件是

  • roar-web-deploy.yaml 是应用程序 Web 应用程序部分的 Kubernetes 部署清单。
  • roar-web-svc.yaml 是应用程序 Web 应用程序部分的 Kubernetes 服务清单。
  • kustomization.yaml 是 Kustomize 输入文件,用于声明要对清单进行的转换类型。

在图 1 中的 kustomization.yaml 文件中,commonLabels 部分(底部中心)是转换器的示例。顾名思义,此转换器的目的是在转换后使指定标签在文件中通用。

kustomization.yaml 文件还包括一个 resources 部分,该部分列出了要包含并可能自定义或转换的文件(在图 2 中突出显示)。

Resources section in kustomization.yaml

图 2:kustomization.yaml 中的 Resources 部分 (Brent Laster, CC BY-SA 4.0)

kustomization.yaml 文件是关于您要更改的清单以及您要如何更改它们的简单声明集;它是资源加上自定义的规范。当您运行 kustomize build 命令时,修改就会发生。构建操作读取 kustomization.yaml 文件,拉入资源,并将转换器应用于每个文件。此示例拉入两个 roar-web YAML 文件,生成它们的副本,并在每个文件的元数据部分中添加请求的标签。

默认情况下,文件不会保存在任何地方,并且原始文件不会被覆盖。您可以将“转换后的”内容直接通过管道传输到 kubectl apply 命令,或者如果您愿意,可以重定向并保存到另一个文件。但是,通常不建议保存生成的文件,因为它们很容易与源失去同步。您可以将 kustomize build 步骤的输出视为生成的内容。

相反,您应该保存相关的原始文件和 kustomization.yaml 文件。由于 kustomization.yaml 文件拉入原始文件并转换它们以进行呈现,因此它们可以保持不变并以其原始形式重用。

其他转换

Kustomize 提供了一组转换,您可以将其应用于一组资源。这些包括

  • commonLabel 将一个公共标签(name:value)添加到每个 Kubernetes (K8s) 资源。
  • commonAnnotations 向所有 K8s 资源添加注释。
  • namePrefix 向所有资源名称添加一个公共前缀。

图 3 显示了其他类型的常见更改的示例。

commonAnnotations and namePrefix transformers

图 3:commonAnnotations 和 namePrefix 转换器 (Brent Laster, CC BY-SA 4.0)

镜像转换器

顾名思义,镜像转换器会生成一个清单版本,其中包含镜像规范(例如容器或 initcontainer)的不同 newnamenewTag。名称值必须与原始资源中的镜像值匹配。

图 4 显示了一个带有镜像更改的 kustomization.yaml 文件的示例。

kustomization.yaml file for an image transformer

图 4:镜像转换器的 kustomization.yaml 文件 (Brent Laster, CC BY-SA 4.0)

虽然进行这些类型的转换很有用,但更具战略意义的功能是从一组资源为不同的环境创建单独的版本。在 Kustomize 中,这些称为“变体”。

变体

在 Kubernetes 中,通常需要同一组资源及其清单的多种变体。一个简单的例子是在一组 Kubernetes 资源之上构建,为产品开发的不同阶段创建不同的变体,例如 dev、stage 和 prod。

为了方便这些类型的更改,Kustomize 使用了“覆盖 (overlays)”和“基础 (bases)”的概念。“基础”声明了变体共有的内容,而“覆盖”声明了变体之间的差异。基础和覆盖都由 kustomization.yaml 文件表示。图 5 包含此结构的一个示例。它在树的根目录中包含原始资源清单和基础 kustomization.yaml 文件。kustomization.yaml 文件将变体定义为 prod 和 stage 子目录中的一组覆盖。

base/overlay approach

图 5:利用基础/覆盖方法的一个结构 (Brent Laster, CC BY-SA 4.0)

变体还可以应用补丁。Kustomize 中的补丁是 K8s 对象的部分规范或“增量”。它们描述了在更改后某个部分应该是什么样子,以及当 Kustomize 渲染更新版本时应该如何修改它。它们代表了一种更“外科手术式”的方法,用于定位资源中的一个或多个特定部分。

下一组图演示了如何利用 Kustomize 的补丁功能。回到前面的一个例子,您有一组核心资源文件(一个部署和一个服务)以及与它们关联的 kustomization.yaml 文件(图 6a 和 6b)。应用程序有两个部分:数据库部分和 Web 应用程序部分。此示例中的补丁重命名了数据库服务。

Patching database content

Renaming database service

图 6a 和 6b:应用程序结构和要打补丁的服务定义 (Brent Laster, CC BY-SA 4.0)

图 7a 到 7d 突出了与服务关联的 kustomization.yaml 文件中的补丁部分。第 12 行定义了补丁的类型,在本例中为“replace”。第 13 行和第 14 行标识了 YAML 层次结构中的“location”,以查找要打补丁的值和要使用的替换值。第 15-17 行标识了您希望更改的 K8s 资源中的特定项目类型。

Patch block

图 7a:kustomization.yaml 文件中的整体补丁块 (Brent Laster, CC BY-SA 4.0)

Patch to apply

图 7b:要应用的补丁类型 (Brent Laster, CC BY-SA 4.0)

Target location

图 7c:结构中要定位的位置 (Brent Laster, CC BY-SA 4.0)

value to modify

图 7d:要修改的值 (Brent Laster, CC BY-SA 4.0)

当您针对这组文件执行 kustomize build 命令时,Kustomize 首先找到您感兴趣的 K8s 资源 - 服务 - 然后找到补丁块中标识的路径 (metadata.name.<value>)。然后,它渲染一个规范版本,并将值 roar-db 替换为 mysql。图 8a 到 8f 说明了这个过程。

Locating the initial named object

Locating the initial named object

图 8a 和 8b:定位初始命名的对象(kind)(Brent Laster, CC BY-SA 4.0)

Locating the target section in the hierarchy

Identifying the path

图 8c 和 8d:定位层次结构中的特定部分 (Brent Laster, CC BY-SA 4.0)

Substituting the desired value

Rendering the result

图 8e-8f:替换所需的值并渲染结果 (Brent Laster, CC BY-SA 4.0)

Kustomize 支持通过“战略合并补丁”(如上所示)或通过 JSON 补丁进行修补。

Kustomization 层次结构

补丁场景示例说明了使用 Kustomize 时的另一个有用概念:项目层次结构中的多个 kustomization.yaml 文件。此示例项目有两个子项目:一个用于数据库,另一个用于 Web 应用程序。

数据库部分具有一个自定义项,可以使用补丁功能更新服务名称,如上所述。

Web 部分只是有一个文件来包含资源。

在基础级别,有一个 kustomization.yaml 文件,它从项目的两个部分提取资源,以及一个简单的文件来创建命名空间。它还将一个通用标签应用于不同的元素。

生成器

Kustomize 还包括“生成器”,以便在更新不同资源时自动更新相关的 Kubernetes 资源。生成器通过生成一个随机标识符并将其用作对象名称的公共后缀来建立两个资源之间的连接。

这对于 configmap 和 secret 很有用:如果更改了其中的数据,则将自动重新生成和更新相应的部署。图 9 显示了 Kustomize 生成器的示例规范。

Kustomize generator spec

图 9a:Kustomize 生成器的示例规范 (Brent Laster, CC BY-SA 4.0)

通过 Kustomize 构建操作运行后,生成的新对象将应用生成的名称并包含在规范中,如图 10 所示。

Objects and specs from a Kustomize generator

图 9b:运行 kustomize build 会将哈希添加到生成项目的引用中 (Brent Laster, CC BY-SA 4.0)

然后,如果您更改与生成器关联的 configmap(如图 11 所示)...

Objects and specs from Kustomize generator

… Kustomize 将生成新的值,这些值已合并到规范和对象中(图 12a)。然后,如果您获取构建输出并应用它,则将更新部署,因为关联的 configmap 已更新(图 12b)。

Changes after configMapGenerator update and Kustomize build

图 9c 和 9d:如果再次进行构建,则 configMapGenerator 规范中的更改会更改哈希 (Brent Laster, CC BY-SA 4.0)

Deployment changes after configmap changes

图 9e:哈希更改导致的更新 (Brent Laster, CC BY-SA 4.0)

总而言之,对构建结果执行 kubectl apply 操作会导致 configmap 和任何依赖项引用已更新的 configmap 的新哈希值,并在集群中更新它们。

Kubernetes 集成

Kustomize 已集成到 Kubernetes 中。有两个集成点

  1. 要查看目录中带有 kustomization 文件的资源,您可以运行

    $ kubectl kustomize < directory >
  2. 要应用这些资源,您可以在 kubectl apply 上使用 -k 选项

    $ kubectl apply -k < directory >

如果您使用的是旧版本的 Kubernetes,则它可能没有更新版本的 Kustomize。在大多数情况下,这不是问题,除非您需要当前版本的 Kustomize 中提供的特定功能或错误修复。

结论

Kustomize 是另一种促进 Kubernetes 清单重用的方法。与大多数其他方法不同,它保持原始文件不变,并使用其 build 命令动态生成更改的版本。要进行的更改在 kustomization.yaml 文件中定义,可以包括添加各种常见属性、在原始内容之上进行修补,甚至生成唯一的标识符以将 configmap 和部署之类的项目联系在一起。

总而言之,一旦您熟悉了 Kustomize 的各种文件转换方法的设置和功能,它就提供了一种独特而简单的方式来交付 Kubernetes 清单的变体。它与 Helm 采用的传统重用方法有很大不同,Helm 是另一种主要的重用工具。我将在以后的文章中探讨这些差异。

接下来要阅读的内容
标签
User profile image.
Brent Laster 是一位全球培训师、演讲者,也是书籍 Professional Git 的作者和

评论已关闭。

Creative Commons License本作品根据知识共享署名-相同方式共享 4.0 国际许可协议获得许可。
© . All rights reserved.