kappについて
VMware Tanzu Application Platform のベータリリースが発表されました。
Kubernetesの運用を簡素化する製品の1つとして注目していきたいです。今回はインストール時に利用されている kapp について、説明いたします。
kappとは
Carvel tools の1つです。その中でkappは、Kubernetesアプリケーション をコンセプトに作られたCLIです。同じラベルのリソースのセットをアプリケーションのように一括で管理できます。リソースの差分、ラベル付け、展開、および削除といった機能を備えています。
インストール方法
OSごとの インストール手順 を参考に実施してください。
また、この記事では minikube を利用して動作確認を行っています。
特徴
kappの特徴として、ドキュメント には、Diff stage と、 Apply stage という内容でまとめられています。
Diff stage
kapp deploy
を実行する際に、ファイルで指定されたリソースをKubernetesAPIに存在するリソースと比較します。その際、アノテーション(Annotations) であるkapp.k14s.io/versioned
を利用することで、リソースをバージョン管理できます。
また、バージョン管理されたリソースが更新されると既存のリソースが新しく作成されます。
バージョン管理したいリソースに、アノテーションとして、kapp.k14s.io/versioned
と値として空文字列を設定するだけで、リソースのバージョン管理ができます。
実際に試してみます。下記のようなConfigMapを備えたnginx.yaml
を作成します。
apiVersion: v1
kind: ConfigMap
metadata:
name: test-config
annotations:
kapp.k14s.io/versioned: ""
data:
config-value: init-config
---
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:stable
ports:
- containerPort: 8080
env:
- name: TEST_CONFIG
valueFrom:
configMapKeyRef:
name: test-config
key: config-value
kapp
コマンドを使ってdeploymentを作成して、pod内の環境変数TEST_CONFIG
を確認してみます。
$ kapp deploy -a nginx-sample -f ./nginx.yaml
Target cluster 'https://127.0.0.1:49154' (nodes: minikube)
Changes
Namespace Name Kind Conds. Age Op Op st. Wait to Rs Ri
default nginx-deployment Deployment - - create - reconcile - -
^ test-config-ver-1 ConfigMap - - create - reconcile - -
Op: 2 create, 0 delete, 0 update, 0 noop
Wait to: 2 reconcile, 0 delete, 0 noop
Continue? [yN]: y
10:17:55AM: ---- applying 1 changes [0/2 done] ----
10:17:55AM: create configmap/test-config-ver-1 (v1) namespace: default
10:17:55AM: ---- waiting on 1 changes [0/2 done] ----
10:17:55AM: ok: reconcile configmap/test-config-ver-1 (v1) namespace: default
10:17:55AM: ---- applying 1 changes [1/2 done] ----
10:17:55AM: create deployment/nginx-deployment (apps/v1) namespace: default
10:17:55AM: ---- waiting on 1 changes [1/2 done] ----
10:17:55AM: ongoing: reconcile deployment/nginx-deployment (apps/v1) namespace: default
10:17:55AM: ^ Waiting for generation 2 to be observed
10:17:55AM: L ok: waiting on replicaset/nginx-deployment-85496bcc7b (apps/v1) namespace: default
10:17:55AM: L ongoing: waiting on pod/nginx-deployment-85496bcc7b-2g5lm (v1) namespace: default
10:17:55AM: ^ Pending: ContainerCreating
10:17:56AM: ongoing: reconcile deployment/nginx-deployment (apps/v1) namespace: default
10:17:56AM: ^ Waiting for 1 unavailable replicas
10:17:56AM: L ok: waiting on replicaset/nginx-deployment-85496bcc7b (apps/v1) namespace: default
10:17:56AM: L ongoing: waiting on pod/nginx-deployment-85496bcc7b-2g5lm (v1) namespace: default
10:17:56AM: ^ Pending: ContainerCreating
10:18:15AM: ok: reconcile deployment/nginx-deployment (apps/v1) namespace: default
10:18:15AM: ---- applying complete [2/2 done] ----
10:18:15AM: ---- waiting complete [2/2 done] ----
Succeeded
成功したので、kubectl exec
にて環境変数がどうなっているか確認します。
$ kubectl exec -it $(kubectl get pods -l app=nginx -o json | jq -r .items[0].metadata.name) -- env | grep TEST_CONFIG
TEST_CONFIG=init-config
ConfigMapで作成した値が環境変数TEST_CONFIG
の値として設定されています。
次は、先ほど作成したnginx.yaml
のConfigMapの値の部分だけ修正します。
data:
config-value: update-config
再度、kapp deploy
を実行します。
$ kapp deploy -a nginx-sample -f ./nginx.yaml
Target cluster 'https://127.0.0.1:49154' (nodes: minikube)
Changes
Namespace Name Kind Conds. Age Op Op st. Wait to Rs Ri
default nginx-deployment Deployment 2/2 t 30m update - reconcile ok -
^ test-config-ver-2 ConfigMap - - create - reconcile - -
Op: 1 create, 0 delete, 1 update, 0 noop
Wait to: 2 reconcile, 0 delete, 0 noop
Continue? [yN]: y
10:47:59AM: ---- applying 1 changes [0/2 done] ----
10:47:59AM: create configmap/test-config-ver-2 (v1) namespace: default
10:47:59AM: ---- waiting on 1 changes [0/2 done] ----
10:47:59AM: ok: reconcile configmap/test-config-ver-2 (v1) namespace: default
10:47:59AM: ---- applying 1 changes [1/2 done] ----
10:47:59AM: update deployment/nginx-deployment (apps/v1) namespace: default
10:47:59AM: ---- waiting on 1 changes [1/2 done] ----
10:47:59AM: ongoing: reconcile deployment/nginx-deployment (apps/v1) namespace: default
10:47:59AM: ^ Waiting for generation 4 to be observed
10:47:59AM: L ok: waiting on replicaset/nginx-deployment-85496bcc7b (apps/v1) namespace: default
10:47:59AM: L ok: waiting on replicaset/nginx-deployment-5974d9b797 (apps/v1) namespace: default
10:47:59AM: L ok: waiting on pod/nginx-deployment-85496bcc7b-2g5lm (v1) namespace: default
10:47:59AM: L ongoing: waiting on pod/nginx-deployment-5974d9b797-cjs7v (v1) namespace: default
10:47:59AM: ^ Pending
10:48:01AM: ongoing: reconcile deployment/nginx-deployment (apps/v1) namespace: default
10:48:01AM: ^ Waiting for 1 unavailable replicas
10:48:01AM: L ok: waiting on replicaset/nginx-deployment-85496bcc7b (apps/v1) namespace: default
10:48:01AM: L ok: waiting on replicaset/nginx-deployment-5974d9b797 (apps/v1) namespace: default
10:48:01AM: L ok: waiting on pod/nginx-deployment-85496bcc7b-2g5lm (v1) namespace: default
10:48:01AM: L ongoing: waiting on pod/nginx-deployment-5974d9b797-cjs7v (v1) namespace: default
10:48:01AM: ^ Pending: ContainerCreating
10:48:02AM: ok: reconcile deployment/nginx-deployment (apps/v1) namespace: default
10:48:02AM: ---- applying complete [2/2 done] ----
10:48:02AM: ---- waiting complete [2/2 done] ----
Succeeded
ConfigMapは新しいバージョンとして作成され、deploymentも更新されていることが確認できます。
kubectl exec
にて環境変数TEST_CONFIG
がどうなっているか確認します。
$ kubectl exec -it $(kubectl get pods -l app=nginx -o json | jq -r .items[0].metadata.name) -- env | grep TEST_CONFIG
TEST_CONFIG=update-config
pod内の環境変数 TEST_CONFIG
が変更されていることが確認できました。
kapp deploy
の実行時に、Op
とWait to
が表示されます。
Op
は差分の概要がわかる列で、create
, update
, delete
, noop
が表示されます。
Wait to
はどのような条件で待機するのかをしますものですreconcile
だとリソースが目的の状態になるまで待機します。
delete
は、削除されるまで待機します。 noop
は、待機の条件なしとなります。
Apply stage
Apply stageでは、以下に示すような特徴が2つあります。これらについて説明していきます。
- Apply順序の制御
- Applyの待機
Apply順序の制御
kappには、特定の順序で変更が行われるためのアノテーションである kapp.k14s.io/change-group
やkapp.k14s.io/change-rule
が組み込まれています。
kapp.k14s.io/change-group
は、リソース変更を任意の名前のグループとしてまとめることができます。
kapp.k14s.io/change-rule
は、リソースの変更ルールを設定できます。change-group
と併用することで、グループごとに変更の順番を決めることができます。
Apply順序を試すRedisの サンプル がありますので、こちらを使って試してみます。サンプルは、下記の順序で構築していきます。
- プライマリのRedisの構築
- レプリカのRedisの構築
- プライマリとレプリカの同期チェック
それでは、実際に試してみます。サンプルソースを取得して、manifestがある対象のディレクトリに対して、kapp deploy
を実施します。
$ kapp deploy -a redis-ordering -f ./resource-ordering
Target cluster 'https://127.0.0.1:49154' (nodes: minikube)
Changes
Namespace Name Kind Conds. Age Op Op st. Wait to Rs Ri
default redis-primary Deployment - - create - reconcile - -
^ redis-primary Service - - create - reconcile - -
^ redis-replica Deployment - - create - reconcile - -
^ redis-replica Service - - create - reconcile - -
^ sync-check Job - - create - reconcile - -
Op: 5 create, 0 delete, 0 update, 0 noop
Wait to: 5 reconcile, 0 delete, 0 noop
Continue? [yN]: y
11:00:23AM: ---- applying 3 changes [0/5 done] ----
11:00:23AM: create deployment/redis-primary (apps/v1) namespace: default
11:00:23AM: create service/redis-replica (v1) namespace: default
11:00:23AM: create service/redis-primary (v1) namespace: default
11:00:23AM: ---- waiting on 3 changes [0/5 done] ----
11:00:23AM: ok: reconcile service/redis-replica (v1) namespace: default
11:00:23AM: ok: reconcile service/redis-primary (v1) namespace: default
11:00:23AM: ongoing: reconcile deployment/redis-primary (apps/v1) namespace: default
11:00:23AM: ^ Waiting for generation 2 to be observed
11:00:23AM: L ok: waiting on replicaset/redis-primary-64df9bf4dc (apps/v1) namespace: default
11:00:23AM: L ongoing: waiting on pod/redis-primary-64df9bf4dc-djg8l (v1) namespace: default
11:00:23AM: ^ Pending
11:00:23AM: ---- waiting on 1 changes [2/5 done] ----
11:00:23AM: ongoing: reconcile deployment/redis-primary (apps/v1) namespace: default
11:00:23AM: ^ Waiting for 1 unavailable replicas
11:00:23AM: L ok: waiting on replicaset/redis-primary-64df9bf4dc (apps/v1) namespace: default
11:00:23AM: L ongoing: waiting on pod/redis-primary-64df9bf4dc-djg8l (v1) namespace: default
11:00:23AM: ^ Pending: ContainerCreating
11:00:33AM: ok: reconcile deployment/redis-primary (apps/v1) namespace: default
11:00:33AM: ---- applying 1 changes [3/5 done] ----
11:00:34AM: create deployment/redis-replica (apps/v1) namespace: default
11:00:34AM: ---- waiting on 1 changes [3/5 done] ----
11:00:34AM: ongoing: reconcile deployment/redis-replica (apps/v1) namespace: default
11:00:34AM: ^ Waiting for generation 2 to be observed
11:00:34AM: L ok: waiting on replicaset/redis-replica-55c45464b8 (apps/v1) namespace: default
11:00:34AM: L ongoing: waiting on pod/redis-replica-55c45464b8-srb4b (v1) namespace: default
11:00:34AM: ^ Pending: ContainerCreating
11:00:34AM: L ongoing: waiting on pod/redis-replica-55c45464b8-rj8pj (v1) namespace: default
11:00:34AM: ^ Pending: ContainerCreating
....<省略>
11:00:41AM: ongoing: reconcile deployment/redis-replica (apps/v1) namespace: default
11:00:41AM: ^ Waiting for 1 unavailable replicas
11:00:41AM: L ok: waiting on replicaset/redis-replica-55c45464b8 (apps/v1) namespace: default
11:00:41AM: L ok: waiting on pod/redis-replica-55c45464b8-srb4b (v1) namespace: default
11:00:41AM: L ongoing: waiting on pod/redis-replica-55c45464b8-rj8pj (v1) namespace: default
11:00:41AM: ^ Condition Ready is not True (False)
11:00:42AM: ok: reconcile deployment/redis-replica (apps/v1) namespace: default
11:00:42AM: ---- applying 1 changes [4/5 done] ----
11:00:42AM: create job/sync-check (batch/v1) namespace: default
11:00:42AM: ---- waiting on 1 changes [4/5 done] ----
logs | # waiting for 'sync-check--1-5wn94 > sync-check' logs to become available...
11:00:42AM: ongoing: reconcile job/sync-check (batch/v1) namespace: default
11:00:42AM: ^ Waiting to complete (0 active, 0 failed, 0 succeeded)
11:00:42AM: L ongoing: waiting on pod/sync-check--1-5wn94 (v1) namespace: default
11:00:42AM: ^ Pending
11:00:43AM: ongoing: reconcile job/sync-check (batch/v1) namespace: default
11:00:43AM: ^ Waiting to complete (1 active, 0 failed, 0 succeeded)
11:00:43AM: L ongoing: waiting on pod/sync-check--1-5wn94 (v1) namespace: default
11:00:43AM: ^ Pending: ContainerCreating
....<省略>
11:00:49AM: ok: reconcile job/sync-check (batch/v1) namespace: default
11:00:49AM: ^ Completed
11:00:49AM: ---- applying complete [5/5 done] ----
11:00:49AM: ---- waiting complete [5/5 done] ----
Succeeded
kapp deploy
で出力された結果を見る限り、change-group
や change-rule
の指定した順番通りに実行されています。
Applyの待機
リソースタイプごとに待機動作に関するルールが組み込まれています。
サンプルがありますので、Deployment
リソースタイプの動作を確認します。
実際に試してみます。こちらも先ほど同様にサンプルソースを取得して、manifestがある対象のディレクトリに対して、kapp deploy
を実施します。
$ kapp deploy -a custom-wait -f ./deployment-with-custom-wait
Target cluster 'https://127.0.0.1:49154' (nodes: minikube)
Changes
Namespace Name Kind Conds. Age Op Op st. Wait to Rs Ri
default deployment-with-custom-wait Deployment - - create - reconcile - -
Op: 1 create, 0 delete, 0 update, 0 noop
Wait to: 1 reconcile, 0 delete, 0 noop
Continue? [yN]: y
11:14:55AM: ---- applying 1 changes [0/1 done] ----
11:14:56AM: create deployment/deployment-with-custom-wait (apps/v1) namespace: default
11:14:56AM: ---- waiting on 1 changes [0/1 done] ----
11:14:56AM: ongoing: reconcile deployment/deployment-with-custom-wait (apps/v1) namespace: default
11:14:56AM: ^ Waiting for generation 2 to be observed
11:14:56AM: L ok: waiting on replicaset/deployment-with-custom-wait-86dcf88f5b (apps/v1) namespace: default
11:14:56AM: L ongoing: waiting on pod/deployment-with-custom-wait-86dcf88f5b-wf5jk (v1) namespace: default
11:14:56AM: ^ Pending
11:14:56AM: L ongoing: waiting on pod/deployment-with-custom-wait-86dcf88f5b-tkvr4 (v1) namespace: default
11:14:56AM: ^ Pending: ContainerCreating
11:14:56AM: L ongoing: waiting on pod/deployment-with-custom-wait-86dcf88f5b-rlzlm (v1) namespace: default
11:14:56AM: ^ Pending
11:14:56AM: L ongoing: waiting on pod/deployment-with-custom-wait-86dcf88f5b-jsxfw (v1) namespace: default
11:14:56AM: ^ Pending: ContainerCreating
11:14:56AM: L ongoing: waiting on pod/deployment-with-custom-wait-86dcf88f5b-hqhpg (v1) namespace: default
11:14:56AM: ^ Pending: ContainerCreating
11:14:56AM: L ongoing: waiting on pod/deployment-with-custom-wait-86dcf88f5b-h9vwm (v1) namespace: default
11:14:56AM: ^ Pending: ContainerCreating
11:14:56AM: L ongoing: waiting on pod/deployment-with-custom-wait-86dcf88f5b-h5n7z (v1) namespace: default
11:14:56AM: ^ Pending: ContainerCreating
11:14:56AM: L ongoing: waiting on pod/deployment-with-custom-wait-86dcf88f5b-fccnb (v1) namespace: default
11:14:56AM: ^ Pending
11:14:56AM: L ongoing: waiting on pod/deployment-with-custom-wait-86dcf88f5b-7wg4q (v1) namespace: default
11:14:56AM: ^ Pending: ContainerCreating
11:14:56AM: L ongoing: waiting on pod/deployment-with-custom-wait-86dcf88f5b-5mgxg (v1) namespace: default
11:14:56AM: ^ Pending
11:14:57AM: ongoing: reconcile deployment/deployment-with-custom-wait (apps/v1) namespace: default
11:14:57AM: ^ Waiting for at least 5 available replicas (currently 0 available)
11:14:57AM: L ok: waiting on replicaset/deployment-with-custom-wait-86dcf88f5b (apps/v1) namespace: default
11:14:57AM: L ongoing: waiting on pod/deployment-with-custom-wait-86dcf88f5b-wf5jk (v1) namespace: default
11:14:57AM: ^ Pending
11:14:57AM: L ongoing: waiting on pod/deployment-with-custom-wait-86dcf88f5b-tkvr4 (v1) namespace: default
11:14:57AM: ^ Pending: ContainerCreating
11:14:57AM: L ongoing: waiting on pod/deployment-with-custom-wait-86dcf88f5b-rlzlm (v1) namespace: default
11:14:57AM: ^ Pending
11:14:57AM: L ongoing: waiting on pod/deployment-with-custom-wait-86dcf88f5b-jsxfw (v1) namespace: default
11:14:57AM: ^ Pending: ContainerCreating
11:14:57AM: L ongoing: waiting on pod/deployment-with-custom-wait-86dcf88f5b-hqhpg (v1) namespace: default
11:14:57AM: ^ Pending: ContainerCreating
11:14:57AM: L ongoing: waiting on pod/deployment-with-custom-wait-86dcf88f5b-h9vwm (v1) namespace: default
11:14:57AM: ^ Pending: ContainerCreating
11:14:57AM: L ongoing: waiting on pod/deployment-with-custom-wait-86dcf88f5b-h5n7z (v1) namespace: default
11:14:57AM: ^ Pending: ContainerCreating
11:14:57AM: L ongoing: waiting on pod/deployment-with-custom-wait-86dcf88f5b-fccnb (v1) namespace: default
11:14:57AM: ^ Pending
11:14:57AM: L ongoing: waiting on pod/deployment-with-custom-wait-86dcf88f5b-7wg4q (v1) namespace: default
11:14:57AM: ^ Pending: ContainerCreating
11:14:57AM: L ongoing: waiting on pod/deployment-with-custom-wait-86dcf88f5b-5mgxg (v1) namespace: default
11:14:57AM: ^ Pending
....<省略>
11:15:36AM: ok: reconcile deployment/deployment-with-custom-wait (apps/v1) namespace: default
11:15:36AM: ---- applying complete [1/1 done] ----
11:15:36AM: ---- waiting complete [1/1 done] ----
Succeeded
サンプルでは、apps-v1-deployment-wait-minimum-replicas-available
を50%と指定しています。
そのため、ちょっと分かりづらいですが、指定したレプリカ数の半数である5個作成時点で成功となりました。
まとめ
kappは、kubectlなどよく使われているKubernetes運用ツールをさらに便利に利用しやすくしたものと考えています。
ただ、それだけで今まで使い慣れてきたツールを変える必要があるかと言われると、ちょっと微妙なところがあります。kapp自体、Carvel toolsの1つにすぎす、単独では価値が分かりづらいです。
ここ に記載されていますように、Carvel toolsである kapp-cotroller, ytt, kbld などを組み合わせて利用することで Continuous Reconciliation と言われているアプリケーションのデプロイ自動化がより実現しやすくなるものと考えています。