[K8s] 声明式资源管理器 Kustomize

5,779 阅读11分钟

Kustomize

我们在使用K8s部署应用的时候,经常会因为管理对应的声明式文件而烦恼。在集群规模的变大和业务的增长的时候,我们通过手动去编排,管理这些声明式文件是不太现实的。目前对声明式文件的编排下,主流的解决方案是HelmKustomize

Helm的功能丰富,提供了更灵敏,可拓展的K8s声明式文件管理解决方案。Kustomize是由K8s社区开发的K8s资源配置管理方案。Kustomize在功能上不如Helm丰富,但是由于与K8s的集成较好,在使用kubectl时候,原生就可以通过-k参数指定 kustomization 文件。在业务量小,集群小,需求不大的情况下使用起来相比Helm更为便利。对于想要学习管理资源配置文件的初学者来说,更为友好。

什么是Kustomize

Kustomize 提供了一种无需模板和 DSL 即可自定义 Kubernetes 资源配置的解决方案。

Kustomize 允许您出于多种目的自定义原始、无模板的 YAML 文件,使原始 YAML 保持不变并按原样使用。

自定义目标 kubernetes;它理解并可以修补kubernetes styleAPI 对象。它就像 make,因为它所做的事情是在文件中声明的,它就像sed,因为它发出编辑后的文本。

Kustomize 是一个用于 Kubernetes 配置管理的强大工具,它旨在帮助开发人员和运维团队更轻松地管理复杂的应用程序部署。Kustomize 提供了一种声明性方法来定制和管理 Kubernetes 配置,而无需修改原始 YAML 文件。以下是 Kustomize 的一些主要特点和优势:

  1. 声明式配置管理:Kustomize 鼓励使用声明性配置,而不是直接编辑 YAML 文件。您可以通过简单的文件修改来实现所需的配置更改,而不必担心复杂的合并和编辑操作。
  2. 模块化配置:Kustomize 支持将 Kubernetes 配置划分为可重用的模块,称为“Kustomization”。这使得可以轻松地组合和共享不同的配置片段,以构建多个应用程序变体。
  3. 环境特定配置:Kustomize 提供了一种简单的方法来管理不同环境(例如开发、测试和生产)的配置差异。您可以轻松地覆盖或合并配置以满足不同环境的需求。
  4. 可扩展性:Kustomize 支持自定义修改器(transformer),这些修改器可以自定义 Kubernetes 配置,以适应特定的用例。这使得 Kustomize 非常灵活,可以适应各种部署要求。
  5. 与持续集成/持续部署(CI/CD)集成:Kustomize 可以与常见的 CI/CD 工具集成,如 Jenkins、GitLab CI/CD、GitHub Actions 等,使自动化部署变得更加容易。

安装kustomize

本文通过Go进行安装,也可以通过二进制进行安装。

二进制安装:

curl -s "https://raw.githubusercontent.com/\
kubernetes-sigs/kustomize/master/hack/install_kustomize.sh"  | bash

Go安装

# golang >= 1.17
go install sigs.k8s.io/kustomize/kustomize/v5@latest

# golang < 1.17
go get sigs.k8s.io/kustomize/kustomize/v5

安装之后通过kustomize version查看是否成功安装。

入门

我们通过一个例子来介绍Kustomize到底是什么:

假设我们当前有一个app需要部署,这个app的部署同时涉及到Service,Deployment,ConfigMap等(这里只列举三个,实际上要部署的工作负载可能会更多)。并且,在不同环境下需要同时部署该app,dev和prod环境下的数据库密码也许不同,Service使用的路由器也有可能不同,此时我们该如何去管理呢?

app.yaml:

apiVersion: v1
kind: Pod
metadata:
  labels:
    traefik.instance: app
  name: whoami
spec:
  containers:
  - image: nginx:1.14.1
    name: whoami
    ports:
    - containerPort: 80

service.yaml:

apiVersion: v1
kind: Service
metadata:
  name: whoami-svc
