使用 Kustomize 对 Kubernetes 对象进行声明式管理

Kustomize 是一个独立的工具,用来通过 kustomization 文件 定制 Kubernetes 对象。

从 1.14 版本开始,kubectl 也开始支持使用 kustomization 文件来管理 Kubernetes 对象。 要查看包含 kustomization 文件的目录中的资源,执行下面的命令:

kubectl kustomize <kustomization_directory> 

要应用这些资源,使用 --kustomize-k 参数来执行 kubectl apply

kubectl apply -k <kustomization_directory> 

准备开始

安装 kubectl

你必须拥有一个 Kubernetes 的集群,且必须配置 kubectl 命令行工具让其与你的集群通信。 建议运行本教程的集群至少有两个节点,且这两个节点不能作为控制平面主机。 如果你还没有集群,你可以通过 Minikube 构建一个你自己的集群,或者你可以使用下面的 Kubernetes 练习环境之一:

要获知版本信息,请输入 kubectl version.

Kustomize 概述

Kustomize 是一个用来定制 Kubernetes 配置的工具。它提供以下功能特性来管理应用配置文件:

  • 从其他来源生成资源
  • 为资源设置贯穿性(Cross-Cutting)字段
  • 组织和定制资源集合

生成资源

ConfigMap 和 Secret 包含其他 Kubernetes 对象(如 Pod)所需要的配置或敏感数据。 ConfigMap 或 Secret 中数据的来源往往是集群外部,例如某个 .properties 文件或者 SSH 密钥文件。 Kustomize 提供 secretGeneratorconfigMapGenerator,可以基于文件或字面值来生成 Secret 和 ConfigMap。

configMapGenerator

要基于文件来生成 ConfigMap,可以在 configMapGeneratorfiles 列表中添加表项。 下面是一个根据 .properties 文件中的数据条目来生成 ConfigMap 的示例:

# 生成一个 application.properties 文件 cat <<EOF >application.properties FOO=Bar EOF  cat <<EOF >./kustomization.yaml configMapGenerator: - name: example-configmap-1  files:  - application.properties EOF 

所生成的 ConfigMap 可以使用下面的命令来检查:

kubectl kustomize ./ 

所生成的 ConfigMap 为:

apiVersion: v1 data:  application.properties: |  FOO=Bar kind: ConfigMap metadata:  name: example-configmap-1-8mbdf7882g 

要从 env 文件生成 ConfigMap,请在 configMapGenerator 中的 envs 列表中添加一个条目。 下面是一个用来自 .env 文件的数据生成 ConfigMap 的例子:

# 创建一个 .env 文件 cat <<EOF >.env FOO=Bar EOF  cat <<EOF >./kustomization.yaml configMapGenerator: - name: example-configmap-1  envs:  - .env EOF 

可以使用以下命令检查生成的 ConfigMap:

kubectl kustomize ./ 

生成的 ConfigMap 为:

apiVersion: v1 data:  FOO: Bar kind: ConfigMap metadata:  name: example-configmap-1-42cfbf598f 

ConfigMap 也可基于字面的键值偶对来生成。要基于键值偶对来生成 ConfigMap, 在 configMapGeneratorliterals 列表中添加表项。下面是一个例子, 展示如何使用键值偶对中的数据条目来生成 ConfigMap 对象:

cat <<EOF >./kustomization.yaml configMapGenerator: - name: example-configmap-2  literals:  - FOO=Bar EOF 

可以用下面的命令检查所生成的 ConfigMap:

kubectl kustomize ./ 

所生成的 ConfigMap 为:

apiVersion: v1 data:  FOO: Bar kind: ConfigMap metadata:  name: example-configmap-2-g2hdhfc6tk 

要在 Deployment 中使用生成的 ConfigMap,使用 configMapGenerator 的名称对其进行引用。 Kustomize 将自动使用生成的名称替换该名称。

这是使用生成的 ConfigMap 的 deployment 示例:

# 创建一个 application.properties 文件 cat <<EOF >application.properties FOO=Bar EOF  cat <<EOF >deployment.yaml apiVersion: apps/v1 kind: Deployment metadata:  name: my-app  labels:  app: my-app spec:  selector:  matchLabels:  app: my-app  template:  metadata:  labels:  app: my-app  spec:  containers:  - name: app  image: my-app  volumeMounts:  - name: config  mountPath: /config  volumes:  - name: config  configMap:  name: example-configmap-1 EOF  cat <<EOF >./kustomization.yaml resources: - deployment.yaml configMapGenerator: - name: example-configmap-1  files:  - application.properties EOF 

