Docker Buildkit InlineCacheを試す
記事の内容
AWS LambdaをDockerコンテナでデプロイしようとするとローカルPCではビルドのキャッシュが効くのですが、
CI/CD環境ではキャッシュが効かず1からビルドしてしまうため、ビルド時間が毎回掛かってしまう状況に悩んでいました。
これはCI/CD環境は基本的に一度使用したら使い捨てでありキャッシュが残らないためです。キャッシュを活用してビルドを迅速に行うにはキャッシュ戦略を立てる必要があります。
DockerのBuildKitにはイメージレイヤーをイメージにキャッシュする(Inline cache)ことができます。これを使ってキャッシュ戦略を立てるために試して見たいと思います。
関係する技術・ツール
- Docker Desktop 4.23.0
- AWS ECR
作業の流れ
- Dockerfile作成
- イメージのビルド&プッシュ
- 再ビルド(Dockerfile変更なし)
- 再ビルド(Dockerfile変更あり)
1. Dockerfile作成
まずは下記でDockerfileを作成します。
FROM node:18.17.0-slim as builder
RUN apt update && \
apt install -y \
curl \
git \
vim
RUN mkdir ~/build
RUN echo "build complete >> ~/build/message.txt"
FROM node:18.17.0-slim
COPY /root/ ./
2. ビルド&プッシュ
次にビルド&プッシュします。
今回はAWS ECRのプライベートリポジトリへプッシュします。
下記でレポジトリにログインしておきます。リポジトリの場所は東京リージョンです。
aws ecr get-login-password --region ap-northeast-1 | docker login --username AWS --password-stdin AWSアカウントID.dkr.ecr.ap-northeast-1.amazonaws.com
ログインできたらビルド&プッシュを実行します。
docker build --cache-from type=registry,ref=AWSアカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/my-test:image1 --cache-to type=inline --push -t AWSアカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/my-test:image1 .
ポイントとしては
--cache-from type=registry,ref=リポジトリ名/イメージ名:タグ
でキャッシュのエントリを指定します。
--cache-to type=inline
でキャッシュの方法を指定します。今回はインラインキャッシュを指定します。
初回のビルド時は下記のように赤字で出力されると思います。
これは初回時はイメージにキャッシュを含んでいないため、キャッシュヒットしないためです。
ビルド自体は問題なく完了してイメージをプッシュします。
=> ERROR importing cache manifest from AWSアカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/my-test:image1
3.再ビルド(Dockerfile変更なし)
これで初回のイメージ構築は完了してキャッシュも作成されました。
それではDockerfileは変更せず、再度2と同じコマンドでビルド&プッシュします。期待通りであれば、2回目以降はイメージに含んだキャッシュが効いてビルドされるはずです。
ちゃんとインラインキャッシュが効くことを確認するために、事前にローカルPCのビルドキャッシュは削除しておきます。
docker builder prune
これでローカルPCにはキャッシュは残っていないため端末のキャッシュを使うこともありません。
それではビルド&プッシュを実行しましょう。
docker build --cache-from type=registry,ref=AWSアカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/my-test:image1 --cache-to type=inline --push -t AWSアカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/my-test:image1 .
すると今度は下記のように出力されると思います。
先ほどは赤字でエラーとなりキャッシュはヒットしませんでしたが、今度はキャッシュヒットしたためです。
RUNやCOPYもCACHEDとなっていることが確認できます。ビルドも迅速に終わると思います。
=> importing cache manifest from AWSアカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/my-test:image1
=> [builder 1/4] FROM docker.io/library/node:18.17.0-slim@sha256:a0cca98f2896135d4c0386922211c1f90f98f27a58b8f2c07850d0fbe1c2104e 0.0s
=> CACHED [builder 2/4] RUN apt update && apt install -y curl git vim 0.0s
=> CACHED [builder 3/4] RUN mkdir ~/build 0.0s
=> CACHED [builder 4/4] RUN echo "build complete >> ~/build/message.txt" 0.0s
=> CACHED [stage-1 2/2] COPY --from=builder /root/ ./
4.再ビルド(Dockerfile変更あり)
3でキャッシュが効いていることが確認できました。
今度はDockerfileを変更して、キャッシュが効くことも確認しておきましょう。
下記のようにDockerfileを変更します。
FROM node:18.17.0-slim as builder
RUN apt update && \
apt install -y \
curl \
git \
vim
RUN npm i -g typescript
RUN mkdir ~/build
RUN echo "build complete >> ~/build/message.txt"
FROM node:18.17.0-slim
COPY /root/ ./
2回目のRUNに下記を追加しています。
+ RUN npm i -g typescript
再度2と同じコマンドでビルド&プッシュします。
期待通りであれば、イメージレイヤーに差分ができるため変更行より前のコマンドはキャッシュされますが、変更行以降はキャッシュが効かなくなるはずです。
docker build --cache-from type=registry,ref=AWSアカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/my-test:image1 --cache-to type=inline --push -t AWSアカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/my-test:image1 .
キャッシュヒットしていますね。
詳細まで追うと、1行目のRUNはキャッシュが効いています。
しかし、今回追加した2行目のRUN以降ではキャッシュが効いていないようです。
ビルドは変更行以降はキャッシュは使わず再構築することが基本の挙動です。
ですので期待通りのキャッシュ動作になっています。これで差分でキャッシュが効いていることも確認できるかと思います。
=> importing cache manifest from AWSアカウントID.dkr.ecr.ap-northeast-1.amazonaws.com/my-test:image1 0.0s
=> CACHED [stage-1 1/2] FROM docker.io/library/node:18.17.0-slim@sha256:a0cca98f2896135d4c0386922211c1f90f98f27a58b8f2c07850d0fbe1c2104e 0.0s
=> CACHED [builder 2/5] RUN apt update && apt install -y curl git vim 0.0s
=> [builder 3/5] RUN npm i -g typescript 2.8s
=> [builder 4/5] RUN mkdir ~/build 0.3s
=> [builder 5/5] RUN echo "build complete >> ~/build/message.txt" 0.3s
=> [stage-1 2/2] COPY --from=builder /root/ ./
まとめ
- インラインキャッシュでイメージにキャッシュを含めることができる
- docker buildの
--cache-from
と--cache-to
でキャッシュを指定する - イメージ編集時も差分でキャッシュを利用できる
以上になります。
迅速なデプロイにはキャッシュ戦略は重要だと思います。ぜひ利用していきましょう。
NCDC株式会社( ncdc.co.jp/ )のエンジニアチームです。 募集中のポジションや、採用している技術スタックの紹介などはこちらをご覧ください! github.com/ncdcdev/recruitment
Discussion