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

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

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

  1. kubectl kustomize <kustomization_directory>

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

  1. kubectl apply -k <kustomization_directory>

准备开始

安装 kubectl.

你必须拥有一个 Kubernetes 的集群,同时你的 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 的示例:

  1. # 生成一个 application.properties 文件
  2. cat <<EOF >application.properties
  3. FOO=Bar
  4. EOF
  5. cat <<EOF >./kustomization.yaml
  6. configMapGenerator:
  7. - name: example-configmap-1
  8. files:
  9. - application.properties
  10. EOF

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

  1. kubectl kustomize ./

所生成的 ConfigMap 为:

  1. apiVersion: v1
  2. data:
  3. application.properties: |
  4. FOO=Bar
  5. kind: ConfigMap
  6. metadata:
  7. name: example-configmap-1-8mbdf7882g

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

  1. cat <<EOF >./kustomization.yaml
  2. configMapGenerator:
  3. - name: example-configmap-2
  4. literals:
  5. - FOO=Bar
  6. EOF

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

  1. kubectl kustomize ./

所生成的 ConfigMap 为:

  1. apiVersion: v1
  2. data:
  3. FOO: Bar
  4. kind: ConfigMap
  5. metadata:
  6. name: example-configmap-2-g2hdhfc6tk

secretGenerator

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

  1. # 创建一个 password.txt 文件
  2. cat <<EOF >./password.txt
  3. username=admin
  4. password=secret
  5. EOF
  6. cat <<EOF >./kustomization.yaml
  7. secretGenerator:
  8. - name: example-secret-1
  9. files:
  10. - password.txt
  11. EOF

所生成的 Secret 如下:

  1. apiVersion: v1
  2. data:
  3. password.txt: dXNlcm5hbWU9YWRtaW4KcGFzc3dvcmQ9c2VjcmV0Cg==
  4. kind: Secret
  5. metadata:
  6. name: example-secret-1-t2kt65hgtb
  7. type: Opaque

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

  1. cat <<EOF >./kustomization.yaml
  2. secretGenerator:
  3. - name: example-secret-2
  4. literals:
  5. - username=admin
  6. - password=secret
  7. EOF

所生成的 Secret 如下:

  1. apiVersion: v1
  2. data:
  3. password: c2VjcmV0
  4. username: YWRtaW4=
  5. kind: Secret
  6. metadata:
  7. name: example-secret-2-t52t6g96d8
  8. type: Opaque

generatorOptions

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

  1. cat <<EOF >./kustomization.yaml
  2. configMapGenerator:
  3. - name: example-configmap-3
  4. literals:
  5. - FOO=Bar
  6. generatorOptions:
  7. disableNameSuffixHash: true
  8. labels:
  9. type: generated
  10. annotations:
  11. note: generated
  12. EOF

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

  1. apiVersion: v1
  2. data:
  3. FOO: Bar
  4. kind: ConfigMap
  5. metadata:
  6. annotations:
  7. note: generated
  8. labels:
  9. type: generated
  10. name: example-configmap-3

设置贯穿性字段

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

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

下面是一个例子:

  1. # 创建一个 deployment.yaml
  2. cat <<EOF >./deployment.yaml
  3. apiVersion: apps/v1
  4. kind: Deployment
  5. metadata:
  6. name: nginx-deployment
  7. labels:
  8. app: nginx
  9. spec:
  10. selector:
  11. matchLabels:
  12. app: nginx
  13. template:
  14. metadata:
  15. labels:
  16. app: nginx
  17. spec:
  18. containers:
  19. - name: nginx
  20. image: nginx
  21. EOF
  22. cat <<EOF >./kustomization.yaml
  23. namespace: my-namespace
  24. namePrefix: dev-
  25. nameSuffix: "-001"
  26. commonLabels:
  27. app: bingo
  28. commonAnnotations:
  29. oncallPager: 800-555-1212
  30. resources:
  31. - deployment.yaml
  32. EOF

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

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. annotations:
  5. oncallPager: 800-555-1212
  6. labels:
  7. app: bingo
  8. name: dev-nginx-deployment-001
  9. namespace: my-namespace
  10. spec:
  11. selector:
  12. matchLabels:
  13. app: bingo
  14. template:
  15. metadata:
  16. annotations:
  17. oncallPager: 800-555-1212
  18. labels:
  19. app: bingo
  20. spec:
  21. containers:
  22. - image: nginx
  23. name: nginx

