Kubernetesの新ツール「kpt」を試してみた

先日[KubernetesのPodcast](https://kubernetespodcast.com/episode/099-kpt/)を聞いていたところ、`kpt`なるツールがリリースされたと知り、早速試してみました。



# `kpt`とは
GoogleがOSSとして開発・公開している、Kubernetes用の設定管理ツールです。ちなみに**「けぷと」**と発音します。アジャイルのふりかえりの手法の1つと同じですね。

- [公式ページ](https://googlecontainertools.github.io/kpt/)
- [アナウンス](https://opensource.googleblog.com/2020/03/kpt-packaging-up-your-kubernetes.html)
  - 2020年3月30日にアナウンスが出たばかりで、公開されたてのホヤホヤです。

Kubernetesで、設定すべき箇所が似通っているサービスを複数起動したいような場合に威力を発揮するツールです。具体的には、以下のように使用します。

1. 各サービスで共用できるKubernetesのリソースファイル（.yaml）群を用意する
2. リソースファイル内で、サービス毎に設定を変更する箇所をテンプレート化しておく
3. 上記ファイル群をまとめて、GitHubリポジトリに格納しておく
4. サービス毎に上記ファイル群（**「パッケージ」と呼称**）をGitHubリポジトリから取得し、
テンプレート部分を変更して起動する

挙動的には、`apt`や`npm`のイメージに近いです。
<br />



# 実際に動かしてみよう
`kpt`を使ってnginxを動かせる[簡単なサンプル](https://github.com/hageyahhoo/kpt-sandbox.git)を用意してみましたので、これをベースに`kpt`の使い方を説明します。
ちなみに、同サンプルの構成は以下の通りです。

```bash
.
├── README.md
└── nginx
    ├── deployment.yml
    └── service.yml
```


## 1. 準備編

### 1) `kpt`のインストール
[こちら](https://googlecontainertools.github.io/kpt/installation/)からダウンロード・インストールできます。


### 2) `Kptfile`の作成
GitHubリポジトリのディレクトリを`kpt`の「パッケージ」として扱えるよう、`kpt pkg init`コマンドを使用して`Kptfile`を作成します。

```bash
kpt pkg init nginx/
```

コマンド実行後、`Kptfile`と`README.md`が新たに作成されたことが分かります。

```bash
./nginx/
├── Kptfile
├── README.md
├── deployment.yml
└── service.yml
```

`Kptfile`の内容は、以下の通りです。

```yaml
apiVersion: kpt.dev/v1alpha1
kind: Kptfile
metadata:
  name: nginx
packageMetadata:
  shortDescription: sample description
```


### 3) `Setter`の作成
後述するテンプレートに適用するための、サービス毎に設定を変更するデータ項目を、キーバリューペア`setter`として作成します。
具体的には、`kpt cfg create-setter`コマンドを使用して作成します。

```bash
kpt cfg create-setter nginx/ name xxx
```

**(書式)**

```bash
kpt cfg create-setter ${Kptfileのあるディレクトリ名} ${キー} ${バリュー}
```
ちなみに、後で度々変更することになるため、この時点でのバリュー部分は、適当な値で大丈夫です。

コマンド実行後、setterが`Kptfile`に追加されたことが分かります。ちなみにsetterには、[OpenAPI](https://www.openapis.org/)を採用しています。

```yaml
apiVersion: kpt.dev/v1alpha1
kind: Kptfile
metadata:
  name: nginx
packageMetadata:
  shortDescription: sample description
openAPI:
  definitions:
    io.k8s.cli.setters.name:
      x-k8s-cli:
        setter:
          name: name
          value: xxx
```


### 4) テンプレートの用意
上記`setter`を適用できるよう、リソースファイル内のサービス毎に設定を変更する箇所を、下記のように書き換えます。

```yaml
name: xxx # {"$ref":"#/definitions/io.k8s.cli.setters.name"}
```

ちなみに今回のサンプルでは、以下の項目を`setter`として用意・設定できるようにしてあります。

- name
- image（Dockerイメージ）


### 5) パッケージの準備完了
上記内容を、GitHubリポジトリにcommit・pushします。これで、上記内容を`kpt`の「パッケージ」として使用できるようになります。
<br />


## 2. 動作確認編

### 1) パッケージの取得
`kpt pkg get`コマンドを使用して、上記で先に作成した「パッケージ」をGitHubリポジトリから取得します。

```bash
kpt pkg get https://github.com/hageyahhoo/kpt-sandbox.git/nginx@master test
```

**(書式)**

```bash
kpt pkg get ${GitHubリポジトリ（.gitで終わるもの）}/${使いたいパッケージのあるディレクトリ名}@${使いたいパッケージのあるブランチ名} ${パッケージのダウンロード先ディレクトリ名}
```

コマンド実行後、指定したディレクトリに、上記で先に作成した「パッケージ」一式がダウンロードされたことが分かります。

```bash
./test/
├── Kptfile
├── README.md
├── deployment.yml
└── service.yml
```


### 2) テンプレートへの値のセット
`kpt cfg set`コマンドを使用して、リソースファイル内のテンプレート部分を、当該サービスに適した値に書き換えます。

```bash
kpt cfg set test/ name kpt-test
```

**(書式)**

```bash
kpt cfg set ${パッケージのダウンロード先ディレクトリ名} ${キー} ${バリュー}
```

**"set 7 fields"** のように表示されればOKです。
実際にリソースファイルを見ると、下記のように指定した値が設定できていることを確認できます。

```yaml
name: kpt-test # {"$ref":"#/definitions/io.k8s.cli.setters.name"}
```

ちなみに今回のサンプルでは、以下の項目を設定して動かすことができます。

- name: 適当
- image: nginx:1.14


### 3) サービスの起動と動作確認
テンプレートへ値を一通り設定し終えたら、パッケージまるごと`kubectl apply`コマンドで動かせます。

```bash
kubectl apply -R -f test/
```

今回のサンプルでは、Webブラウザで http://localhost:8080/ にアクセスすると、以下の画面が見られます。

![スクリーンショット 2020-04-25 午前8.34.15.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/92580/3ed09041-7dfb-7f95-632f-d8298bd14e4e.png)


### 4) サービスの停止
起動時と同様、`kubectl delete`コマンドでパッケージまるごとサービスを停止できます。

```bash
kubectl delete -R -f test/
```


### 5) 補足
実際の運用では、namespaceやサービスの単位で「パッケージ」をダウンロードし、テンプレートへ値を設定し、各パッケージを起動する形となります。
<br />



# 今後解決が必要な課題
本稿執筆時点（2020年4月25日）での、実際に試してみて見つけた課題を列挙します。

## 1) 1行に複数のテンプレートを定義できない
テンプレートがyamlファイルのコメントであるがゆえの課題です。
[helm](https://helm.sh/)の`{{ namespace }}/{{ サービス名 }}` みたいな設定は、現時点では無理です。


## 2) パッケージの取得・テンプレートへの値のセットの一連の操作が面倒
サービスを複数設定・起動したい場合は、設定ミスの防止と時間短縮の観点から、一連の作業をまとめて実行できるスクリプトを作成することをお勧めします。
<br />



# まとめ
まだ公開されたてのツールなので、`kpt`だけでできることは少なめです。現時点では、[helm](https://helm.sh/)や[kustomize](https://kustomize.io/)と必要に応じて使い分けるのが現実的でしょう。

一方で、基本的な操作がシンプルなこと、この短期間でも機能追加・拡張が行われ続けていること、また公開されたてのツールを早期に試す面白みが味わえるという意味では、追う価値はあるのかなと個人的には思います。