えんじにあメモ

試してみた技術とか、たまに家電ネタ

k8sの設定管理ツール「kpt」を試してみる

はじめに

先日行われた Kubernetes Meetup Tokyo #31 の中で kpt というk8sの設定管理ツールの存在を知りました

googlecontainertools.github.io

github.com

まだ出来て日が浅いとのことで開発も進んでいるらしく、どのようなものか実際に使って試してみました

kptとは

公式ドキュメントのFAQ に他のツールとの違いなどが書かれています

  • 他のツールとどう違うか?
    • 設定パッケージをコードとしてではなく、Kubernetesリソースモデルに準拠したYAML/JSONオブジェクトとして表す
  • なぜテンプレートやDSLでないか?
    • kubectl、kustomizeなどのk8sプロジェクトで開発されたツールと同じ書き方ができる

インストール

実際に動かしてみます

こちら からバイナリをダウンロードします

MacだとHomebrewでも入れられますが、6/9時点ではHomebrewがv0.27.0に対して、上記のバイナリがv0.29.0だったため、今回は最新版が使える方で導入しました

$ kpt version
v0.29.0

pkgの作成

サンプルパッケージを作ってみます
kpt pkg init でパッケージを作ります

$ mkdir kpt-sample-pkg
$ kpt pkg init kpt-sample-pkg
writing kpt-sample-pkg/Kptfile
writing kpt-sample-pkg/README.md

kpt-sample-pkgディレクトリを見るとKptfileというものが出来ました

apiVersion: kpt.dev/v1alpha1
kind: Kptfile
metadata:
  name: kpt-sample-pkg
packageMetadata:
  shortDescription: sample description

kptで管理するリソース作成

今回のサンプルではnginxイメージのdeploymentとClusterIPのserviceをパッケージに含めます

(以下kpt-sample-pkgディレクトリで作業)

↓のdeployment.yamlservice.yamlを作成します

deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
  labels:
    app: nginx
  name: nginx
spec:
  replicas: 2
  selector:
    matchLabels:
      app: nginx
  template:
    metadata:
      labels:
        app: nginx
    spec:
      containers:
      - image: nginx:1.18.0
        name: nginx

service.yaml

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

setter/substitutionの作成

kptで値を書き換えるよう、setter/substitutionというものを作ります

setterの作成にはkpt cfg create-setterを利用します

$ kpt cfg create-setter . replicas 2 --field "spec.replicas" --set-by "package-default" --description "replicas" --type integer

spec.replicas の値についてsetterを作成しました
set-by/descriptionに加えて、値がintegerであることもオプションで指定しています

setterはOpenAPIに基づいて定義されるようです

Kptfileが書き換わったので差分を確認しておきます

--- Kptfile
+++ Kptfile
@@ -4,3 +4,13 @@ metadata:
   name: kpt-sample-pkg
 packageMetadata:
   shortDescription: sample description
+openAPI:
+  definitions:
+    io.k8s.cli.setters.replicas:
+      description: replicas
+      type: integer
+      x-k8s-cli:
+        setter:
+          name: replicas
+          value: "2"
+          setBy: package-default

--- deployment.yaml
+++ deployment.yaml
@@ -5,7 +5,7 @@ metadata:
     app: nginx
   name: nginx
 spec:
-  replicas: 2
+  replicas: 2 # {"$kpt-set":"replicas"}
   selector:
     matchLabels:
       app: nginx

Kptfileにsetterの情報が、deployment.yamlのsetter対象であるspec.replicasの部分に何やらコメントが追記されています

続いてimageを指定する部分もsetter化します
imageはnginx:1.18.0のようにイメージ名:イメージタグの形式になっているため、まずはそれぞれをsetterとして定義します

$ kpt cfg create-setter . image-setter nginx --field "none" --set-by "package-default" --description "image name"
$ kpt cfg create-setter . tag-setter 1.18.0 --field "none" --set-by "package-default" --description "image tag version"

作成したsetter(image-settertag-setter)を利用してspec.containers.imageを管理するために、substitutionを作成します

substitutionの作成にはkpt cfg create-substを利用します

$ kpt cfg create-subst . image-tag --field-value nginx:1.18.0 --pattern \${image-setter}:\${tag-setter}

ちなみに、最初のkpt cfg create-setterはやらなくても自動(推測して)で作ってくれますが、set-byやdescriptionは埋められないので明示的に作りました

再度差分を確認すると、