生成 ConfigMap 和 Deployment:

kubectl kustomize ./ 

生成的 Deployment 将通过名称引用生成的 ConfigMap:

apiVersion: v1 data:  application.properties: |  FOO=Bar kind: ConfigMap metadata:  name: example-configmap-1-g4hk9g2ff8 --- apiVersion: apps/v1 kind: Deployment metadata:  labels:  app: my-app  name: my-app spec:  selector:  matchLabels:  app: my-app  template:  metadata:  labels:  app: my-app  spec:  containers:  - image: my-app  name: app  volumeMounts:  - mountPath: /config  name: config  volumes:  - configMap:  name: example-configmap-1-g4hk9g2ff8  name: config 

secretGenerator

你可以基于文件或者键值偶对来生成 Secret。要使用文件内容来生成 Secret, 在 secretGenerator 下面的 files 列表中添加表项。 下面是一个根据文件中数据来生成 Secret 对象的示例:

# 创建一个 password.txt 文件 cat <<EOF >./password.txt username=admin password=secret EOF  cat <<EOF >./kustomization.yaml secretGenerator: - name: example-secret-1  files:  - password.txt EOF 

所生成的 Secret 如下:

apiVersion: v1 data:  password.txt: dXNlcm5hbWU9YWRtaW4KcGFzc3dvcmQ9c2VjcmV0Cg== kind: Secret metadata:  name: example-secret-1-t2kt65hgtb type: Opaque 

要基于键值偶对字面值生成 Secret,先要在 secretGeneratorliterals 列表中添加表项。下面是基于键值偶对中数据条目来生成 Secret 的示例:

cat <<EOF >./kustomization.yaml secretGenerator: - name: example-secret-2  literals:  - username=admin  - password=secret EOF 

所生成的 Secret 如下:

apiVersion: v1 data:  password: c2VjcmV0  username: YWRtaW4= kind: Secret metadata:  name: example-secret-2-t52t6g96d8 type: Opaque 

与 ConfigMap 一样,生成的 Secret 可以通过引用 secretGenerator 的名称在 Deployment 中使用:

# 创建一个 password.txt 文件 cat <<EOF >./password.txt username=admin password=secret EOF  cat <<EOF >deployment.yaml apiVersion: apps/v1 kind: Deployment metadata:  name: my-app  labels:  app: my-app spec:  selector:  matchLabels:  app: my-app  template:  metadata:  labels:  app: my-app  spec:  containers:  - name: app  image: my-app  volumeMounts:  - name: password  mountPath: /secrets  volumes:  - name: password  secret:  secretName: example-secret-1 EOF  cat <<EOF >./kustomization.yaml resources: - deployment.yaml secretGenerator: - name: example-secret-1  files:  - password.txt EOF 

generatorOptions

所生成的 ConfigMap 和 Secret 都会包含内容哈希值后缀。 这是为了确保内容发生变化时,所生成的是新的 ConfigMap 或 Secret。 要禁止自动添加后缀的行为,用户可以使用 generatorOptions。 除此以外,为生成的 ConfigMap 和 Secret 指定贯穿性选项也是可以的。

cat <<EOF >./kustomization.yaml configMapGenerator: - name: example-configmap-3  literals:  - FOO=Bar generatorOptions:  disableNameSuffixHash: true  labels:  type: generated  annotations:  note: generated EOF 

运行 kubectl kustomize ./ 来查看所生成的 ConfigMap:

apiVersion: v1 data:  FOO: Bar kind: ConfigMap metadata:  annotations:  note: generated  labels:  type: generated  name: example-configmap-3 

设置贯穿性字段

在项目中为所有 Kubernetes 对象设置贯穿性字段是一种常见操作。 贯穿性字段的一些使用场景如下:

  • 为所有资源设置相同的名字空间
  • 为所有对象添加相同的前缀或后缀
  • 为对象添加相同的标签集合
  • 为对象添加相同的注解集合

下面是一个例子:

# 创建一个 deployment.yaml cat <<EOF >./deployment.yaml apiVersion: apps/v1 kind: Deployment metadata:  name: nginx-deployment  labels:  app: nginx spec:  selector:  matchLabels:  app: nginx  template:  metadata:  labels:  app: nginx  spec:  containers:  - name: nginx  image: nginx EOF  cat <<EOF >./kustomization.yaml namespace: my-namespace namePrefix: dev- nameSuffix: "-001" labels:  - pairs:  app: bingo  includeSelectors: true commonAnnotations:  oncallPager: 800-555-1212 resources: - deployment.yaml EOF 

执行 kubectl kustomize ./ 查看这些字段都被设置到 Deployment 资源上:

