GitHub Actions でキャッシュを利用して Docker イメージを高速にビルドする方法
今や本番環境に Docker を利用することは当然であり、それに伴い CI/CD パイプラインの中で Docker イメージをビルドするという機会も増えてきたのではないでしょうか🧐
皆さんご存知の通り、 Docker イメージはレイヤー構造になっており、レイヤー単位でキャッシュが行なわれる仕組みとなっております。
変更の無いレイヤーの場合は、以前のキャッシュが利用されることによってイメージのビルドが高速になるわけですが、 GitHub Actions などの CI/CD 環境では VM 上でワークフローが走るためそのままではキャッシュを利用することはできません。
全く変更の無いイメージであったとしてもキャッシュが利用されることはなく、最初から全てビルドされていきます😭
これは継続的デリバリーの観点から問題であり、迅速な開発サイクルに影響を与えてしまいます。。。
そこで今回は皆大好き GitHub Actions を例にして CI/CD 環境 でも Docker レイヤーキャッシュを利用する方法についてご紹介します😊
やる
GitHub Actions では Actions を利用することによって予め作成されたパッケージをワークフローに簡単に取り込めることが大きな利点ですが、 Docker 公式が提供している Action の中に今回の要件にそのものズバリなものがあります。
Docker イメージをビルドして、そのまま push することまで可能にするアクションです!
GitHub Actions はデフォルトで docker cli
が利用可能なので、ワークフローの中で
$ docker build ...
$ docker push ...
とやっても同じことはできます。
しかし、詳しくは Action の公式ドキュメントを見て頂きたいのですが、便利な機能が沢山あることからこの Action を利用することをおすすめします🙌
そしてこの公式ドキュメントの中にしっかり cache の項目があるのでそちらを参照します。
「どこにキャッシュしたデータを保存するか?」という観点があるのでやり方は複数あります。どれでも良いのですが、私は
の方法を選びました。この方法では、
という Docker に限らず GitHub Actions でキャッシュを利用する際のデファクトスタンダードになっている公式アクションを利用します。name: ci
on:
push:
branches:
- 'master'
jobs:
docker:
runs-on: ubuntu-latest
steps:
-
name: Checkout
uses: actions/checkout@v2
-
name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
-
name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
-
name: Login to DockerHub
uses: docker/login-action@v1
with:
username: ${{ secrets.DOCKERHUB_USERNAME }}
password: ${{ secrets.DOCKERHUB_TOKEN }}
-
name: Build and push
uses: docker/build-push-action@v2
with:
context: .
push: true
tags: user/app:latest
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
-
# Temp fix
# https://github.com/docker/build-push-action/issues/252
# https://github.com/moby/buildkit/issues/1896
name: Move cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
公式はこんな感じで書いてありまして、これを要件に合わせて少し書き換えるだけでOKです!
非常に簡単。
ただ公式のサンプルだけ記述してもつまらないのでもう少しだけ😅
私の場合だと
- GCP の Artifact Registry をイメージレジストリとして利用している
- stg, prod 2つの環境に同じイメージを push したい
という要件だったのでこんな感じになりました。
build:
name: container image build
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v2
- name: Set up Cloud SDK
uses: google-github-actions/setup-gcloud@master
with:
service_account_key: ${{ secrets.GCP_SA_KEY }}
export_default_credentials: true
- name: authenticate registry
run: gcloud auth configure-docker $GCP_REGION-docker.pkg.dev
- name: Set up Docker Buildx
uses: docker/setup-buildx-action@v1
- name: Cache Docker layers
uses: actions/cache@v2
with:
path: /tmp/.buildx-cache
key: ${{ runner.os }}-buildx-${{ github.sha }}
restore-keys: |
${{ runner.os }}-buildx-
- name: Build and push
uses: docker/build-push-action@v2
with:
push: true
tags: |
${{ env.GCP_REGION }}-docker.pkg.dev/${{ env.GCP_PROJECT_ID }}/stg-${{ env.APP_NAME }}-main/golang-api:${{ github.sha }}
${{ env.GCP_REGION }}-docker.pkg.dev/${{ env.GCP_PROJECT_ID }}/prod-${{ env.APP_NAME }}-main/golang-api:${{ github.sha }}
cache-from: type=local,src=/tmp/.buildx-cache
cache-to: type=local,dest=/tmp/.buildx-cache-new,mode=max
- # Temp fix
# https://github.com/docker/build-push-action/issues/252
# https://github.com/moby/buildkit/issues/1896
name: Move cache
run: |
rm -rf /tmp/.buildx-cache
mv /tmp/.buildx-cache-new /tmp/.buildx-cache
これでキャッシュを効かせた Docker イメージのビルド + push までしてくれるようになりました。
このように認証さえ行えば、 DockerHub 以外のイメージレジストリに push することも可能です。
詳しくは こちら の 公式ドキュメントをご参照ください。
結果としては、以前
の記事で書いたような Golang の Docker イメージで顕著に結果が出ました。比較的軽量なイメージでしたが以前は毎回 2分半
ほどかかっていたのがこれを利用してからは 1分
程度になりました😋
どなたかの参考になれば幸いです🙌
Discussion