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

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

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

    1. kubectl apply -k <kustomization_directory>

    安装 。

    你必须拥有一个 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

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

    1. # 创建一个 .env 文件
    2. cat <<EOF >.env
    3. FOO=Bar
    4. EOF
    5. cat <<EOF >./kustomization.yaml
    6. configMapGenerator:
    7. - name: example-configmap-1
    8. envs:
    9. - .env
    10. EOF

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

    1. kubectl kustomize ./

    生成的 ConfigMap 为:

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

    说明: .env 文件中的每个变量在生成的 ConfigMap 中成为一个单独的键。 这与之前的示例不同,前一个示例将一个名为 .properties 的文件(及其所有条目)嵌入到同一个键的值中。

    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 ./
    1. apiVersion: v1
    2. data:
    3. FOO: Bar
    4. kind: ConfigMap
    5. metadata:
    6. name: example-configmap-2-g2hdhfc6tk

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

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

    1. # 创建一个 application.properties 文件
    2. cat <<EOF >application.properties
    3. FOO=Bar
    4. EOF
    5. cat <<EOF >deployment.yaml
    6. apiVersion: apps/v1
    7. kind: Deployment
    8. metadata:
    9. name: my-app
    10. labels:
    11. app: my-app
    12. spec:
    13. selector:
    14. matchLabels:
    15. app: my-app
    16. template:
    17. metadata:
    18. labels:
    19. app: my-app
    20. spec:
    21. containers:
    22. - name: app
    23. image: my-app
    24. volumeMounts:
    25. - name: config
    26. mountPath: /config
    27. volumes:
    28. - name: config
    29. configMap:
    30. name: example-configmap-1
    31. EOF
    32. cat <<EOF >./kustomization.yaml
    33. resources:
    34. - deployment.yaml
    35. configMapGenerator:
    36. - name: example-configmap-1
    37. files:
    38. - application.properties
    39. EOF

    生成 ConfigMap 和 Deployment:

    1. kubectl kustomize ./

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

    1. apiVersion: v1
    2. data:
    3. application.properties: |
    4. FOO=Bar
    5. kind: ConfigMap
    6. metadata:
    7. name: example-configmap-1-g4hk9g2ff8
    8. ---
    9. apiVersion: apps/v1
    10. kind: Deployment
    11. metadata:
    12. labels:
    13. app: my-app
    14. name: my-app
    15. spec:
    16. selector:
    17. matchLabels:
    18. app: my-app
    19. template:
    20. metadata:
    21. labels:
    22. app: my-app
    23. spec:
    24. containers:
    25. - image: my-app
    26. name: app
    27. volumeMounts:
    28. - mountPath: /config
    29. name: config
    30. volumes:
    31. - configMap:
    32. name: example-configmap-1-g4hk9g2ff8
    33. name: config

    secretGenerator

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

    所生成的 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

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

    1. # 创建一个 password.txt 文件
    2. cat <<EOF >./password.txt
    3. username=admin
    4. password=secret
    5. EOF
    6. cat <<EOF >deployment.yaml
    7. apiVersion: apps/v1
    8. kind: Deployment
    9. metadata:
    10. name: my-app
    11. labels:
    12. app: my-app
    13. spec:
    14. selector:
    15. matchLabels:
    16. app: my-app
    17. template:
    18. metadata:
    19. labels:
    20. app: my-app
    21. spec:
    22. containers:
    23. - name: app
    24. image: my-app
    25. volumeMounts:
    26. - name: password
    27. mountPath: /secrets
    28. volumes:
    29. - name: password
    30. secret:
    31. secretName: example-secret-1
    32. EOF
    33. cat <<EOF >./kustomization.yaml
    34. resources:
    35. - deployment.yaml
    36. secretGenerator:
    37. - name: example-secret-1
    38. files:
    39. - password.txt
    40. EOF

    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. FOO: Bar
    3. kind: ConfigMap
    4. metadata:
    5. annotations:
    6. note: generated
    7. labels:
    8. 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

    定制

    补丁文件(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 补丁找到正确的资源,需要在 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. resources:
    31. - deployment.yaml
    32. patchesJson6902:
    33. - target:
    34. group: apps
    35. version: v1
    36. kind: Deployment
    37. name: my-nginx
    38. 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 字段设置新的镜像来更改容器中使用的镜像。

    执行 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

    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 对象 :

    1. kubectl delete -k ./

    接下来