apiVersion: apps/v1 kind: Deployment metadata:  annotations:  oncallPager: 800-555-1212  labels:  app: bingo  name: dev-nginx-deployment-001  namespace: my-namespace spec:  selector:  matchLabels:  app: bingo  template:  metadata:  annotations:  oncallPager: 800-555-1212  labels:  app: bingo  spec:  containers:  - image: nginx  name: nginx 

组织和定制资源

一种常见的做法是在项目中构造资源集合并将其放到同一个文件或目录中管理。 Kustomize 提供基于不同文件来组织资源并向其应用补丁或者其他定制的能力。

组织

Kustomize 支持组合不同的资源。kustomization.yaml 文件的 resources 字段定义配置中要包含的资源列表。 你可以将 resources 列表中的路径设置为资源配置文件的路径。 下面是由 Deployment 和 Service 构成的 NGINX 应用的示例:

# 创建 deployment.yaml 文件 cat <<EOF > deployment.yaml apiVersion: apps/v1 kind: Deployment metadata:  name: my-nginx spec:  selector:  matchLabels:  run: my-nginx  replicas: 2  template:  metadata:  labels:  run: my-nginx  spec:  containers:  - name: my-nginx  image: nginx  ports:  - containerPort: 80 EOF  # 创建 service.yaml 文件 cat <<EOF > service.yaml apiVersion: v1 kind: Service metadata:  name: my-nginx  labels:  run: my-nginx spec:  ports:  - port: 80  protocol: TCP  selector:  run: my-nginx EOF  # 创建 kustomization.yaml 来组织以上两个资源 cat <<EOF >./kustomization.yaml resources: - deployment.yaml - service.yaml EOF 

kubectl kustomize ./ 所得到的资源中既包含 Deployment 也包含 Service 对象。

定制

补丁文件(Patches)可以用来对资源执行不同的定制。 Kustomize 通过 StrategicMergeJson6902 使用 patches 字段支持不同的打补丁机制。

patches 字段包含了一列按指定顺序应用的补丁。 补丁目标通过 groupversionkindnamenamespacelabelSelectorannotationSelector 来选择资源。

建议使用只做一件事的小补丁。例如,创建一个用于增加部署副本数量的补丁,以及另一个用于设置内存限制的补丁。 目标资源是通过补丁文件中的 groupversionkindname 字段进行匹配的。

# 创建 deployment.yaml 文件 cat <<EOF > deployment.yaml apiVersion: apps/v1 kind: Deployment metadata:  name: my-nginx spec:  selector:  matchLabels:  run: my-nginx  replicas: 2  template:  metadata:  labels:  run: my-nginx  spec:  containers:  - name: my-nginx  image: nginx  ports:  - containerPort: 80 EOF  # 生成一个补丁 increase_replicas.yaml cat <<EOF > increase_replicas.yaml apiVersion: apps/v1 kind: Deployment metadata:  name: my-nginx spec:  replicas: 3 EOF  # 生成另一个补丁 set_memory.yaml cat <<EOF > set_memory.yaml apiVersion: apps/v1 kind: Deployment metadata:  name: my-nginx spec:  template:  spec:  containers:  - name: my-nginx  resources:  limits:  memory: 512Mi EOF  cat <<EOF >./kustomization.yaml resources: - deployment.yaml patches:  - path: increase_replicas.yaml  - path: set_memory.yaml EOF 

执行 kubectl kustomize ./ 来查看 Deployment:

apiVersion: apps/v1 kind: Deployment metadata:  name: my-nginx spec:  replicas: 3  selector:  matchLabels:  run: my-nginx  template:  metadata:  labels:  run: my-nginx  spec:  containers:  - image: nginx  name: my-nginx  ports:  - containerPort: 80  resources:  limits:  memory: 512Mi 

并非所有资源或者字段都支持策略性合并(strategicMerge)补丁。为了支持对任何资源的任何字段进行修改, Kustomize 提供通过 Json6902 来应用 JSON 补丁的能力。 为了给 Json6902 补丁找到正确的资源,必须在 kustomization.yaml 文件中设置 target 字段。

例如,可以通过 Json6902 补丁来增加 Deployment 对象的副本数量。 目标资源是通过 target 字段中的 groupversionkindname 进行匹配的。