组织和定制资源

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

组织

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

  1. # 创建 deployment.yaml 文件
  2. cat <<EOF > deployment.yaml
  3. apiVersion: apps/v1
  4. kind: Deployment
  5. metadata:
  6. name: my-nginx
  7. spec:
  8. selector:
  9. matchLabels:
  10. run: my-nginx
  11. replicas: 2
  12. template:
  13. metadata:
  14. labels:
  15. run: my-nginx
  16. spec:
  17. containers:
  18. - name: my-nginx
  19. image: nginx
  20. ports:
  21. - containerPort: 80
  22. EOF
  23. # 创建 service.yaml 文件
  24. cat <<EOF > service.yaml
  25. apiVersion: v1
  26. kind: Service
  27. metadata:
  28. name: my-nginx
  29. labels:
  30. run: my-nginx
  31. spec:
  32. ports:
  33. - port: 80
  34. protocol: TCP
  35. selector:
  36. run: my-nginx
  37. EOF
  38. # 创建 kustomization.yaml 来组织以上两个资源
  39. cat <<EOF >./kustomization.yaml
  40. resources:
  41. - deployment.yaml
  42. - service.yaml
  43. EOF

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

定制

补丁文件(Patches)可以用来对资源执行不同的定制。 Kustomize 通过 patchesStrategicMergepatchesJson6902 支持不同的打补丁 机制。patchesStrategicMerge 的内容是一个文件路径的列表,其中每个文件都应可解析为 策略性合并补丁(Strategic Merge Patch)。 补丁文件中的名称必须与已经加载的资源的名称匹配。 建议构造规模较小的、仅做一件事情的补丁。 例如,构造一个补丁来增加 Deployment 的副本个数;构造另外一个补丁来设置内存限制。

  1. # 创建 deployment.yaml 文件
  2. cat <<EOF > deployment.yaml
  3. apiVersion: apps/v1
  4. kind: Deployment
  5. metadata:
  6. name: my-nginx
  7. spec:
  8. selector:
  9. matchLabels:
  10. run: my-nginx
  11. replicas: 2
  12. template:
  13. metadata:
  14. labels:
  15. run: my-nginx
  16. spec:
  17. containers:
  18. - name: my-nginx
  19. image: nginx
  20. ports:
  21. - containerPort: 80
  22. EOF
  23. # 生成一个补丁 increase_replicas.yaml
  24. cat <<EOF > increase_replicas.yaml
  25. apiVersion: apps/v1
  26. kind: Deployment
  27. metadata:
  28. name: my-nginx
  29. spec:
  30. replicas: 3
  31. EOF
  32. # 生成另一个补丁 set_memory.yaml
  33. cat <<EOF > set_memory.yaml
  34. apiVersion: apps/v1
  35. kind: Deployment
  36. metadata:
  37. name: my-nginx
  38. spec:
  39. template:
  40. spec:
  41. containers:
  42. - name: my-nginx
  43. resources:
  44. limits:
  45. memory: 512Mi
  46. EOF
  47. cat <<EOF >./kustomization.yaml
  48. resources:
  49. - deployment.yaml
  50. patchesStrategicMerge:
  51. - increase_replicas.yaml
  52. - set_memory.yaml
  53. EOF

