iT邦幫忙

2021 iThome 鐵人賽

DAY 22
1
DevOps

k8s 入門學習 30天系列 第 22

IT 鐵人賽 k8s 入門30天 -- day22 k8s 資源管理工具 kustomize

  • 分享至 

  • twitterImage
  •  

前言

文件參考來源: 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


上一篇
IT 鐵人賽 k8s 入門30天 -- day21 k8s Task Deploying PHP Guestbook application with Redis
下一篇
IT 鐵人賽 k8s 入門30天 -- day23 k8s task Deploying WordPress and MySQL with Persistent Volumes
系列文
k8s 入門學習 30天30
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言