--- Kptfile
+++ Kptfile
@@ -14,3 +14,27 @@ openAPI:
           name: replicas
           value: "2"
           setBy: package-default
+    io.k8s.cli.setters.image-setter:
+      description: image name
+      x-k8s-cli:
+        setter:
+          name: image-setter
+          value: nginx
+          setBy: package-default
+    io.k8s.cli.setters.tag-setter:
+      description: image tag version
+      x-k8s-cli:
+        setter:
+          name: tag-setter
+          value: 1.18.0
+          setBy: package-default
+    io.k8s.cli.substitutions.image-tag:
+      x-k8s-cli:
+        substitution:
+          name: image-tag
+          pattern: ${image-setter}:${tag-setter}
+          values:
+          - marker: ${image-setter}
+            ref: '#/definitions/io.k8s.cli.setters.image-setter'
+          - marker: ${tag-setter}
+            ref: '#/definitions/io.k8s.cli.setters.tag-setter'

--- deployment.yaml
+++ deployment.yaml
@@ -15,5 +15,5 @@ spec:
         app: nginx
     spec:
       containers:
-      - image: nginx:1.18.0
+      - image: nginx:1.18.0 # {"$kpt-set":"image-tag"}
         name: nginx

replicasのときと同様にKptfiledeployment.yamlが更新されました

作成したpkgをgit push

kptのpkgはgitで管理を行うため、gitへ上げておきます

kptではブランチ名でも管理可能ですが、バージョン管理できるようv0.1.0のタグも打っておきます

この時点でのサンプルパッケージ
GitHub - sminamot/kpt-sample-pkg at v0.1.0

作成したpkgの利用

さきほど作ったkpt-sample-pkgパッケージを実際に使ってみます

pkgの取得
v0.1.0のバージョンを指定して取得します

$ kpt pkg get https://github.com/sminamot/kpt-sample-pkg.git@v0.1.0 ./
fetching package / from https://github.com/sminamot/kpt-sample-pkg to kpt-sample-pkg

取得したpkg情報を参照

$ kpt pkg desc
/Users/sminamot/Documents/kpt-sample-pkg/Kptfile
   PACKAGE NAME                      DIR                                        REMOTE                     REMOTE PATH   REMOTE REF   REMOTE COMMIT
  kpt-sample-pkg   /Users/sminamot/Documents/kpt-sample-pkg   https://github.com/sminamot/kpt-sample-pkg   /             v0.1.0       e94562c

setterの指定

setterの値を書き換えてみます

setterの一覧を確認

$ kpt cfg list-setters .
      NAME       VALUE        SET BY           DESCRIPTION      COUNT
  image-setter   nginx    package-default   image name          1
  replicas       2        package-default   replicas            1
  tag-setter     1.18.0   package-default   image tag version   1
  SUBSTITUTION              PATTERN                       SETTERS
  image-tag      ${image-setter}:${tag-setter}   [image-setter,tag-setter]

replicastag-setterを書き換える

$ kpt cfg set . replicas 3
$ kpt cfg set . tag-setter 1.19.0
$ kpt pkg diff
diff /var/folders/hf/s2x0n1yd7fgdptq9xp4dsf3c0000gn/T/kpt-089821092/deployment.yaml /var/folders/hf/s2x0n1yd7fgdptq9xp4dsf3c0000gn/T/kpt-029525683/deployment.yaml
8c8
<   replicas: 3 # {"$kpt-set":"replicas"}
---
>   replicas: 2 # {"$kpt-set":"replicas"}
18c18
<       - image: nginx:1.19.0 # {"$kpt-set":"image-tag"}
---
>       - image: nginx:1.18.0 # {"$kpt-set":"image-tag"}

書き換えたyamlはkubectlでそのままデプロイ可能です

$ kubectl apply -f .
deployment.apps/nginx created
service/nginx created

ちなみにreplicasのsetter定義時にintegerであることを指定したので、文字列などを設定しようとすると怒られます

$ kpt cfg set . replicas hoge
set 0 fields
Error: The input value doesn't validate against provided OpenAPI schema: validation failure list:
replicas in body must be of type integer: "string"

今回の例ではv0.1.0しか作成しませんでしたが、v0.2.0をリリースした場合に利用する側で更新するには、

$ kpt pkg update kpt-sample-pkg@v0.2.0

と実行すればOKです

その他の機能

live

kptのパッケージをデプロイするためのサブコマンド

パッケージが管理するリソースを追跡するために最初に kpt live init を実施してテンプレートリソースを作ります