执行 kubectl kustomize ./ 来查看 Deployment:

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: my-nginx
  5. spec:
  6. replicas: 3
  7. selector:
  8. matchLabels:
  9. run: my-nginx
  10. template:
  11. metadata:
  12. labels:
  13. run: my-nginx
  14. spec:
  15. containers:
  16. - image: nginx
  17. name: my-nginx
  18. ports:
  19. - containerPort: 80
  20. resources:
  21. limits:
  22. memory: 512Mi

并非所有资源或者字段都支持策略性合并补丁。为了支持对任何资源的任何字段进行修改, Kustomize 提供通过 patchesJson6902 来应用 JSON 补丁 的能力。为了给 JSON 补丁找到正确的资源,需要在 kustomization.yaml 文件中指定资源的 组(group)、版本(version)、类别(kind)和名称(name)。 例如,为某 Deployment 对象增加副本个数的操作也可以通过 patchesJson6902 来完成:

  1. # 创建一个 deployment.yaml 文件
  2. cat <<EOF > deployment.yaml
  3. apiVersion: apps/v1
  4. kind: Deployment
  5. metadata:
  6. name: my-nginx
  7. spec:
  8. selector:
  9. matchLabels:
  10. run: my-nginx
  11. replicas: 2
  12. template:
  13. metadata:
  14. labels:
  15. run: my-nginx
  16. spec:
  17. containers:
  18. - name: my-nginx
  19. image: nginx
  20. ports:
  21. - containerPort: 80
  22. EOF
  23. # 创建一个 JSON 补丁文件
  24. cat <<EOF > patch.yaml
  25. - op: replace
  26. path: /spec/replicas
  27. value: 3
  28. EOF
  29. # 创建一个 kustomization.yaml
  30. cat <<EOF >./kustomization.yaml
  31. resources:
  32. - deployment.yaml
  33. patchesJson6902:
  34. - target:
  35. group: apps
  36. version: v1
  37. kind: Deployment
  38. name: my-nginx
  39. path: patch.yaml
  40. EOF

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

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: my-nginx
  5. spec:
  6. replicas: 3
  7. selector:
  8. matchLabels:
  9. run: my-nginx
  10. template:
  11. metadata:
  12. labels:
  13. run: my-nginx
  14. spec:
  15. containers:
  16. - image: nginx
  17. name: my-nginx
  18. ports:
  19. - containerPort: 80

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

  1. cat <<EOF > deployment.yaml
  2. apiVersion: apps/v1
  3. kind: Deployment
  4. metadata:
  5. name: my-nginx
  6. spec:
  7. selector:
  8. matchLabels:
  9. run: my-nginx
  10. replicas: 2
  11. template:
  12. metadata:
  13. labels:
  14. run: my-nginx
  15. spec:
  16. containers:
  17. - name: my-nginx
  18. image: nginx
  19. ports:
  20. - containerPort: 80
  21. EOF
  22. cat <<EOF >./kustomization.yaml
  23. resources:
  24. - deployment.yaml
  25. images:
  26. - name: nginx
  27. newName: my.image.registry/nginx
  28. newTag: 1.4.0
  29. EOF

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

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: my-nginx
  5. spec:
  6. replicas: 2
  7. selector:
  8. matchLabels:
  9. run: my-nginx
  10. template:
  11. metadata:
  12. labels:
  13. run: my-nginx
  14. spec:
  15. containers:
  16. - image: my.image.registry/nginx:1.4.0
  17. name: my-nginx
  18. ports:
  19. - containerPort: 80

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

  1. # 创建一个 deployment.yaml 文件
  2. cat <<EOF > deployment.yaml
  3. apiVersion: apps/v1
  4. kind: Deployment
  5. metadata:
  6. name: my-nginx
  7. spec:
  8. selector:
  9. matchLabels:
  10. run: my-nginx
  11. replicas: 2
  12. template:
  13. metadata:
  14. labels:
  15. run: my-nginx
  16. spec:
  17. containers:
  18. - name: my-nginx
  19. image: nginx
  20. command: ["start", "--host", "$(MY_SERVICE_NAME)"]
  21. EOF
  22. # 创建一个 service.yaml 文件
  23. cat <<EOF > service.yaml
  24. apiVersion: v1
  25. kind: Service
  26. metadata:
  27. name: my-nginx
  28. labels:
  29. run: my-nginx
  30. spec:
  31. ports:
  32. - port: 80
  33. protocol: TCP
  34. selector:
  35. run: my-nginx
  36. EOF
  37. cat <<EOF >./kustomization.yaml
  38. namePrefix: dev-
  39. nameSuffix: "-001"
  40. resources:
  41. - deployment.yaml
  42. - service.yaml
  43. vars:
  44. - name: MY_SERVICE_NAME
  45. objref:
  46. kind: Service
  47. name: my-nginx
  48. apiVersion: v1
  49. EOF

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

  1. apiVersion: apps/v1
  2. kind: Deployment
  3. metadata:
  4. name: dev-my-nginx-001
  5. spec:
  6. replicas: 2
  7. selector:
  8. matchLabels:
  9. run: my-nginx
  10. template:
  11. metadata:
  12. labels:
  13. run: my-nginx
  14. spec:
  15. containers:
  16. - command:
  17. - start
  18. - --host
  19. - dev-my-nginx-001
  20. image: nginx
  21. name: my-nginx