spec:
  ports:
    - protocol: TCP
      port: 4000
      targetPort: 80
  selector:
    traefik.instance: app

此时我们可以通过Kustomize进行管理对应的资源文件。

通过kustomize create --resources app.yaml,svc.yaml生成对应的kustomize文件。

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
# resources声明了多个K8s资源文件
resources:
- app.yaml
- svc.yaml

我们看一下目录结构:

./
├── app.yaml
├── kustomization.yaml
└── svc.yaml

我们可以通过kubectl apply -k ./(kustomization文件所在的目录),就可以将Kustomization文件中声明的resources部署K8s集群中。

Transformer

Kustomize 中的转换器(transformer)是一种可以修改 Kubernetes 配置的插件或工具。这些转换器允许您在部署过程中对原始的 Kubernetes YAML 文件进行修改、扩展或定制,以适应特定的需求。转换器通常用于应用程序配置的特定场景,例如添加标签、修改资源名称、引入配置片段等。

我们可以理解为,这是对资源文件的一些字段进行统一修改。

我们先学习一个command: kustomize build ./ ,这可以将当前kustomize所管理的resources构建出来。

CommonLabels

CommonLabels为Kustomize管理的所有资源和资源中存在Selectors字段添加Labels。

  • 如果资源上已经存在同名label,则该值将被覆盖。
  • 如果资源上没有同名label,则值会添加上去
apiVersion: v1
kind: Pod
metadata:
  labels:
    # 此时存在labels abc
    abc: def
  name: whoami
spec:
  containers:
  - image: nginx:1.14.1
    name: whoami
    ports:
    - containerPort: 80

我们在kustomize中进行声明commonLabels

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- app.yaml

commonLabels:
  abc: zxc

进行构建: kustomize build ./

$ kustomize build ./
apiVersion: v1
kind: Pod
metadata:
  labels:
    # 此时对应的label被覆盖
    abc: zxc
    traefik.instance: app
  name: whoami
spec:
  containers:
  - image: nginx:1.14.1
    name: whoami
    ports:
    - containerPort: 80

CommonAnnotations

CommonAnnotations为Kustomize管理的所有资源添加annotations

  • 如果资源上已经存在同名annotation,则该值将被覆盖
  • 如果资源上没有同名annotation,则值会添加上去
apiVersion: v1
kind: Pod
metadata:
  # 此时不存在annotation
  name: whoami
spec:
  containers:
  - image: nginx:1.14.1
    name: whoami
    ports:
    - containerPort: 80

我们在kustomize中添加annotation:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- app.yaml

commonAnnotations:
  shyunn.io: instance

通过kustomize build ./进行构建,此时可以看见annotation自动添加到资源上。

$ kustomize build ./
apiVersion: v1
kind: Pod
metadata:
  annotations:
    shyunn.io: instance
  name: whoami
spec:
  containers:
  - image: nginx:1.14.1
    name: whoami
    ports:
    - containerPort: 80

Name

kustomize提供了对资源名称添加prefix前缀和suffix后缀的功能,这可以让我们在不同的环境下可以生成不同name。尤其是在下面我们介绍的multi namespace中提供了能力。

NamePrefix:为所有资源和引用的名称添加前缀

NameSuffix:为所有资源和引用的名称添加后缀

apiVersion: v1
kind: Pod
metadata:
  name: whoami
spec:
  containers:
  - image: nginx:1.14.1
    name: whoami
    ports:
    - containerPort: 80

在kustomize文件中声明nameprefixnamefuffix:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- app.yaml

namePrefix: shyunn-

nameSuffix: -dev

通过kustomize构建,我们可以看到对应的资源名称被添加上了前缀和后缀。

$ kustomize build ./
apiVersion: v1
kind: Pod
metadata:
  # 添加了prefix和suffix
  name: shyunn-whoami-dev
spec:
  containers:
  - image: nginx:1.14.1
    name: whoami
    ports:
    - containerPort: 80

Namespace

