Kubernetes関連のツールを作ったときなどに,E2Eテストをしたいことがある.実際にKubernetesクラスタに入れてみて,動かしてみてどうか,というのは開発環境でやるにしても結構手間だ. そういうときにkindはすごく便利なんだけど,これのlocal registryは更に便利だった.
kind内で使うdocker imageどうする問題
kindは1コマンドでローカルにkubernetesクラスタを作ってはくれる. ただ,内部でPodを動かすにはdocker imageをどこかからpullできる必要がある.
E2Eテストをする場合,成果物のdocker imageをkind内で動かしてほしい場合がほとんどだろうから,これをどこかにpushして,kind内でpullできる必要がある.
publicなdocker registryで良いのであれば,例えはhub.docker.comやghcr.ioなどにpushしておいて,それを使う必要がある.
privateなdocker registryであれば,kindにデプロイするPodの定義に,imagePullSecrets
を指定しておく必要があるだろう.
いずれにしろ,以下のような手順を踏む必要はある.
- 成果物をdocker buildする
- public/privateなdocker registryにpushする
- 上記docker imageを利用するような環境変数,設定等を書く
- 上記docker imageを使う形でE2Eテストをkind内で動かす
さて,これをCI内で実行しようとすると,更に問題が発生する.
forkされてPRをもらったときにsecretsは使えない問題
E2Eテストとしてkindを使う場合,それをCIに組み込むだろう.GitHub ActionsやCircleCIに組み込んだ場合,一つ大きな問題がsecretsをどうするかという問題だ. パスワードやAccessToken等は,GitHub Actionsであればsecretsに,CircleCIであれば環境変数に書くのが普通だろう. ただ,こうしたsecretsは基本的にforkされたリポジトリでは読み出せないようになっている.
リポジトリがforkされた場合,そしてそこからPullRequestが出された場合,CIとしてはPullRequestのhookで動くことになる.ただしリポジトリ自体はforkした人のものであり,そこにどのようなコードをpushするかはforkした人に委ねられる.
そのため,CIのstep内で echo
とかしてしまえば環境変数は全部見えるのだ.
だから,secrets等もそこで読み出せてはいけないのである.
ただ,そうなると問題なのは,前述のdocker imageをどこにpushするかという問題だ. hub.docker.comにしろghcr.ioにしろ,pushするにはAccessTokenが必要になり,それはsecretsだ. ということは,これはforkされたリポジトリからのPullRequestでは使えない.
local registryでimageを外部にpushせずにkind内で使う
いろいろ考えたが,そもそも外部にpushするのは諦めたほうが良いのではないかという結論に至った.どう考えてもsecretsなしでpushはできないし,secretsを読み込めた時点でセキュリティ的にNGだろう.
こういうときに使えるのが kind local registryだ.
これにより,localhostにdocker registryを立てることができ,そこにdocker imageをpushすることができる.そして,そのregistryはkind内のPodからアクセス可能だ.このフローの中にはsecretsは一切出てこない.そのため,secretsの管理を考える必要がなく,forkされたリポジトリだろうが普通に実行可能だ.
というわけで,以下のようなGitHub Actionsのworkflowを書いた.
env: IMAGE_NAME: my-image KIND_VERSION: v0.10.0 KUBECTL_VERSION: v1.20.2 jobs: e2e-test: runs-on: ubuntu-latest steps: - uses: actions/setup-go@v2 with: go-version: '^1.15.0' - uses: actions/checkout@master - name: Install kind env: KIND_VERSION: ${{ env.KIND_VERSION }} BIN_DIR: ${{ github.workspace }}/tools/ run: | mkdir -p $BIN_DIR curl -sSLo "$BIN_DIR/kind" "https://github.com/kubernetes-sigs/kind/releases/download/$KIND_VERSION/kind-linux-amd64" chmod +x "$BIN_DIR/kind" echo "$BIN_DIR" >> "$GITHUB_PATH" - name: Install kubectl env: KUBECTL_VERSION: ${{ env.KUBECTL_VERSION }} BIN_DIR: ${{ github.workspace }}/tools/ run: | mkdir -p $BIN_DIR curl -sSLo "$BIN_DIR/kubectl" "https://storage.googleapis.com/kubernetes-release/release/${KUBECTL_VERSION}/bin/linux/amd64/kubectl" chmod +x "$BIN_DIR/kubectl" echo "$BIN_DIR" >> "$GITHUB_PATH" - name: Setup kind run: | ./scripts/kind-with-registry.sh - name: Info run: | kind version kubectl cluster-info kubectl version - name: Build docker image run: | IMAGE_ID=localhost:5000/$IMAGE_NAME SHA=${{ github.sha }} docker build . --file Dockerfile --tag $IMAGE_ID:$SHA docker push $IMAGE_ID:$SHA - name: Install ginkgo run: | go get -u github.com/onsi/ginkgo/ginkgo - name: Testing run: | IMAGE_ID=localhost:5000/$IMAGE_NAME SHA=${{ github.sha }} export IMAGE=$IMAGE_ID:$SHA go mod download ginkgo -r ./e2e
./scripts/kind-with-registry.sh
は,ここのものをまるごとコピーした.
これでkindによるE2Eテストは,secretsを使う必要がなくなった.