y-ohgi's blog

TODO: ここになにかかく

kustomizeで管理するGKE-autopilot

TL;DR

  • GKEのmanifestをkustomizeで管理する際のサンプルです
  • 例としてdevとprod環境を分けてプロビジョニングします

概要

kustomizeとは

kustomizeとはKubernetesのマニフェスト(yamlベースのIaC)を管理するために使用されるツールです。
素のmanifestファイルとの相違点として、主に環境毎に設定を変更できる点です。
また、他の管理ツールと比較して直感的な使いやすさとkubectlコマンドに組み込まれていることも強みです。

e.g.

$ kubectl apply -k base/
$ kubectl kustomize base/

Version

  • kubectl
    • 1.27.4
  • GKE-autopilot
    • 1.27.3-gke.100

Code

github.com

How to

kustomizeで環境差分を表現するサンプルになります。
構築するものはnginxを立ち上げるDeploymentとServiceの2つのみで、kustomizeに重点を置いて書いています。

GKEクラスターの作成と接続

kustomize-exampleという名前のクラスターを東京リージョンに作成します。

$ gcloud container clusters create-auto "kustomize-example" \
  --region "asia-east1" \
  --release-channel "regular"

作成したクラスターに接続します。

$ gcloud container clusters get-credentials kustomize-example

接続の確認を行います。

$ kubectl get all
NAME                 TYPE        CLUSTER-IP     EXTERNAL-IP   PORT(S)   AGE
service/kubernetes   ClusterIP   34.118.224.1   <none>        443/TCP   165m

kustomize

devとprod環境が欲しいため、今回は以下のようなディレクトリ構成で行います。

$ tree -d
.
├── base
└── overlays
    ├── development
    └── production
  • baseディレクトリ
    • この配下にテンプレートとなるマニフェストファイルを記載します。
  • overlaysディレクトリ
    • この配下には構築したい環境分ディレクトリを切ります
    • その各ディレクトリにbaseディレクトリのテンプレートとの環境差分を定義したマニフェストファイルを記載します。

今回は以下の3つのObjectの作成と環境差分の定義をします。 1. namespace 2. deployment 3. service

baseディレクトリとマニフェストの作成

baseディレクトリにはテンプレートとなるファイルを作成します。

base/
├── deployment.yaml
├── kustomization.yaml
└── service.yaml

kustomizeでメインとなるマニフェストファイルは kustomization.yaml です。
このファイルを起点に他の2つのファイルが呼び出されます。

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

resources:
  - deployment.yaml
  - service.yaml

depoyment.yamlservice.yaml はk8sのマニフェストをそのまま書く形になります。
サンプルコードはnginxのバージョン1.25のPodを3つ建て、serviceと紐付けるシンプルなものです。

定義されるマニフェストを一括で閲覧します。
kubectlコマンドに組み込まれている kubectl kustomize で生成することが可能です。

$ kubectl kustomize base/
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx
  name: nginx-service
spec:
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: nginx
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx-deployment
spec:
  replicas: 3
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.25
        name: nginx
        ports:
        - containerPort: 80
        resources:
          limits:
            cpu: 200m
            memory: 512Mi
          requests:
            cpu: 200m
            memory: 512Mi

overlaysディレクトリでマニフェストの書き換え

まずはdev環境で使用するために、 overlays/development/ ディレクトリで差分の定義をします。
今回の例ではdev環境ではdevelopmentというnamespaceを作成し、 そのnamespace上にnginx:1.24のPodを1つ立ち上げる よう変更します。

ディレクトリ構成は以下です。

$ tree overlays/development/
overlays/development/
├── deployment.yaml
├── kustomization.yaml
└── namespace.yaml

まずは overlays/development/kustomization.yaml の定義を行います。
プロビジョニングする際は各ディレクトリの kustomization.yaml が起点になるため、このファイルがdev環境の起点のファイルになります。各定義の説明はコメントに記載します。

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