$ kpt live init .
$ tree .
.
├── Kptfile
├── README.md
├── deployment.yaml
├── inventory-template.yaml
└── service.yaml

0 directories, 5 files

# inventory-template.yamlというのができてる

これによってstatusの制御やapply時の自動pruneが行われるようになります

kpt live preview で実際にデプロイされるリソースを確認

$ kpt live preview .
configmap/inventory-e00bb1dd created (preview)
service/nginx created (preview)
deployment.apps/nginx created (preview)
3 resource(s) applied. 3 created, 0 unchanged, 0 configured (preview)
0 resource(s) pruned, 0 skipped (preview)

kpt live applyでデプロイ

reconcile-timeoutオプションを指定することで作成されたpodが利用可能になるまで待機してくれます
公式Docでは--wait-for-reconcileオプションを指定するようになってますが、--wait-timeoutと合わせて--reconcile-timeoutオプションに統合されたようです→関連Issue

$ kpt live apply --reconcile-timeout=15m .
configmap/inventory-e00bb1dd created
service/nginx created
deployment.apps/nginx created
3 resource(s) applied. 3 created, 0 unchanged, 0 configured
configmap/inventory-e00bb1dd is NotFound: Resource not found
service/nginx is NotFound: Resource not found
deployment.apps/nginx is NotFound: Resource not found
configmap/inventory-e00bb1dd is Current: Resource is always ready
service/nginx is Current: Service is ready
deployment.apps/nginx is InProgress: Available: 0/3
deployment.apps/nginx is InProgress: Available: 1/3
deployment.apps/nginx is InProgress: Available: 2/3
deployment.apps/nginx is Current: Deployment is available. Replicas: 3
all resources has reached the Current status
0 resource(s) pruned, 0 skipped

また、--outputオプションにtableを指定するとより見やすい形式(色も付く)で表示されます

$ kpt live apply --reconcile-timeout=15m --output table .
NAMESPACE   RESOURCE                                  ACTION        STATUS      CONDITIONS                                AGE     MESSAGE
default     ConfigMap/inventory-e00bb1dd              Created       Current     <None>                                    4s      Resource is always ready
default     Service/nginx                             Created       Current     <None>                                    4s      Service is ready
default     Deployment/nginx                          Created       Current     Available,Progressing                     4s      Deployment is available. Replicas: 3
default     └─ ReplicaSet/nginx-6fd78f555b                          Current     <None>                                    4s      ReplicaSet is available. Replicas: 3
default        ├─ Pod/nginx-6fd78f555b-6rgfd                        Current     Initialized,Ready,ContainersReady,PodSch  4s      Pod is Ready
default        ├─ Pod/nginx-6fd78f555b-8lf46                        Current     Initialized,Ready,ContainersReady,PodSch  4s      Pod is Ready
default        └─ Pod/nginx-6fd78f555b-mlqr8                        Current     Initialized,Ready,ContainersReady,PodSch  4s      Pod is Ready

ただ、このreconcile機能ですが、v0.29.0時点ではタイムアウトで落ちてもexit statusが0のため、改善されないとCIなどでは使えなさそう

cfg fmt

kpt cfgのサブコマンドにfmtという、k8syamlファイルのフォーマット機能があります

これはkptで管理するリソースには限らず、既存のyamlに適用することができます

例えば以下のようなpod.yamlがあった場合(apiVersion/kindが下にあったり、インデントが統一されていない)に、

metadata:
  labels:
    run: nginx
  name: nginx
spec:
      containers:
      - image: nginx:1.19.0
        name: nginx
      dnsPolicy: ClusterFirst
      restartPolicy: Never
kind:       Pod
apiVersion: v1

kpt cfg fmtをかけると、

apiVersion: v1
kind: Pod
metadata:
  name: nginx
  labels:
    run: nginx
spec:
  restartPolicy: Never
  dnsPolicy: ClusterFirst
  containers:
  - name: nginx
    image: nginx:1.19.0

このように整形してくれます

kptへの移行はすぐに出来ないかもしれませんが、フォーマッタだけ導入するものアリかもしれません

まとめ

k8sの設定管理ツールであるkptを使ってみました

ドキュメントが最新バージョンのものに追いついていなかったり、機能的に物足りない点が多いですが、今後の改善に期待しましょう

今週末6/13(土)に開催される KubeFest Tokyo 2020 にも kptに関するLT があるようです

今回紹介出来なかった機能についても説明がありそうなので楽しみです😃