GitHub Actionsで Docker イメージのキャッシュと docker run する方法
GitHub Actions 上の CI をしていてプロダクションで Docker イメージを実行する場合に、CI のテストを実行する環境をできるだけプロダクションに寄せたいという気持ちになることがあります。
Actions の YAML を工夫してセットアップするのもいいのですが、「そもそも Dockerfile があるならこれでテストを実行してしまえばいいよね」という発想を多くの方はするのではないかなと思います。
ここでは、この発想をあまりストレージのコストを掛けたくないというのをモチベーションに GitHub Actions のキャッシュを利用する方法で Docker イメージをキャッシュし、Docker イメージを Actions 上で docker run する方法を備忘録として書いています。
サンプルで作成した GitHub リポジトリを元に説明しています。
サンプルは Node.js のプロジェクトを想定していますが、その他の言語でも使える方法なので異なる言語の場合は各言語の作法に読み替えてください。
また、この記事ではコードの要所をかいつまんで説明しています。
全体のコードはサンプルリポジトリを見てみてください。
Dockerfile の作成
CI 用の Dockerfile を作成します。
サンプルで作ったものはプロダクションで利用するものと共通の Dockerfile を想定しています。
Build Args で開発時のみ依存するパッケージを除外の有無を切り替えられるようにしています。
これにより GitHub Actions 上では NPM_CI_ARGS の値を空白にしてテスト用のパッケージをインストールするようにできます。
apt を利用しているのは apt のパッケージもキャッシュできることを確認のために入れているだけです。
共通にしない場合は Dockerfile を分割する手段もあります。
その際はビルド時に CI 用の Dockerfile を設定してください。
GitHub Actions 上で Docker イメージの作成
基本的には公式ドキュメントのやり方で Docker イメージを作成します。
GitHub Actions のキャッシュを利用するため、Buildx のセットアップを行ないます。
そして、docker/build-push-action に cache-from と cache-to をつけてキャッシュをするようにします。
uses: docker/build-push-action@v6
with:
cache-from: type=gha
cache-to: type=gha,mode=max
詳細については Docker のドキュメントを見てみてください。
- name: Build and push Docker image
id: build
uses: docker/build-push-action@v6
with:
context: .
file: ./Dockerfile
load: ${{ inputs.load }} # ビルドだけなら false
push: false
tags: ${{ steps.meta.outputs.tags }}
labels: ${{ steps.meta.outputs.labels }}
cache-from: type=gha
# main ブランチの時だけ、キャッシュを保存する
cache-to: ${{ (github.ref_name == 'main' && ( inputs.cache-to == 'true' && 'type=gha,mode=max') || '') || '' }}
# Dockerfile 側にある ARG を上書きする
build-args: |
NPM_CI_ARGS=
Docker イメージを利用する
docker/build-push-action の load を true にすることで Actions 上からそのイメージを docker run
などで利用することができます。
load を true にして Docker イメージのレイヤーが GitHub Actions 上で読み込めた場合は、以下のように Actions 内の Docker コマンドで利用できます。
- name: npm test
run: |
docker run --rm -t \
-v ${{ github.workspace }}/lib:/app/lib \ # checkout したコードをコンテナにマウント
${{ steps.docker-build.outputs.image }} \
npm test
これで、GitHub Actions 上で Docker イメージを利用できます。
制限の考慮事項
この方法は GitHub Actions のキャッシュの制限に収まる場合にはよいのですが、キャッシュに収まらない場合は別途キャッシュレイヤーを検討する必要があります。
コストとか諸々考慮点はありますが例としては GitHub Packages や GitHub Actions Artifact なども選択肢になりそうです。
まとめ
ここでは、GitHub Actions 上で Docker イメージを作成する際のキャッシュを Actions のキャッシュに載せる方法と、docker/build-push-action でビルドしたイメージを Actions 上の docker run で利用する方法を説明しました。
余談ですが、docker run の際に --network ${{ job.container.network }} オプションも含めることでサービスコンテナと同一のネットワークで動かすこともできます。
サービスコンテナは DB など別にコンテナが必要な際は利用すると便利です。
Discussion