# 作成する全てのObjectにlabelを付与することも可能です。
labels:
  - includeSelectors: true
    pairs:
      env: development

# developmentのnamespace内にObjectを配置します。
namespace: development

# MEMO: 重要な点です。
# 使用するマニフェストファイルを選択します。ここでbaseディレクトリのテンプレートを元に、同一ディレクトリのnamespace.yamlを統合したものを1つのマニフェストにまとめます。
resources:
  - ../../base
  - namespace.yaml

# resourcesで作成されたマニフェストに変更を加えます。
# 今回はPodを3から1つに変更するために使用します。
patches:
  - path: deployment.yaml
    target:
      kind: Deployment

# 指定したイメージnameのuriを書き換えます。
# 今回は1.25から1.24に変更します。
images:
  - name: nginx
    newName: nginx
    newTag: "1.24"

patches で指定した deployment.yaml です。Pod(replicas)を3つから1つに変更するための定義です。

apiVersion: apps/v1
kind: Deployment
metadata:
  # このnameのDeploymentを対象にします
  name: nginx-deployment

# 変更点を定義します
spec:
  replicas: 1

この定義でビルドされるマニフェストを kubectl kustomize overlays/development.yaml で閲覧します。

# $ kubectl kustomize overlays/development/
apiVersion: v1
kind: Namespace
metadata:
  labels:
    env: development
  name: development
---
apiVersion: v1
kind: Service
metadata:
  labels:
    app: nginx
    env: development
  name: nginx-service
  namespace: development
spec:
  ports:
  - port: 80
    targetPort: 80
  selector:
    app: nginx
    env: development
---
apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
    env: development
  name: nginx-deployment
  namespace: development
spec:
  replicas: 1
  selector:
    matchLabels:
      app: nginx
      env: development
  template:
    metadata:
      labels:
        app: nginx
        env: development
    spec:
      containers:
      - image: nginx:1.24
        name: nginx
        ports:
        - containerPort: 80
        resources:
          limits:
            cpu: 200m
            memory: 512Mi
          requests:
            cpu: 200m
            memory: 512Mi

namespaceが development の作成とそこへの配置、labelsに env: development の追加、Deploymentのreplicasが3つから1つ・imageが1.25から1.24に変更されたことがわかります。

プロビジョニング

baseディレクトリの確認

はじめに、テンプレートとなるbaseディレクトリをnamespace default にプロビジョニングを試します。
こちらも kubectl kustomize <PATH> 同様に kubectl apply -k <PATH> コマンドで適用ができます。

baseディレクトリを起点にapplyを行います。

$ kubectl apply -k base/

default namespaceにDeployment・Service・3台のPodが作成されていることを確認します。

$ kubectl get all -n default
NAME                                    READY   STATUS    RESTARTS   AGE
pod/nginx-deployment-6487695f74-pngkc   1/1     Running   0          23s
pod/nginx-deployment-6487695f74-qjbcv   1/1     Running   0          23s
pod/nginx-deployment-6487695f74-zz6mf   1/1     Running   0          23s

NAME                    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
service/kubernetes      ClusterIP   34.118.224.1     <none>        443/TCP   3h29m
service/nginx-service   ClusterIP   34.118.238.247   <none>        80/TCP    23s

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-deployment   3/3     3            3           23s

NAME                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-deployment-6487695f74   3         3         3       24s

nginxのバージョンが1.25であることを確認します。

$ kubectl get deployment -o yaml | grep "image: nginx"
        - image: nginx:1.25

baseディレクトリのプロビジョニングが成功しました。

起動確認のためにServiceにポートフォワードを行い、nginxの起動とバージョンを確認します。

$ kubectl port-forward service/nginx-service 8080:80
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
$ curl -I localhost:8080
HTTP/1.1 200 OK
Server: nginx/1.25.3
Date: Tue, 14 Nov 2023 12:25:35 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 24 Oct 2023 13:46:47 GMT
Connection: keep-alive
ETag: "6537cac7-267"
Accept-Ranges: bytes