kustomize可以为所有的资源添加namespace。

  • 如果在资源上设置了现有 namespace,则将覆盖现有 namespace

  • 如果在资源上未设置现有 namespace,则使用现有 namespace

apiVersion: v1
kind: Pod
metadata:
  name: whoami
spec:
  containers:
  - image: nginx:1.14.1
    name: whoami
    ports:
    - containerPort: 80

在kustomize文件中声明namespace

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- app.yaml

namespace: dev

通过进行构建我们可以发现,对应的资源被声明在dev的namespace中

$ kustomize build ./
apiVersion: v1
kind: Pod
metadata:
  name: whoami
  # 对应的namespace被添加上去
  namespace: dev
spec:
  containers:
  - image: nginx:1.14.1
    name: whoami
    ports:
    - containerPort: 80

Other

Image

修改镜像的name,tag或digest,而无需使用patches 。

images字段将会修改 kustomization 所引用的资源的镜像。

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

resources:
 - deploy.yaml

images:
# 将会修改所有资源中镜像名对应的镜像
- name: redis
  # 修改镜像名
  newName: aliyun/redis
  # 修改tag
  newTag: v1
  
- name: nginx
  # 仅修改tag
  newTag: 1.8.0
  
- name: my-demo-app
  # 仅修改镜像名
  newName: my-app
  
- name: alpine
  # 修改镜像digest
  digest: sha256:24a0c4b4a4c0eb97a1aabb8e29f18e917d05abfe1b7a7c07857230879ce7d3d3

Replicas

Replicas修改 kustomization 文件中所引用的资源的副本数。

只能匹配如下资源中的一种:

  • Deployment
  • ReplicationController
  • ReplicaSet
  • StatefulSet

如果有更复杂的变更需求,则使用patch进行修改

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

# 覆盖引用的资源中,指定资源的replicas数量
replicas:
  # 资源名 
  # 必须匹配上述资源中的其中一种
- name: deployment-name
  count: 5

Generator

kustomize提供了生成K8s中SecretConfigMap资源的功能。

ConfigMap

我们可以通过传入file,env file,literals进行生成ConfigMap。

先来看一个例子

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

# 配置对应的configMapGen
configMapGenerator:
  - name: cm-1
    # 引用file
    # file名作为key
    files: 
      - cm-data-1
  - name: cm-2
    # 引用env文件(kv文件)
    envs:
      - kv2
  - name: cm-3
    # 使用字面值kv对
    literals:
      - GO_ROOT=/usr/bin/go/bin

我们进行渲染查看效果:

$ kustomize build ./
apiVersion: v1
data:
  cm-data-1: |
    123
kind: ConfigMap
metadata:
  name: cm-1-kc4gtbhgk9
---
apiVersion: v1
data:
  kvabcf: ""
kind: ConfigMap
metadata:
  name: cm-2-hm5fc8dt8f
---
apiVersion: v1
data:
  GO_ROOT: /usr/bin/go/bin
kind: ConfigMap
metadata:
  name: cm-3-7mf596gcb2

我们可以看到,当我们构建 kustomization 时,将会为我们生成指定的ConfigMap。当我们在进行多环境管理的时候,可以根据需求和环境进行生成ConfigMap。

我们在resources中定义的ConfigMap名可以声明与configMapGenerator名称一致,当进行构建的时候会自动进行关联。

我们还可以对生成的ConfigMap设置LabelsAnnotations

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

configMapGenerator:
  - name: cm-3
    literals:
      - GO_ROOT=/usr/bin/go/bin
    # 通过options进行设置ConfigMap的labels和annotations
    options:
      labels:
        cm-gen: "true"
      annotations:
        cm-gen: "true"

构建结果:

$ kustomize build ./
apiVersion: v1
data:
  GO_ROOT: /usr/bin/go/bin
kind: ConfigMap
metadata:
  # 对应的annotations和labels也被设置了
  annotations:
    cm-gen: "true"
  labels:
    cm-gen: "true"
  name: cm-3-7mf596gcb2

