re:annkara

日々学んだことを書き留めておく。

kubectl plugin 機能を利用してkubectl コマンドを拡張する

最近 kubectl コマンドを拡張したいと思い、調べてみたら kubectl plugin 機構で機能拡張できることを知ったので、公式ドキュメントをベースにまとめておこうと思う。

kubectl plugin 機構とは

kubectl v1.12 以上のバージョンで使用できる、kubectl のサブコマンドを自前で実装できる plugin 機構のこと。

実行可能ファイル(シェルスクリプトやbatファイル、goで実装したバイナリなど)を PATH 上に配置し、kubectl-SUBCOMMANDというようなファイル名にすれば、kubectl SUBCOMMAND を実行した際に、kubectl が PATH上を検索し実行するような仕組みとなっている。

現状、v1.15 がリリースされており、機能としても stable となっているが、windwos で実行すると現状以下のエラーが返ってくる。

$ kubectl.exe version
Client Version: version.Info{Major:"1", Minor:"15", GitVersion:"v1.15.0", GitCommit:"e8462b5b5dc2584fdcd18e6bcfe9f1e4d970a529", GitTreeState:"clean", BuildDate:"2019-06-19T16:40:16Z", GoVersion:"go1.12.5", Compiler:"gc", Platform:"windows/amd64"}

$ cat kubectl-echo.bat
echo "HELLO"

$ kubectl.exe echo
not supported by windows

v1.15 のバージョンにおいてはどうやら Windows 向けの実装が入っていなかったが、このプルリクエストがすでにマージされているので、次のバージョンでは利用できそう。

Replace syscall.Execve with exec.Command. by sawlanipradeep · Pull Request #76227 · kubernetes/kubernetes · GitHub

リンク先から入手できる v1.16 のアルファ版リリースを試してみると、実行できているのできっと大丈夫なはず。

kubernetes/CHANGELOG-1.16.md at master · kubernetes/kubernetes · GitHub

$ kubectl-1.16.exe echo

"HELLO"

制約事項

kubectl に既に存在するコマンドをオーバライドすることはできないため、kubectl-version といったコマンドを実装しても、実装したプラグインは実行されず、もともと存在するコマンドが実行される。

$ cat kubectl-version.bat
echo "kubectl version"

$ kubectl-1.16.exe version
Client Version: version.Info{Major:"1", Minor:"16+", GitVersion:"v1.16.0-alpha.1", GitCommit:"704790e0412842e782904f1c2e7123112a9aab2c", GitTreeState:"clean", BuildDate:"2019-07-17T01:06:25Z", GoVersion:"go1.12.7", Compiler:"gc", Platform:"windows/amd64"}

なので、例えば kubectl-create-foo みたいなコマンドを実装し、kubectl create foo というように実行しても、自前で実装したコマンドは実行されない。

実装方法

上述の通り、スクリプトやbatファイル、実行バイナリなどを実装し、実行権限を付与し、PATH上に配置すればあとは kubectl がよしなにしてくれる。

kubectl の実装上、環境変数は kubectl 実行時の環境変数を引き継いでくれるし、パラメータもスクリプト実行時のように渡すことができる。
この編の仕組みは、上で貼ったプルリクエストのリンクを参照すると理解できるかもしれない。

時間があれば自分でもまとめておきたいと思う。

サブコマンドの検索ルール

サブコマンドの検索は最長一致で検索するようになっている。

つまり、実行コマンドが kubectl foo bar baz arg1 --flag=value arg2 だった場合には、kubectl-foo-bar-baz-arg1 という実行可能ファイルを検索し、--flag=value arg2 というパラメータは、kubectl-foo-bar-baz-arg1 にそのまま渡される。

仮に kubectl-foo-bar-baz-arg1 という実行可能ファイルが PATH 上から見つからなかった場合には、kubectl-foo-bar-baz という実行可能ファイルを検索し、arg1 --flag=value arg2というパラメータがサブコマンドに引き渡される。

最終的にサブコマンドが見つからない場合には、通常の kubectl コマンドのエラーが表示される。

ちなみに、すでにインストールされているプラグインを表示するには kubectl plugin list を実行する。
自前で実装したプラグインも、PATH 上に配置されていれば表示される。

sub-command

サブコマンド名に - を利用したい場合には、実行可能ファイル名に _ を利用する。

kubectl foo-bar を実行する際には、ファイル名は kubectl-foo_bar とすればよい。
また、kubectl foo_bar を実行しても、kubectl-foo_bar が実行される。

今のところ、これができることの良さがあまり実感できていない。

実行ファイル名被り

同一名の実行ファイルが別々の PATH 上のディレクトリに配置されている際には、常に最初に見つかったサブコマンドが実行される。
これは kubectl plugin list を実行すれば、そのような警告が表示されるため気づくことができる。

PATHを変更すればよいが、実際にはあまり気にしたくないと思うので名前が被らないようにするのが良いかと思う。

もう少しややこしい問題として、kubectl-foo-barkubectl-foo-bar-baz といった実行ファイルが同一ディレクトリ上に配置されていた場合がある。

kubectl foo bar の場合は kubectl-foo-bar
kubectl foo bar baz の場合は kubectl-foo-bar-baz が実行されることになる。

ややこしいので、あまり自分で実装することはなさそうな気がしている。

k8s.io/cli-runtime パッケージ

今まで見てきたように、kubectl plugin 機構を利用すれば、シェルスクリプトやbatファイルを利用してプラグインを拡張することができる。

ただ、その場合にはパラメータは単純にスクリプトに渡されるだけなので、パラメータの解析などは自前で行う必要があるし、kubectl コマンドをラップするだけになってしまう。

もう少し機能効いた拡張機能を実装したい場合には、kubectl の実装にも利用されている k8s/cli-runtime を利用して Go言語で実装すると良い。ただ、サンプルの実装がGitHubにあるとは言え、ちょっとハードルが高いなと感じてしまったので、簡単なものを作ってみたら再度まとめておきたいと思う。

参考

公式ドキュメント kubernetes.io

今年のKubeCon/CloudNativeConでkubectl plugin についての講演があったので載せておく。 www.youtube.com

krewというプラグインマネージャの話とか記述されたりしています。 qiita.com