Krew のカスタムプラグインインデックスで kubectl プラグインを配布しよう

## はじめに

kubectl プラグインマネージャの Krew[^krew] ではこれまでは Krew が公式で提供するプラグインインデックス（[kubernetes-sigs/krew-index](https://github.com/kubernetes-sigs/krew-index)） しか使用できませんでしたが、v0.4.0 で待望のカスタムプラグインインデックスがサポートされました。

- https://github.com/kubernetes-sigs/krew/releases/tag/v0.4.0

カスタムプラグインインデックスは、Homebrew でいうところの `brew tap` コマンドで外部のリポジトリを Formula として追加するとの同じことです。これにより、公式のプラグインインデックスに自作の kubectl プラグインを登録しなくても Krew を使ってプラグインを配布できるようになります。

[^krew]: Krew 自体については [kubectl のプラグイン機能 kubectl plugin を使おう！](https://qiita.com/superbrothers/items/b4a0aab0575ca6d65739#kubectl-plugin-%E3%83%9E%E3%83%8D%E3%83%BC%E3%82%B8%E3%83%A3-krew-%E3%82%92%E4%BD%BF%E3%81%8A%E3%81%86) を参照してください。

## カスタムプラグインインデックスの使い所

Krew プロジェクトとしてはできる限りプラグインは公式インデックスに追加してくれというスタンスに見えますが、次のような場合がカスタムプラグインインデックスの使い所です。

**公式インデックスにプラグインを追加しようとしたけど何らかの理由で追加できなかった**

公式インデックスに追加するには Krew プロジェクトが決めたプラグイン命名規則に従う必要がありますが、カスタムプラグインインデックスでは好きな名前が使えます。といっても命名規則はよりよいものにするためにできる限り従ったほうがよいでしょう。

**プラグイン配布のライフサイクルを完全にコントロールしたい**

公式インデックスに追加したプラグインマニフェストの更新はバージョンやアーカイブファイルのハッシュ値の更新のみであればマージが自動化されているため、ほとんどの場合で問題ないと思いますが、自分たちでコントロールしたいこともあるでしょう。

**組織内でのみ使用するプライベートなプラグインを配布したい**

おそらく、プライベートなプラグインの配布を目的にすることが多そうです。

---

ここでは、カスタムプラグインインデックスの使い方と提供方法を紹介します。

## カスタムプラグインインデックスを使う

最初にカスタムプラグインインデックスの使い方です。インデックスの追加、削除、リストは全て `kubectl krew index` コマンドのサブコマンドで提供されています。

- `kubectl krew index add <index-name> <git-url>`: インデックスを追加
- `kubectl krew index remove <index-name>`: インデックスを削除
- `kubectl krew index list`: インデックスをリスト

インデックスを追加すると `kubectl krew search` コマンドでカスタムインデックスに登録されているプラグインがヒットするようになります。カスタムインデックスに登録されているプラグインをインストールするには次のようにインデックス名も一緒に指定します。

```
kubectl krew install INDEX_NAME/PLUGIN_NAME
```

なお、公式プラグインインデックスの `krew-index` は `default` インデックスとして登録されています。`default` インデックスはプラグインをリストした際にインデックス名の表記が省略されるようになっています。また、プラグインのインストール時にインデックス名のプレフィックスの付与が不要です。`default` インデックスを削除したい場合は、次のコマンドで削除できます。

```
kubectl krew index remove default
```

また、カスタムプラグインインデックスを `default` のインデックスとして登録もできます。

```
kubectl krew index add default <git-url>
```

以上のように、とても簡単に使うことができ迷うところもないですね。

## カスタムプラグインインデックスを提供する

次にカスタムプラグインインデックスの提供方法です。カスタムインデックスは Git リポジトリとして提供する必要があります。また、次のようなディレクトリ構成にする必要もあります。

```
.
└── plugins/
    ├── plugin-a.yaml
    ├── plugin-b.yaml
    └── plugin-c.yaml
```

利用者は、カスタムインデックスの Git リポジトリの READ 権限が必要です。プライベートリポジトリの場合は、SSH の設定 `UseKeychain yes` を利用するなどしてください。

プラグインマニフェストの書き方は [公式ドキュメント](https://krew.sigs.k8s.io/docs/developer-guide/plugin-manifest/) の手順を参考にしてください。

### インデックスに追加されたプラグインマニフェストを CI する

カスタムプラグインインデックスに追加されるプラグインマニフェストが機能するかどうかを確認するのに [`validate-krew-manifest` ツール](https://github.com/kubernetes-sigs/krew/tree/master/cmd/validate-krew-manifest)が使用できます。このツールは、マニフェストプラグインの構造が正しいのかや実際にプラグインを `kubectl krew install` コマンドでインストールしてアーカイブファイルのハッシュ値が正しいのかの検証を実施してくれます。

公式のプラグインインデックスである krew-index リポジトリでは GitHub Actions での CI でこのツールを使用しています。これを参考に必要ならカスタマイズするのがよいでしょう。

```yaml
name: krew-index CI
on: pull_request
jobs:
  build:
    name: Build and Tags
    runs-on: ubuntu-latest
    env:
      KREW_VERSION: v0.3.4
      GO111MODULE: on
    steps:
    - name: Set up Go 1.13
      uses: actions/setup-go@v1
      with:
        go-version: 1.13
      id: go
    - name: Check out PR branch
      uses: actions/checkout@v2
      with:
        fetch-depth: 0  # disable shallow clones
    - name: Fetch base branch
      run: |
        git fetch --no-tags --prune --depth=1 origin +refs/heads/${GITHUB_BASE_REF}:refs/remotes/origin/${GITHUB_BASE_REF}
    - name: Install kubectl
      run: |
        set -euo pipefail
        sudo curl -fsSL -o /usr/bin/kubectl https://storage.googleapis.com/kubernetes-release/release/v1.13.1/bin/linux/amd64/kubectl
        sudo chmod +x /usr/bin/kubectl
    - name: Install krew
      run: |
        set -euo pipefail
        cd "$(mktemp -d)"
        curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/download/${KREW_VERSION}/krew.{tar.gz,yaml}"
        tar zxvf krew.tar.gz
        ./krew-linux_amd64 install --manifest=krew.yaml --archive=krew.tar.gz
    - name: Install validate-krew-manifest plugin
      run : |
        set -euo pipefail
        export GOBIN=$HOME/bin
        go get sigs.k8s.io/krew/cmd/validate-krew-manifest@${KREW_VERSION}
    - name: Validate updated plugin manifests
      run : |
        set -x
        set -euo pipefail
        export PATH="${KREW_ROOT:-$HOME/.krew}/bin:$PATH"
        git diff --name-only --diff-filter=AM origin/${GITHUB_BASE_REF} ${{ github.sha }} -- plugins/ |
          tee /dev/stderr |
          xargs -I _ $HOME/bin/validate-krew-manifest -manifest _
```

- https://github.com/kubernetes-sigs/krew-index/blob/master/.github/workflows/ci.yml

## さいごに

ここでは Krew v0.4.0 で追加されたカスタムプラグインインデックスについて解説しました。カスタムプラグインインデックスによって今後さらにべんりな kubectl プラグインが広まりそうで楽しみです。