每个 ConfigMapGenerator项均接受的参数 behavior: [create|replace|merge],这个参数允许修改或替换父级现有的 ConfigMap.

在kustomize进行级联使用的时候,我们如果声明一个同名的ConfigMap。此时则需要考虑如何设置behavior

Secret

Secret的字段与ConfigMap字段使用类似。

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

secretGenerator:
  - name: cm-1
    files:
      - cm-data-1
    type: Opaque
  - name: cm-2
    envs:
      - kv2
  - name: cm-3
    literals:
      - GO_ROOT=/usr/bin/go/bin
    options:
      labels:
        cm-gen: "true"
      annotations:
        cm-gen: "true"

进行构建的结果:

$ kustomize build ./
apiVersion: v1
data:
  cm-data-1: MTIzCg==
kind: Secret
metadata:
  name: cm-1-76642cdm79
type: Opaque
---
apiVersion: v1
data:
  kvabcf: ""
kind: Secret
metadata:
  name: cm-2-f844thkf2f
type: Opaque
---
apiVersion: v1
data:
  GO_ROOT: L3Vzci9iaW4vZ28vYmlu
kind: Secret
metadata:
  annotations:
    cm-gen: "true"
  labels:
    cm-gen: "true"
  name: cm-3-tmg5k7k57c
type: Opaque

GeneratorOptions

GeneratorOptions用于控制生成的ConfigMapSecret。我们不仅可以单独声明,在上面的例子中,我们在ConfigMapSecret项中也可以声明option去覆盖全局声明的GeneratorOptions

先来看一下相关的字段定义:

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

generatorOptions:
  # 添加labels到所有生成的Secret/Confimap上
  # Sercet/Configmap可以通过option进行覆盖全局的配置
  labels:
    kustomize.generated.resources: somevalue

  # 添加annotations到所有生成的Secret/Confimap上
  # Sercet/Configmap可以通过option进行覆盖全局的配置
  annotations:
    kustomize.generated.resource: somevalue
    
  # 禁用生成的资源名后面加hash后缀
  # 细心的朋友应该有注意到,我们上面几个生成资源的例子渲染后输出的资源名都有一个hash后缀
  disableNameSuffixHash: true

我们尝试使用generatorOptions

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization

generatorOptions:
  labels:
    gen-options: global    
  
  # 禁用生成的ConfigMap携带Hash后缀
  disableNameSuffixHash: true

configmapGenerator:
  - name: cm-1
    literals:
      - GOOS=linux
	# 使用局部的option进行覆盖      
  - name: cm-2-overlay
  	literals:
  	  - GOOS=windows
    options:
      labels:
        gen-options: overlay

经过构建后输出:

$ kustomize build ./
apiVersion: v1
data:
  GOOS: linux
kind: ConfigMap
metadata:
  labels:
    gen-options: global
  name: cm-1
---
apiVersion: v1
data:
  GOOS: windows
kind: ConfigMap
metadata:
  labels:
    gen-options: overlay
  name: cm-2-overlay

Base-Overlay

在 kustomization 文件中,不仅可以关联K8s resources资源文件,同时还可以引用其他 kustomization 文件。在开发中,我们一般会将通用的deploymentservice作为基础层(base),在基础层通过 kustomization 文件将相关的基础资源进行组织。在部署期间,可能开发阶段需要连接开发的数据库,生成阶段需要连接生产的数据库。此时我们会创建一个覆盖层(overlays)。在该覆盖层下根据不同的环境/命名空间进行声明目录,在目录中创建对应的 kustomization 文件应用基础层(base)的 kustomization 文件。

resources:
  # 通过资源引用base层的kustomization文件
  - ../../base/kustomization.yaml

这种方式让我们可以有更灵活的方式组织资源文件。对应用进行抽象,将基础的组件抽象成base层,在部署的时候根据业务要求和环境,进行动态的组合不同的resources

处理 Kustomization 文件时,可能会访问到该目录以内或以外的文件。

