本物のクラスタを利用してkubectl pluginをテストする
kubectlのプラグインを開発していると、ユニットテストだけでなく、本物のKubernetesクラスタを利用したテストが欲しくなります。プラグインの振る舞いが複雑な場合は自動テストがあると安心してリリースできます。
本稿では、本物のKubernetesクラスタを利用してkubectlプラグインをテストする方法を考えます。
テストの基本形
本物のクラスタを利用してプラグインをテストするための構成を下図に示します。
必要なのは以下の3つです。
テストの流れは以下のようになります。
- クラスタを作成する。
- 必要なリソースをデプロイする。
- kubectlを実行する。
- 間接的にkubectl pluginが実行される。
- 実行結果が期待通りか検証する。
このようなテストはプラグインのリリース前に手動でやっていることが多いと思います。自動テストを導入することで、
- リリース前ではなくPull Requestの契機で不具合を検出できる
- クリーンな環境でテストできるので信頼性が高い
- 手動では手間のかかる組合せテストが可能になる(複数のクラスタバージョンなど)
といったメリットがあります。
例: kubectl-treeのテストを書いてみる
ここでは、kubectl-treeというプラグインをテストする例を考えます。これはクラスタにあるリソースを木構造で表示してくれる便利なプラグインです。
簡単のため、テストシナリオはMakefileで書くことにします。Makefileをよく知らない方はシェルスクリプトだと思って読んでみてください。
クラスタの作成とリソースのデプロイ
まずは新しいクラスタを作成するターゲットを定義します。Kindを利用すると、Docker上に簡単にクラスタを作成できます。
CLUSTER_NAME := kubectl-tree-e2e-test OUTPUT_DIR := $(CURDIR)/output KUBECONFIG := $(OUTPUT_DIR)/kubeconfig.yaml export KUBECONFIG .PHONY: cluster cluster: $(OUTPUT_DIR)/kubeconfig.yaml $(OUTPUT_DIR)/kubeconfig.yaml: kind create cluster --name $(CLUSTER_NAME) kubectl cluster-info .PHONY: delete-cluster delete-cluster: kind delete cluster --name $(CLUSTER_NAME) -rm $(KUBECONFIG)
これでmakeを実行すると新しいクラスタが作成される仕組みができました。実行にはDockerとKindが必要です。
% make kind create cluster --name kubectl-tree-e2e-test Creating cluster "kubectl-tree-e2e-test" ... ✓ Ensuring node image (kindest/node:v1.17.0) 🖼 ✓ Preparing nodes 📦 ✓ Writing configuration 📜 ✓ Starting control-plane 🕹️ ✓ Installing CNI 🔌 ✓ Installing StorageClass 💾 Set kubectl context to "kind-kubectl-tree-e2e-test" You can now use your cluster with: kubectl cluster-info --context kind-kubectl-tree-e2e-test Not sure what to do next? 😅 Check out https://kind.sigs.k8s.io/docs/user/quick-start/ kubectl cluster-info Kubernetes master is running at https://127.0.0.1:32771 KubeDNS is running at https://127.0.0.1:32771/api/v1/namespaces/kube-system/services/kube-dns:dns/proxy To further debug and diagnose cluster problems, use 'kubectl cluster-info dump'. % make delete-cluster kind delete cluster --name kubectl-tree-e2e-test Deleting cluster "kubectl-tree-e2e-test" ... rm /kubectl-tree-e2e-test/output/kubeconfig.yaml
テストを行うにはクラスタだけでなく適当なリソースも必要です。ここではechoserverをデプロイすることにします。以下のようにkubectl applyコマンドを追記します。
.PHONY: cluster cluster: $(OUTPUT_DIR)/kubeconfig.yaml $(OUTPUT_DIR)/kubeconfig.yaml: # create a cluster kind create cluster --name $(CLUSTER_NAME) kubectl cluster-info # deploy the echoserver kubectl apply -f fixture.yaml # wait for the deployment kubectl -n echoserver rollout status deployment/echoserver
これで、テストに必要なクラスタとリソースが揃いました。
プラグインの実行
kubectl treeコマンドを実行すると以下のような結果が表示されます。
% kubectl tree -n echoserver deployment echoserver NAMESPACE NAME READY REASON AGE echoserver Deployment/echoserver - 59s echoserver └─ReplicaSet/echoserver-5d8cc8d48 - 48s echoserver └─Pod/echoserver-5d8cc8d48-bcvs4 True 46s
ここでは簡単のため、grepで必要な文字列が表示されているかチェックします。もっと複雑な条件判定が必要な場合はスクリプトを書く方がよいでしょう。
.PHONY: test test: cluster # run kubectl-tree kubectl tree -n echoserver deployment echoserver | tee $(OUTPUT_DIR)/actual # make sure the output contains the expected lines egrep --color '^echoserver +Deployment/echoserver' $(OUTPUT_DIR)/actual egrep --color '^echoserver +└─ReplicaSet/echoserver-' $(OUTPUT_DIR)/actual egrep --color '^echoserver +└─Pod/echoserver-' $(OUTPUT_DIR)/actual
makeを実行してみましょう。以下のようにテストに合格するはずです。
% make # run kubectl-tree kubectl tree -n echoserver deployment echoserver | tee /kubectl-tree-e2e-test/output/actual NAMESPACE NAME READY REASON AGE echoserver Deployment/echoserver - 5m4s echoserver └─ReplicaSet/echoserver-5d8cc8d48 - 4m56s echoserver └─Pod/echoserver-5d8cc8d48-nk47g True 4m55s # check actual output egrep '^echoserver +Deployment/echoserver' output/actual echoserver Deployment/echoserver - 5m4s egrep '^echoserver +└─ReplicaSet/echoserver-' output/actual echoserver └─ReplicaSet/echoserver-5d8cc8d48 - 4m56s egrep '^echoserver +└─Pod/echoserver-' output/actual echoserver └─Pod/echoserver-5d8cc8d48-nk47g True 4m55s
これでローカルでのテストは完了です。
CIで実行する
品質を継続的に向上させるにはCIが不可欠です。ここではGitHub Actionsでテストを実行します。
GitHub ActionsのUbuntu 18.04にはすでにKindがインストールされていますが、バージョンが古いので改めて最新版をインストールすることにします。CIの最初のステップでは以下のツールをインストールします。
- Kind
- krew
- kubectl-tree
それからmakeを実行します。
最終的に、workflowは以下のようになります。
name: test on: [push] jobs: build: name: test # https://help.github.com/en/actions/automating-your-workflow-with-github-actions/software-installed-on-github-hosted-runners#ubuntu-1804-lts runs-on: ubuntu-18.04 steps: - uses: actions/checkout@v1 # https://kind.sigs.k8s.io/docs/user/quick-start/ - run: | wget -q -O ./kind "https://github.com/kubernetes-sigs/kind/releases/download/v0.7.0/kind-linux-amd64" chmod +x ./kind sudo mv ./kind /usr/local/bin/kind kind version # https://github.com/kubernetes-sigs/krew - run: | ( set -x; cd "$(mktemp -d)" && curl -fsSLO "https://github.com/kubernetes-sigs/krew/releases/download/v0.3.3/krew.{tar.gz,yaml}" && tar zxvf krew.tar.gz && KREW=./krew-"$(uname | tr '[:upper:]' '[:lower:]')_amd64" && "$KREW" install --manifest=krew.yaml --archive=krew.tar.gz && "$KREW" update ) # https://github.com/ahmetb/kubectl-tree - run: PATH=$PATH:$HOME/.krew/bin kubectl krew install tree - run: PATH=$PATH:$HOME/.krew/bin make
ここまでの内容は下記のリポジトリにまとめてあります。CIの実行時間や実行結果が気になる方はぜひご覧ください。
例:kubeloginの受け入れテスト
拙作のkubeloginでは、本物のKubernetesクラスタとOpenID Connect OPを利用したテストを下図の構成で行っています。
テストを支える裏方の仕組みは https://github.com/int128/kubelogin/tree/master/acceptance_test をご覧ください。
まとめ
DockerとKindを利用すると、本物のクラスタを用いたkubectl pluginのテストを実現できます。