IT 铁人赛 k8s 入门30天 -- day22 k8s 资源管理工具 kustomize

前言

文件参考来源: https://kubernetes.io/docs/tasks/manage-kubernetes-objects/kustomization/

今天要来介绍 k8s 中用来做资源管理的工具 kustomize

kustomize 是一个 standalone 的工具透过 kustomization file 来管理 k8s 物件

在 k8s 中可以透过以下指令来查看资料夹中包含的 kustomization file

kubectl kustomize $kustomization_directory

要布署这些资源要使用以下指令:

kubectl apply -k $kustomization_directory

什麽是 kustomize ?

Kustomize 是一个用来客制化 k8s 设定档的工具, 具有以下特性可以管理设定档:

从其他资源档来产生资源

ConfigMap 跟 Secret 具有其他 k8s 物件比如说 Pod 的设定档跟机敏资料

而这些设定档跟机敏资料来源通常是来自 k8s 丛集之外, 比如说 .properties 或是 SSH keyfile

Kustomize 有 secretGeneratorconfigMapGenerator 可以从外部档案产生 Secret 与 ConfigMap

configMapGenerator

来源档案 application.properties 如下:

FOO=Bar

则可以透过设定 kustomization.yaml 如下

configMapGenerator:
- name: example-configmap-1
  files:
  - application.properties

然後在同一个资料夹执行以下指令

kubectl kustomize ./

产生出以下 ConfigMap :

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

来源档案 .env 如下

FOO=Bar

则可以设定 kustomization.yaml 如下:

configMapGenerator:
- name: example-configmap-1
  envs:
  - .env

然後在同一个资料夹执行以下指令

kubectl kustomize ./

产生出以下 ConfigMap :

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

要注意的是 每个 .env 的设定值在产生出来的 ConfigMap 都是原本的 key-value 形式保存, 而 .properties 的所有内容则是都被当成 value

另外也有一种 literal 的作法

直接设定 kustomization.yaml 如下:

configMapGenerator:
- name: example-configmap-2
  literals:
  - FOO=Bar

然後在同一个资料夹执行以下指令

kubectl kustomize ./

产生出以下 ConfigMap:

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

上面由於是用 generator 产生出来的 configMap 所以名称都带有 hash

这边的 hash 值都是随意给的, 所以实际在机器上跑出来的应该不会根本文一样

下面给一个实际的范例

给一个设定档案 application.properties 如下:

FOO=BAR

给一设定档 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

就可以透过写一个 kustomization.yaml 如下:

resources: 
- deployment.yaml
configMapGenerator:
- name: example-configmap-1
  files:
  - application.properties

然後在同一个资料夹执行以下指令

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

给定一个设定档 password.txt 如下:

username=admin
password=secret

写一个设定档 kustomization.yaml 如下:

secretGenerator:
- name: example-secret-1
  files:
  - password.txt

然後在同一个资料夹执行以下指令

kubectl kustomize ./

产生出以下 Secret:

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

另外也可以使用 literals 来建制 Secrets

建制 kustomization.yaml 如下

secretGenerator:
- name: examples-secret-2
  literals:
  - username=admin
  - password=secret

然後在同一个资料夹执行以下指令

kubectl kustomize ./

产生出以下 Secret:

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

下面给一个实际的范例

给定设定档 password.txt 如下:

username=admin
password=secret

而设定档 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

就可以透过以下设定档 kustomization.yaml

resources:
- deployment.yaml
secretGenerator:
- name: example-secret-1
  files:
  - password.txt

把 password.txt 跟 deployment.yaml 给结合在一起

另外对於 generator 其实有一些选项可以设定

比如说不想要档案产生出来名称有 hash 就可以设定 disableNameSuffixHash: true 如下

configMapGenerator:
- name: example-configmap-3
  literals:
  - FOO=Bar
generatorOptions:
  disableNameSuffixHash: true
  labels:
    type: generated
  annotations:
    note: generated

然後在同一个资料夹执行以下指令

kubectl kustomize ./

产生出来 ConfigMap 的 name 不会有 hash 如下

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

设定 cross-cutting field 给资鸳档

所谓的 cross-cutting field 指的是有一些共通栏位会出现各种设定档之内

比如说 namespace, name prefix 或 suffix 或是 labels 或是 annotations

假设有一个设定档 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

就可以透过设定 kustomization.yaml 如下

namespace: my-namespace
namePrefix: dev-
nameSuffix: "-001"
commonLabels:
  app: bingo
commonAnnotations:
  oncallPager: 800-555-1212
resources:
- deployment.yaml

然後在同一个资料夹执行以下指令

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 可以针对 Deployment 做一些附加属性, 让布署增加弹性

统合与客制化多个资源档

可以透过 kustomizae 来组合同一个资料夹下的布署资源

或是把其他资源附加到目前的资源内

组合资源

以下是透过 kustomize 组合同一个资料夹下的 Deployment 跟 Service

建立一个 nginx 的 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

建立一个 nginx 的 service.yaml 如下

apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: my-nginx

然後就可以透过建立 kustomization.yaml 来把上面两个资源组合在一起如下:

resources:
- deployment.yaml
- service.yaml

然後在同一个资料夹执行以下指令

kubectl kustomize ./