像 YAML 资源这样的数据文件,或者用于生成 ConfigMap 或 Secret 的包含 name=value 的文本文件,或者用于补丁转换的补丁文件,必须在这个目录的内部,需要显式的使用相对路径来表达。

v2.1 中有一个特殊选项 --load_restrictions none 能够放宽这个限制,从而让不同的 Kustomization 可以共享补丁文件。

可以用 URL、绝对路径或者相对路径引用其它的 Kustomization(包含 kustomization.yaml 文件的其它目录)。

如果 A Kustomization 依赖 B Kustomization,那么:

  • B 不能包含 A
  • B 不能依赖 A,间接依赖也不可以。

A 可以包含 B,但是这样的话,最简单的方式可能是让 A 直接依赖 B 的资源,并去除 Bkustomization.yaml 文件(就是把 B 合并到 A)。

通常情况下,BA 处于同级目录,或者 B 放在一个完全独立的 Git 仓库里,可以从任意的 Kustomization 进行引用。

常见布局大致如下:

├── base
│   ├── deployment.yaml
│   ├── kustomization.yaml
│   └── service.yaml
└── overlays
    ├── dev
    │   ├── kustomization.yaml
    │   └── patch.yaml
    ├── prod
    │   ├── kustomization.yaml
    │   └── patch.yaml
    └── staging
        ├── kustomization.yaml
        └── patch.yaml

devprod 以及 staging 是否依赖于 base,要根据 kustomization.yaml 具体判断。

Patch

Patches 在资源上添加或覆盖字段,Kustomization 使用 patches 字段来提供该功能。

patches 字段包含要按指定顺序应用的 patch 列表。

patch可以是:

  • 是一个 strategic merge patch,或者是一个 JSON patch。
  • 也可以是 patch 文件或 inline string
  • 针对单个资源或多个资源

目标选择器可以通过 group、version、kind、name、namespace、标签选择器和注释选择器来选择资源,选择一个或多个匹配所有指定字段的资源来应用 patch。

当我们使用仓库中,或者引用别人的 kustomization 文件的时候,由于并不能直接在源文件上直接进行修改,此时我们可以通过patch操作进行打补丁

假设我们在base文件中定义好了一个deployment文件,我们在dev环境中进行引用,此时我们可以通过patch的操作进行补丁形式修改副本数。

# deploymen文件
apiVersion: apps/v1
kind: Deployment
metadata:
  name: whoami
spec:
  selector:
    matchLabels:
      run: nginx
  replicas: 1
  template:
    metadata:
      labels:
        run: nginx
    spec:
      containers:
      - name: my-nginx
        image: nginx:1.14.1
        ports:
          - containerPort: 80

# base/kustomization.yaml
aiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml

我们在dev环境中引用base的 kustomization 文件:

# dev/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../base/

# 声明patches
patches:
# 可以通过patch声明inline string patch
# 或者通过path指定patch文件
- patch: |-
    - op: replace
      path: /spec/replicas
      # 将副本数改为3
      value: 3
  target:
    group: apps
    version: v1
    kind: Deployment
    name: whoami
    # 可以通过label或annotation选择器进行选择
    #labelSelector: "env=dev"
    #annotationSelector: "zone=west"

我们构建输出结果:

$ kustomize build ./
apiVersion: apps/v1
kind: Deployment
metadata:
  name: whoami
spec:
  replicas: 3
  selector:
    matchLabels:
      run: nginx
  template:
    metadata:
      labels:
        run: nginx
    spec:
      containers:
      - image: nginx:1.14.1
        name: my-nginx
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /usr/share/nginx/html/
          name: config
      volumes:
      - configMap:
          name: nginx-cm
        name: config

可以看到副本数被补丁改为3。因此在很多情况我们不能直接进行修改源文件,可以通过补丁的形式根据需求的修改字段。

我们还可以通过patchesStrategicMerge的形式进行打补丁。如下所示

apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../base/

