🐳

GitHub Actionsで Docker イメージのキャッシュと docker run する方法

2024/10/03に公開

GitHub Actions 上の CI をしていてプロダクションで Docker イメージを実行する場合に、CI のテストを実行する環境をできるだけプロダクションに寄せたいという気持ちになることがあります。
Actions の YAML を工夫してセットアップするのもいいのですが、「そもそも Dockerfile があるならこれでテストを実行してしまえばいいよね」という発想を多くの方はするのではないかなと思います。
ここでは、この発想をあまりストレージのコストを掛けたくないというのをモチベーションに GitHub Actions のキャッシュを利用する方法で Docker イメージをキャッシュし、Docker イメージを Actions 上で docker run する方法を備忘録として書いています。

サンプルで作成した GitHub リポジトリを元に説明しています。
サンプルは Node.js のプロジェクトを想定していますが、その他の言語でも使える方法なので異なる言語の場合は各言語の作法に読み替えてください。

また、この記事ではコードの要所をかいつまんで説明しています。
全体のコードはサンプルリポジトリを見てみてください。

Dockerfile の作成

CI 用の Dockerfile を作成します。
サンプルで作ったものはプロダクションで利用するものと共通の Dockerfile を想定しています。
Build Args で開発時のみ依存するパッケージを除外の有無を切り替えられるようにしています。

https://github.com/k2wanko/usecase-github-actions-docker-cache/blob/main/Dockerfile

これにより GitHub Actions 上では NPM_CI_ARGS の値を空白にしてテスト用のパッケージをインストールするようにできます。

apt を利用しているのは apt のパッケージもキャッシュできることを確認のために入れているだけです。

共通にしない場合は Dockerfile を分割する手段もあります。
その際はビルド時に CI 用の Dockerfile を設定してください。

GitHub Actions 上で Docker イメージの作成

基本的には公式ドキュメントのやり方で Docker イメージを作成します。

https://docs.github.com/ja/actions/use-cases-and-examples/publishing-packages/publishing-docker-images

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 のドキュメントを見てみてください。

.github/actions/docker-build/action.yaml
    - 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