产生出来的布署档包含 Service, Deployment

客制化

Kustomize 可以让设定档切分成多个 patch 档, 在发布时组合所有 patch 成为一个发布档

patch 档合成的机制分为 patchesStrategicMergepatchesJson6902

patchesStrategicMerge

这种模式写法就是一堆档案的路径

而每个 patch 档案需要符合 strategic merge patch

范例如下:

设定档 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

建立 increase_replicas.yaml 来增加 replicas
increase_replicas.yaml:

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  replicas: 3

建立 set_memory.yaml 来设定 memroy limit
set_memory.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  name: my-nginx
spec:
  template:
    spec:
      containers:
      - name: my-nginx
        resources:
          limits:
            memory: 512Mi

建立 kustomization.ymal 如下

resources:
- deployment.yaml
patchesStrategicMerge:
- increase_replicas.yaml
- set_memory.yaml

然後在同一个资料夹执行以下指令

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

patchesJson6902

因为不是所有 Resource 栏位都能支援 strategic merge patches

所以 Kustomize 提供 patchesJson6902 来支援 JSON patch

范例如下:

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

建立一个 json patch 的设定档 patch.yaml 如下:

- op: replace
  path: /spec/replicas
  value: 3

设定 kustomization.yaml 如下:

resources:
- deployment.yaml

patchesJson6902:
- target:
    group: apps
    version: v1
    kind: Deployment
    name: my-nginx
  path: patch.yaml

然後在同一个资料夹执行以下指令

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

更换 image

在 kustomization.yaml 可以指定 images 来替换原本 Deployment 内部的 images

假设 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

建立 kustomization.yaml 如下:

resources:
- deployment.yaml
images:
- name: nginx
  newName: my.image.registry/nginx
  newTag: 1.4.0

然後在同一个资料夹执行以下指令

kubectl kustomize ./

产生出来的 Deployment 就会如下

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

变数替换

有时候为了让 Deployment 更有弹性

所会在 Deployment 引入变数

也可以在 Kustomize 设定变数值做变数替换

范例如下:

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)"]

service.yaml 如下:

apiVersion: v1
kind: Service
metadata:
  name: my-nginx
  labels:
    run: my-nginx
spec:
  ports:
  - port: 80
    protocol: TCP
  selector:
    run: my-nginx

建立一个 ksutomization.yaml 如下:

namePrefix: dev-
nameSuffix: "-001"

resources:
- deployment.yaml
- service.yaml

vars:
- name: MY_SERVICE_NAME
  objref:
    kind: Service
    name: my-nginx
    apiVersion: v1

然後在同一个资料夹执行以下指令

kubectl kustomize ./

产生出来的 Deployment 就会如下

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

command 的变数被 kustomization.yaml 的设定所替换了

Bases , Overlays

Kustomize 具有 baseoverlay 的概念

base 就是指在一个资料夹具有一个 kustomization.yaml 档案包含所有布署设定

overlay 指指在一个资料夹具有一个 kustomization.yaml 档案把 base 参考到其他具有 kustomization.yaml 的路径

base 可以被其他 overlay 引用

overlay 可以具有多个 base

base 范例如下

假设在资料夹 base

建立一个 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

建立 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

建立 base/kustomization.yaml 如下:

resources:
- deployment.yaml
- service.yaml

而 overlay 范例则如下

建立一个 dev 资料夹

mkdir dev

建立一个 dev/kustomization.yaml 如下

bases:
- ../base
namePrefix: dev-

建立一个 prod 资料夹

mkdir prod

建立一个 prod/kustomization.yaml 如下

bases:
- ../base
namePrefix: prod-

上面两个 overlay 都引用了 base , 并且加入 namePrefix

使用 Kustomize 来做资源修改

以下指令用来布署

kubectl apply -k $kustomization_dir/

范例如下:

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

建立 kustomization.yaml 如下:

namePrefix: dev-
commonLabels:
  app: my-nginx
resources:
- deployment.yaml

在同一个资料夹使用以下指令做布署

kubectl apply -k ./

查看布署可以使用以下两个指令

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

比较 k8s 物件状态与布署差别可以用以下指令

kubectl diff -k ./

删除布署

kubectl delete -k ./

後记

在布署 k8s 中会产生许多的设定档

这时候管理设定档就是一个很重要的事情

这时如果能透过一些工具来做不同环境的设定切割就会是很方便的事情

比如这个章节所提到的 kustomize


<<:  JavaScript学习日记 : Day24 - Map

>>:  後记

[Day 27] Edge Impulse + BLE Sense实现影像分类(上)

在前面章节已介绍如何让Arduino Nano 33 BLE Sense(以下简称BLE Sense...

用React刻自己的投资Dashboard Day12 - 下拉式选单筛选功能

tags: 2021铁人赛 React 还记得这个网站有筛选图表的功能吗?当初画wireframe的...

如何用 AppFollow 做关键字研究

在 AppFollow 上查目标市场的 auto suggestion 找在一些大关键字中排名比较...

[Day25] NLP会用到的模型(八)-transformer decoder

一. decoder 架构如下: decoder主要是解析encoder的资讯,转换成output的...

Day25 Plugin 从零开始到上架 - Android instagram APIs

GraphInstagramService: interface GraphInstagramSer...