patches:
- patch: |-
    - op: replace
      path: /spec/replicas
      value: 3
  target:
    group: apps
    version: v1
    kind: Deployment
    name: whoami
    
# 添加一个deployment中pod的镜像 nginx:1.14.1 + nginx:latest
# 当然,也可以将inline string替换为file:  - patch: image_patch.yaml
- patch: |-
    apiVersion: apps/v1
    kind: Deployment
    metadata:
      name: whoami
    spec:
      template:
        spec:
          containers:
            - name: nginx
              image: nignx:latest

最佳实践

【又学又练,快如闪电】

application

我们通过一个案例巩固一下 kustomize 的使用: 现有一个需求,我们需要部署一个应用,该应用在不同的环境中所对应的配置文件也不同,我们需要根据需求进行不同环境下的部署。

该应用需要准备deployment(应用)service(服务)configmap(配置)文件

# deployment文件(丐版)
apiVersion: apps/v1
kind: Deployment
metadata:
  name: application
spec:
  # 基础副本数为1
  replicas: 1
  selector:
    matchLabels:
      run: app
  template:
    metadata:
      labels:
        run: app
    spec:
      containers:
      - image: shyunn.images.io/app:v0.1.5
        name: app
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /usr/share/nginx/html/
          name: config
      # configmap配置挂载
      volumes:
      - configMap:
          name: app-cm
        name: config

# service
apiVersion: v1
kind: Service
metadata:
  name: app-svc
spec:
  ports:
    - protocol: TCP
      port: 4000
      targetPort: 80
  selector:
    run: app

# configmap我们通过kustomize进行生成,灵活度更高. 故在此不声明
---

# dev开发环境下的conf配置
database:
  mysql:
    username: dev-usr
    password: abcd-efg
  redis:
    url: 127.0.0.1:9090

# prod生产环境下的conf配置
database:
  mysql:
    username: prod-usr
    password: 123-456
  redis:
    url: 127.0.0.1:9010

此时我们创建目录进行分类,如下:

$ tree ./
./
├── base
│   ├── deployment.yaml
│   ├── kustomization.yaml
│   └── service.yaml
├── dev
│   ├── conf.yaml
│   └── kustomization.yaml
└── prod
    ├── conf.yaml
    └── kustomization.yaml
    
# base的kustomization文件组合了所需的基础资源配置    
$ cat base/kustomization.yaml 
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- deployment.yaml
- service.yaml

# dev的kustomization
$ cat dev/kustomization.yaml 
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../base/
configMapGenerator:
  # 对应app应用的ConfigMap
  - name: app-cm
    files: 
      - ./conf.yaml
commonLabels:
  shyunn.app.stage: dev
nameSuffix: -dev
replicas:
  - name: application
    count: 2

# prod的kustmization
$ cat prod/kustomization.yaml 
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- ../base/
configMapGenerator:
    # 对应app应用的ConfigMap
  - name: app-cm
    files: 
      - ./conf.yaml
commonLabels:
  shyunn.app.stage: prod
nameSuffix: -prod
replicas:
  - name: application
    count: 5

我们通过kustomize build进行渲染输出,看一下是否符合我们的预期:

# 开发环境下构建
$ kustomize build ./dev/
apiVersion: v1
data:
  conf.yaml: |
    # dev开发环境下的配置
    database:
      mysql:
        username: dev-usr
        password: abcd-efg
      redis:
        url: 127.0.0.1:9090
kind: ConfigMap
metadata:
  labels:
    shyunn.app.stage: dev
  name: app-cm-dev-gc9d9d6gcc
---
apiVersion: v1
kind: Service
metadata:
  labels:
    shyunn.app.stage: dev
  name: app-svc-dev
spec:
  ports:
  - port: 4000
    protocol: TCP
    targetPort: 80
  selector:
    run: app
    shyunn.app.stage: dev
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    shyunn.app.stage: dev
  name: application-dev
