前回書いた記事では,CodeBuildのベースイメージとしてkanikoを利用した際のビルド及びECRにpushする方法を書いた.
今回はCodeBuildのイメージを変更せずデフォルトイメージ(aws/codebuild/standard:2.0
)のまま,docker runを使ってkanikoを利用する方法について書いていく.
この方法はCloudBuildでビルドする方法に近く,またgcr.io/kaniko-project/warmer
を使ったベースイメージのキャッシュも利用できるようになるため,実際にCodeBuildでkanikoを利用したい場合にはこちらを利用することが一般的になると思う.
以下では動かすための手順を書いていく.
CodeBuildのロール情報をkanikoのイメージに渡す
kanikoをdocker run経由で実行するということで,そのままではECRにpushする際に必要なIAMのロール情報をコンテナに渡すことができない.
ロール情報をコンテナに渡すための方法としてはCodeBuildからhttp://169.254.170.2${AWS_CONTAINER_CREDENTIALS_RELATIVE_URI}
というエンドポイントを叩き,その結果をコンテナの環境変数として渡すという方法をとれば良い.
metadata=$(curl -s http://169.254.170.2${AWS_CONTAINER_CREDENTIALS_RELATIVE_URI}) export AWS_ACCESS_KEY_ID=$(echo "${metadata}" | jq -r .AccessKeyId) export AWS_SECRET_ACCESS_KEY=$(echo "${metadata}" | jq -r .SecretAccessKey) export AWS_SESSION_TOKEN=$(echo "${metadata}" | jq -r .Token) mkdir .docker && echo "{\"credsStore\":\"ecr-login\"}" > .docker/config.json docker run \ -v $(pwd):/workspace \ -v $(pwd)/.docker:/kaniko/.docker \ -e AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} \ -e AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} \ -e AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN} \ gcr.io/kaniko-project/executor \ -d ${ECR_REPO}
エンドポイントや環境変数の渡し方などは以下の記事が参考になる.
gcr.io/kaniko-project/warmerを使えるようにする
これだけでもkanikoを使ったビルドができるようになるが,これに加えてkaniko-project/warmerを使うことで,ビルドする際のベースイメージのキャッシュが効くようになり,ビルド時間の短縮を狙うことができる.
以下のように書くことで,環境変数BASE_IMAGES
にキャッシュを効かせたいイメージを書くことで,ホストの/cache
ディレクトリにベースメージのキャッシュを保存することができる.
images=$(echo ${BASE_IMAGES} | perl -anal -e 'print join(" ", map {"--image=" . $_ } split ",")') docker run -v /cache:/cache gcr.io/kaniko-project/warmer --cache-dir=/cache ${images}
そしてこのディレクトリをCodeBuildがキャッシュするようにbuildspec.ymlを書き換えれば良い.
BASE_IMAGES
には複数のイメージを書くことができ,例えばgolang:1.10,alpine:latest
を渡すと,$images
の内容は--image=golang:1.10 --image=alpine:latest
となる
その他の注意点
気をつけないといけないのはまず,CodeBuildのビルド環境に特権付与が必要ということ.
特権を付与しないとdocker run自体を実行することができずに,
docker: Cannot connect to the Docker daemon at unix:///var/run/docker.sock. Is the docker daemon running?.
と言われてしまう.
また,docker runする際に,gcr.io/kaniko-project/executor
やgcr.io/kaniko-project/warmer
のイメージが必要になってくるため,これらのイメージ自体をキャッシュするためにはCodeBuildのレイヤキャッシュも有効にする必要がある.
つまりは基本的にCodeBuildのローカルキャッシュは全部有効にしておけば良い.
buildspecとCloudFormationテンプレート
以上を踏まえて,完成したbuildspec.ymlはこのようになった.
version: 0.2 phases: install: runtime-versions: docker: 18 build: commands: - metadata=$(curl -s http://169.254.170.2${AWS_CONTAINER_CREDENTIALS_RELATIVE_URI}) - export AWS_ACCESS_KEY_ID=$(echo "${metadata}" | jq -r .AccessKeyId) - export AWS_SECRET_ACCESS_KEY=$(echo "${metadata}" | jq -r .SecretAccessKey) - export AWS_SESSION_TOKEN=$(echo "${metadata}" | jq -r .Token) - images=$(echo ${BASE_IMAGES} | perl -anal -e 'print join(" ", map {"--image=" . $_ } split ",")') - mkdir .docker && echo "{\"credsStore\":\"ecr-login\"}" > .docker/config.json - | docker run \ -v /cache:/cache \ gcr.io/kaniko-project/warmer \ --cache-dir=/cache \ ${images} - | docker run \ -v $(pwd):/workspace \ -v $(pwd)/.docker:/kaniko/.docker \ -v /cache:/cache \ -e AWS_ACCESS_KEY_ID=${AWS_ACCESS_KEY_ID} \ -e AWS_SECRET_ACCESS_KEY=${AWS_SECRET_ACCESS_KEY} \ -e AWS_SESSION_TOKEN=${AWS_SESSION_TOKEN} \ gcr.io/kaniko-project/executor \ --cache=true \ --cache-dir=/cache \ --cache-repo ${ECR_REPO} \ -d ${ECR_REPO}:${ECR_TAG} cache: paths: - /cache/**/*
CodeBuildのキャッシュでカスタムキャッシュを有効にしていれば,/cache
以下の内容を保持し,次回以降のビルドが高速化される.
以上の構成を動かすCloudFormationテンプレートは以下から利用できる.
以上の形で,結構複雑ではあるけれど,キャッシュを利用できるような形でkanikoを使うことができるようになった.