# 创建一个 deployment.yaml 文件 cat <<EOF > deployment.yaml apiVersion: apps/v1 kind: Deployment metadata:  name: my-nginx spec:  selector:  matchLabels:  run: my-nginx  replicas: 2  template:  metadata:  labels:  run: my-nginx  spec:  containers:  - name: my-nginx  image: nginx  ports:  - containerPort: 80 EOF  # 创建一个 JSON 补丁文件 cat <<EOF > patch.yaml - op: replace  path: /spec/replicas  value: 3 EOF  # 创建一个 kustomization.yaml cat <<EOF >./kustomization.yaml resources: - deployment.yaml  patches: - target:  group: apps  version: v1  kind: Deployment  name: my-nginx  path: patch.yaml EOF 

执行 kubectl kustomize ./ 以查看 replicas 字段被更新:

apiVersion: apps/v1 kind: Deployment metadata:  name: my-nginx spec:  replicas: 3  selector:  matchLabels:  run: my-nginx  template:  metadata:  labels:  run: my-nginx  spec:  containers:  - image: nginx  name: my-nginx  ports:  - containerPort: 80 

除了补丁之外,Kustomize 还提供定制容器镜像或者将其他对象的字段值注入到容器中的能力,并且不需要创建补丁。 例如,你可以通过在 kustomization.yaml 文件的 images 字段设置新的镜像来更改容器中使用的镜像。

cat <<EOF > deployment.yaml apiVersion: apps/v1 kind: Deployment metadata:  name: my-nginx spec:  selector:  matchLabels:  run: my-nginx  replicas: 2  template:  metadata:  labels:  run: my-nginx  spec:  containers:  - name: my-nginx  image: nginx  ports:  - containerPort: 80 EOF  cat <<EOF >./kustomization.yaml resources: - deployment.yaml images: - name: nginx  newName: my.image.registry/nginx  newTag: "1.4.0" EOF 

执行 kubectl kustomize ./ 以查看所使用的镜像已被更新:

apiVersion: apps/v1 kind: Deployment metadata:  name: my-nginx spec:  replicas: 2  selector:  matchLabels:  run: my-nginx  template:  metadata:  labels:  run: my-nginx  spec:  containers:  - image: my.image.registry/nginx:1.4.0  name: my-nginx  ports:  - containerPort: 80 

有些时候,Pod 中运行的应用可能需要使用来自其他对象的配置值。 例如,某 Deployment 对象的 Pod 需要从环境变量或命令行参数中读取读取 Service 的名称。 由于在 kustomization.yaml 文件中添加 namePrefixnameSuffix 时 Service 名称可能发生变化,建议不要在命令参数中硬编码 Service 名称。 对于这种使用场景,Kustomize 可以通过 replacements 将 Service 名称注入到容器中。

# 创建一个 deployment.yaml 文件(引用此处的文档分隔符) cat <<'EOF' > deployment.yaml apiVersion: apps/v1 kind: Deployment metadata:  name: my-nginx spec:  selector:  matchLabels:  run: my-nginx  replicas: 2  template:  metadata:  labels:  run: my-nginx  spec:  containers:  - name: my-nginx  image: nginx  command: ["start", "--host", "MY_SERVICE_NAME_PLACEHOLDER"] EOF  # 创建一个 service.yaml 文件 cat <<EOF > service.yaml apiVersion: v1 kind: Service metadata:  name: my-nginx  labels:  run: my-nginx spec:  ports:  - port: 80  protocol: TCP  selector:  run: my-nginx EOF  cat <<EOF >./kustomization.yaml namePrefix: dev- nameSuffix: "-001"  resources: - deployment.yaml - service.yaml  replacements: - source:  kind: Service  name: my-nginx  fieldPath: metadata.name  targets:  - select:  kind: Deployment  name: my-nginx  fieldPaths:  - spec.template.spec.containers.0.command.2 EOF 

执行 kubectl kustomize ./ 以查看注入到容器中的 Service 名称是 dev-my-nginx-001

apiVersion: apps/v1 kind: Deployment metadata:  name: dev-my-nginx-001 spec:  replicas: 2  selector:  matchLabels:  run: my-nginx  template:  metadata:  labels:  run: my-nginx  spec:  containers:  - command:  - start  - --host  - dev-my-nginx-001  image: nginx  name: my-nginx 

基准(Bases)与覆盖(Overlays)

Kustomize 中有 基准(bases)覆盖(overlays) 的概念区分。 基准 是包含 kustomization.yaml 文件的一个目录,其中包含一组资源及其相关的定制。 基准可以是本地目录或者来自远程仓库的目录,只要其中存在 kustomization.yaml 文件即可。 覆盖 也是一个目录,其中包含将其他 kustomization 目录当做 bases 来引用的 kustomization.yaml 文件。 基准不了解覆盖的存在,且可被多个覆盖所使用。