200 OK でServerヘッダーに nginx/1.25.3 が入っていることを確認できました。

overlaysでそれぞれの環境をプロビジョニング

では差分があるdev環境のプロビジョニングを行ってみます。
改めて差分のおさらいです。 1. namespaceがdevelopmentを使用していること 2. nginxのreplicasが3台から1台になること 3. nginxのバージョンが1.25から1.24になること

baseと同様に、使用するパスを指定してプロビジョニングを行います。

apply

$ kubectl apply -k overlays/development

development namespaceにDeployment・Service・1台のPodが作成されていることを確認します。

$ kubectl get all -n development
NAME                                    READY   STATUS    RESTARTS   AGE
pod/nginx-deployment-74bfdb9795-qvxzr   1/1     Running   0          131m

NAME                    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
service/nginx-service   ClusterIP   34.118.229.212   <none>        80/TCP    133m

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-deployment   1/1     1            1           133m

NAME                                          DESIRED   CURRENT   READY   AGE
replicaset.apps/nginx-deployment-74bfdb9795   1         1         1       133m

nginxのバージョンが1.24であることを確認します。

$ kubectl get deployment -o yaml -n development | grep "image: nginx"
        - image: nginx:1.24

プロビジョニングが成功しました。
baseディレクトリと同様に、ポートフォワードで疎通確認を行います。

$ kubectl port-forward service/nginx-service 8080:80 -n development
Forwarding from 127.0.0.1:8080 -> 80
Forwarding from [::1]:8080 -> 80
$ curl -I localhost:8080
HTTP/1.1 200 OK
Server: nginx/1.24.0
Date: Tue, 14 Nov 2023 12:35:11 GMT
Content-Type: text/html
Content-Length: 615
Last-Modified: Tue, 11 Apr 2023 01:45:34 GMT
Connection: keep-alive
ETag: "6434bbbe-267"
Accept-Ranges: bytes

200 OK でServerヘッダーに nginx/1.24.0 が入っていることを確認できました。

お片付け

kustomizeコマンドで作成したものは kubectl get -k <PATH> で閲覧することも可能です。

$ kubectl get -k overlays/development/
NAME                    STATUS   AGE
namespace/development   Active   138m

NAME                    TYPE        CLUSTER-IP       EXTERNAL-IP   PORT(S)   AGE
service/nginx-service   ClusterIP   34.118.229.212   <none>        80/TCP    138m

NAME                               READY   UP-TO-DATE   AVAILABLE   AGE
deployment.apps/nginx-deployment   1/1     1            1           138m

同様に kubectl delete -k <PATH> で削除することも可能です。

$ kubectl delete -k overlays/development/
namespace "development" deleted
service "nginx-service" deleted
deployment.apps "nginx-deployment" deleted

$ kubectl get all -n development
No resources found in development namespace.

今回作成したクラスターごと削除してお片付け完了です。

$ gcloud container clusters delete "kustomize-example"
The following clusters will be deleted.
 - [kustomize-example] in [asia-northeast1]

Do you want to continue (Y/n)?  Y

Deleting cluster kustomize-example...

所感

個人的にkustomizeを使用することで環境差分を直感的に定義できることが魅力だと感じており、私自身好きなツールの1つです。
また、環境管理を行うに際には素のマニフェストファイルでの管理から乗り換えやすい点、kubectlコマンドがデフォルトで対応するようになった点も採用しやすいポイントです。

ただ、kustomize自体はlatestなのですがapiVersion自体はまだbetaです ( apiVersion: kustomize.config.k8s.io/v1beta1 )。
最近であれば kustomization.yaml で使用可能だった patchesJson6902: commonLabels: 等がdeprecatedになっていたり改善が続いています。
他のライブラリやツールでも同様ですが、kustomizeを使用する際はしっかりとアップデートを追う必要があります。
ちなみにkustomizeには kustomize edit fix という優秀なコマンドがあり、簡単な修正であればこのコマンドを使うだけで自動で修正してくれる点も優秀です。