spec:
  replicas: 2
  selector:
    matchLabels:
      run: app
      shyunn.app.stage: dev
  template:
    metadata:
      labels:
        run: app
        shyunn.app.stage: dev
    spec:
      containers:
      - image: shyunn.images.io/app:v0.1.5
        name: app
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /usr/share/nginx/html/
          name: config
      volumes:
      - configMap:
          name: app-cm-dev-gc9d9d6gcc
        name: config

# 生产环境下构建
$ kustomize build ./prod/
apiVersion: v1
data:
  conf.yaml: |
    # prod生产环境下的配置
    database:
      mysql:
        username: prod-usr
        password: 123-456
      redis:
        url: 127.0.0.1:9010
kind: ConfigMap
metadata:
  labels:
    shyunn.app.stage: prod
  name: app-cm-prod-82k4f42245
---
apiVersion: v1
kind: Service
metadata:
  labels:
    shyunn.app.stage: prod
  name: app-svc-prod
spec:
  ports:
  - port: 4000
    protocol: TCP
    targetPort: 80
  selector:
    run: app
    shyunn.app.stage: prod
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    shyunn.app.stage: prod
  name: application-prod
spec:
  replicas: 5
  selector:
    matchLabels:
      run: app
      shyunn.app.stage: prod
  template:
    metadata:
      labels:
        run: app
        shyunn.app.stage: prod
    spec:
      containers:
      - image: shyunn.images.io/app:v0.1.5
        name: app
        ports:
        - containerPort: 80
        volumeMounts:
        - mountPath: /usr/share/nginx/html/
          name: config
      volumes:
      - configMap:
          name: app-cm-prod-82k4f42245
        name: config

以上就完成了通过kustomize管理K8s资源文件。通过base管理基础文件,overlay组合基础层文件进行自定义构建。这样操作的好处是让我们更灵活的管理配置,组合配置。以上例子中,我们可以对conf进行更为灵活的权限设置,dev和prod的配置文件设置不同的权限。让不同的开发人员仅关注属于专业领域的资源管理

作为运维管理员,我们也许需要同时部署到生产和开发环境中,此时我们可以再叠加一层,将应用同时部署在一个命名空间中。

首先修改dev和prod中kustomization文件resources指向的base路径。然后重新修改目录结构

$ tree ./
./
├── base
│   ├── deployment.yaml
│   ├── kustomization.yaml
│   └── service.yaml
└── overlay
    ├── dev
    │   ├── conf.yaml
    │   └── kustomization.yaml
    ├── kustomization.yaml # 管理dev,prod
    ├── namespace.yaml # 需要部署的namespace
    └── prod
        ├── conf.yaml
        └── kustomization.yaml

# 运维人员可以一键将应用部署到指定的namespace中,同时部署prod和dev的应用。
$ cat overlay/kustomization.yaml 
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- dev/
- prod/
- namespace.yaml

namespace: orange

command

kustomize命令中有许多比较实用命令,可以帮助我们快速构建 kustomization 文件以及部署。

kustomize kustomize create --resources app.yaml: 帮助我们快速构建一个 kustomization 文件,同时将app.yaml引用在resources中。

kustomize build ./ | kubectl apply -f -:将kustomize 构建输出作为STDIN传递给kubectl进行部署

此命令等价于kubectl apply -k ./

kustomize cfg count ./:统计当前目录下资源配置

$ kustomize cfg count ./
.//
: 2
Deployment: 1
Kustomization: 4
Namespace: 1
Service: 1

kustomize cfg tree ./:输出当前目录下资源的树形结构

:fire:: 这个命令极大的帮助我们进行构建 kustomization 文件结构

$ kustomize cfg tree ./
.
├── base
│   ├── [deployment.yaml]  Deployment application
│   ├── [kustomization.yaml]  Kustomization 
│   └── [service.yaml]  Service app-svc
└── overlay
    ├── [kustomization.yaml]  Kustomization 
    ├── [namespace.yaml]  Namespace orange
    ├── dev
    │   └── [kustomization.yaml]  Kustomization 
    └── prod
        └── [kustomization.yaml]  Kustomization