kustomization.yaml 文件位于 overlay 目录中,可以引用多个 bases, 将这些 base 中定义的所有资源合并为一个统一的配置。 此外,它还可以在这些资源之上应用定制化修改以满足特定需求。

以下是 base 的一个示例:

# 创建一个包含基准的目录 mkdir base # 创建 base/deployment.yaml cat <<EOF > base/deployment.yaml apiVersion: apps/v1 kind: Deployment metadata:  name: my-nginx spec:  selector:  matchLabels:  run: my-nginx  replicas: 2  template:  metadata:  labels:  run: my-nginx  spec:  containers:  - name: my-nginx  image: nginx EOF  # 创建 base/service.yaml 文件 cat <<EOF > base/service.yaml apiVersion: v1 kind: Service metadata:  name: my-nginx  labels:  run: my-nginx spec:  ports:  - port: 80  protocol: TCP  selector:  run: my-nginx EOF  # 创建 base/kustomization.yaml cat <<EOF > base/kustomization.yaml resources: - deployment.yaml - service.yaml EOF 

此基准可在多个覆盖中使用。你可以在不同的覆盖中添加不同的 namePrefix 或其他贯穿性字段。 下面是两个使用同一基准的覆盖:

mkdir dev cat <<EOF > dev/kustomization.yaml resources: - ../base namePrefix: dev- EOF  mkdir prod cat <<EOF > prod/kustomization.yaml resources: - ../base namePrefix: prod- EOF 

如何使用 Kustomize 来应用、查看和删除对象

kubectl 命令中使用 --kustomize-k 参数来识别被 kustomization.yaml 所管理的资源。 注意 -k 要指向一个 kustomization 目录。例如:

kubectl apply -k <kustomization 目录>/ 

假定使用下面的 kustomization.yaml

# 创建 deployment.yaml 文件 cat <<EOF > deployment.yaml apiVersion: apps/v1 kind: Deployment metadata:  name: my-nginx spec:  selector:  matchLabels:  run: my-nginx  replicas: 2  template:  metadata:  labels:  run: my-nginx  spec:  containers:  - name: my-nginx  image: nginx  ports:  - containerPort: 80 EOF  # 创建 kustomization.yaml cat <<EOF >./kustomization.yaml namePrefix: dev- labels:  - pairs:  app: my-nginx  includeSelectors: true resources: - deployment.yaml EOF 

执行下面的命令来应用 Deployment 对象 dev-my-nginx

> kubectl apply -k ./ deployment.apps/dev-my-nginx created 

运行下面的命令之一来查看 Deployment 对象 dev-my-nginx

kubectl get -k ./ 
kubectl describe -k ./ 

执行下面的命令来比较 Deployment 对象 dev-my-nginx 与清单被应用之后集群将处于的状态:

kubectl diff -k ./ 

执行下面的命令删除 Deployment 对象 dev-my-nginx

> kubectl delete -k ./ deployment.apps "dev-my-nginx" deleted 

Kustomize 功能特性列表

字段类型解释
bases[]string列表中每个条目都应能解析为一个包含 kustomization.yaml 文件的目录
commonAnnotationsmap[string]string要添加到所有资源的注解
commonLabelsmap[string]string要添加到所有资源和选择算符的标签
configMapGenerator[]ConfigMapArgs列表中的每个条目都会生成一个 ConfigMap
configurations[]string列表中每个条目都应能解析为一个包含 Kustomize 转换器配置 的文件
crds[]string列表中每个条目都应能够解析为 Kubernetes 类别的 OpenAPI 定义文件
generatorOptionsGeneratorOptions更改所有 ConfigMap 和 Secret 生成器的行为
images[]Image每个条目都用来更改镜像的名称、标记与/或摘要,不必生成补丁
labelsmap[string]string添加标签而不自动注入对应的选择器
namePrefixstring此字段的值将被添加到所有资源名称前面
nameSuffixstring此字段的值将被添加到所有资源名称后面
patchesJson6902[]Patch列表中每个条目都能解析为一个 Kubernetes 对象和一个 JSON 补丁
patchesStrategicMerge[]string列表中每个条目都能解析为某 Kubernetes 对象的策略性合并补丁
replacements[]Replacements将 resource 字段的值复制到任意数量的指定目标
resources[]string列表中的每个条目都必须能够解析为现有的资源配置文件
secretGenerator[]SecretArgs列表中的每个条目都会生成一个 Secret
vars[]Var每个条目用来从某资源的字段来析取文字

接下来

最后修改 July 07, 2025 at 10:43 AM PST: sync cri kubeadm-upgrade kustomization (748c37bbef)