基准(Bases)与覆盖(Overlays)

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

  1. # 创建一个包含基准的目录
  2. mkdir base
  3. # 创建 base/deployment.yaml
  4. cat <<EOF > base/deployment.yaml
  5. apiVersion: apps/v1
  6. kind: Deployment
  7. metadata:
  8. name: my-nginx
  9. spec:
  10. selector:
  11. matchLabels:
  12. run: my-nginx
  13. replicas: 2
  14. template:
  15. metadata:
  16. labels:
  17. run: my-nginx
  18. spec:
  19. containers:
  20. - name: my-nginx
  21. image: nginx
  22. EOF
  23. # 创建 base/service.yaml 文件
  24. cat <<EOF > base/service.yaml
  25. apiVersion: v1
  26. kind: Service
  27. metadata:
  28. name: my-nginx
  29. labels:
  30. run: my-nginx
  31. spec:
  32. ports:
  33. - port: 80
  34. protocol: TCP
  35. selector:
  36. run: my-nginx
  37. EOF
  38. # 创建 base/kustomization.yaml
  39. cat <<EOF > base/kustomization.yaml
  40. resources:
  41. - deployment.yaml
  42. - service.yaml
  43. EOF

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

  1. mkdir dev
  2. cat <<EOF > dev/kustomization.yaml
  3. bases:
  4. - ../base
  5. namePrefix: dev-
  6. EOF
  7. mkdir prod
  8. cat <<EOF > prod/kustomization.yaml
  9. bases:
  10. - ../base
  11. namePrefix: prod-
  12. EOF

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

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

  1. kubectl apply -k <kustomization 目录>/

假定使用下面的 kustomization.yaml

  1. # 创建 deployment.yaml 文件
  2. cat <<EOF > deployment.yaml
  3. apiVersion: apps/v1
  4. kind: Deployment
  5. metadata:
  6. name: my-nginx
  7. spec:
  8. selector:
  9. matchLabels:
  10. run: my-nginx
  11. replicas: 2
  12. template:
  13. metadata:
  14. labels:
  15. run: my-nginx
  16. spec:
  17. containers:
  18. - name: my-nginx
  19. image: nginx
  20. ports:
  21. - containerPort: 80
  22. EOF
  23. # 创建 kustomization.yaml
  24. cat <<EOF >./kustomization.yaml
  25. namePrefix: dev-
  26. commonLabels:
  27. app: my-nginx
  28. resources:
  29. - deployment.yaml
  30. EOF

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

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

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

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

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

  1. kubectl diff -k ./

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

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

Kustomize 功能特性列表

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

接下来