🐳
Github Actionsでのdocker buildでキャッシュを有効にする
以下を実現するGithub Actionsを作る方法を紹介する。
- Dockerイメージのビルドには BuildKit を使う
- Github Actionsのもつキャッシュの仕組みを有効にする
- DockerイメージのタグにはYYYYMM-(コミットハッシュの頭7桁)のように、コミットごとにユニークになる値を使う
- mainブランチをビルドする際には、latestタグも付与する
このBuildKitとGithub Actionsのキャッシュを組み合わせる方法は、Dockerの公式ドキュメントに、Optimizing the workflow として掲載されている。
これに自分のアレンジを加えた方法として紹介する。
まず、BuildKitを有効にするには、以下のdocker/setup-buildx-action@v1を先に組み込む。
      - name: Set up Docker Buildx
        id: buildx
        uses: docker/setup-buildx-action@v1
次にactions/cache@v2をBuildKitのキャッシュとして使うファイルを引数に組み込む。${{ github.ref }}にはブランチ名が入るため、これをresore-keysにいれておくと、ブランチ内でキャッシュが効くようになる。さらに、mainブランチも指定しておくことで、mainブランチ以外のfeature/xxxブランチであったとしても、mainブランチのキャッシュを使えるようになる。
      - name: Cache Docker layers
        uses: actions/cache@v2
        with:
          path: /tmp/.buildx-cache
          key: ${{ github.ref }}-${{ github.sha }}
          restore-keys: |
            ${{ github.ref }}-${{ github.sha }}
            ${{ github.ref }}
            refs/head/main
タグは別途シェルスクリプトのステップで作成する。ステップ間の値渡しには環境変数を使う。この例では、YYYYMM-HASH先頭7文字をタグにし、さらにmainブランチの場合にはカンマ区切りでlatestタグも追加している。
env:
  IMAGE: 74th/githjub-actions-docker-build-with-cache
jobs:
  build:
    ...
    steps:
      ...
      - name: create tag
        run: |
          SHA=${{ github.sha }}
          TAG=${IMAGE}:$(TZ=UTC-9 date '+%Y%m')-${SHA:0:7}
          if [ "${{ github.ref }}" == "refs/heads/main" ]; then
            LATEST=${IMAGE}:latest
            echo "TAGS=$TAG,$LATEST" >> $GITHUB_ENV
          else
            echo "TAGS=$TAG" >> $GITHUB_ENV
          fi
          echo TAG $TAG
docker/build-push-action@v2 を組み込んでdocker buildを行う。ここで、先のステップのキャッシュのパスと、作成したタグを組み込む。tagsにはカンマ区切りで複数与えることができる。
      - name: Build and push
        id: docker_build
        uses: docker/build-push-action@v2
        with:
          context: ./
          file: ./Dockerfile
          builder: ${{ steps.buildx.outputs.name }}
          push: true
          tags: ${{ env.TAGS }}
          cache-from: type=local,src=/tmp/.buildx-cache
          cache-to: type=local,dest=/tmp/.buildx-cache
以上を組み合わせると、以下のYAMLができあがる。
name: build-docker
on: push
env:
  IMAGE: 74th/githjub-actions-docker-build-with-cache
jobs:
  build:
    runs-on: ubuntu-20.04
    steps:
      - name: checkout
        uses: actions/checkout@v1
      - name: Cache Docker layers
        uses: actions/cache@v2
        with:
          path: /tmp/.buildx-cache
          key: ${{ github.ref }}-${{ github.sha }}
          restore-keys: |
            ${{ github.ref }}-${{ github.sha }}
            ${{ github.ref }}
            refs/head/main
      - name: Set up Docker Buildx
        id: buildx
        uses: docker/setup-buildx-action@v1
      - name: create tag
        run: |
          SHA=${{ github.sha }}
          TAG=${IMAGE}:$(TZ=UTC-9 date '+%Y%m')-${SHA:0:7}
          if [ "${{ github.ref }}" == "refs/heads/main" ]; then
            LATEST=${IMAGE}:latest
            echo "TAGS=$TAG,$LATEST" >> $GITHUB_ENV
          else
            echo "TAGS=$TAG" >> $GITHUB_ENV
          fi
          echo TAG $TAG
      - name: Build and push
        id: docker_build
        uses: docker/build-push-action@v2
        with:
          context: ./
          file: ./Dockerfile
          builder: ${{ steps.buildx.outputs.name }}
          push: false
          tags: ${{ env.TAGS }}
          cache-from: type=local,src=/tmp/.buildx-cache
          cache-to: type=local,dest=/tmp/.buildx-cache
キャッシュが効いている場合には、以下のようにログにCACHEDと書かれて、そのビルドステップは省略され、高速にビルドすることができる。
...
#12 [1/6] FROM docker.io/library/python:3.9@sha256:168fd55b03929f88cd3e1e05b9ebe8f9cc1c095af8b53a8c0cd50da04a8c3a40
#12 sha256:d23acac7e68ba122c4a36d2f678784fa44485e2b1b3ce45b3f4e162de16f7e33
#12 resolve docker.io/library/python:3.9@sha256:168fd55b03929f88cd3e1e05b9ebe8f9cc1c095af8b53a8c0cd50da04a8c3a40 done
#12 DONE 0.0s
#7 [internal] load build context
#7 sha256:d8baf4b681cfd956bd41e7dcd88e0885036e445ad5d58210350906952e0d5393
#7 transferring context: 8.29kB done
#7 DONE 0.0s
#5 [2/6] WORKDIR /app
#5 sha256:cc5bf3907fccf389eeddea6b0481756956d5d7f28d724aaa3a40ea7ee3832ba5
#5 CACHED
#6 [3/6] RUN pip install poetry
#6 sha256:28fee1bc4b7c051e0d5cabc28ba60d91893046d47339c2202ac83d7454322d16
#6 CACHED
#9 [5/6] RUN poetry install
#9 sha256:5eee4e56fd80670a93603c955cf19a8015609f7c776fd9fdbe4e029b3bb23d60
#9 CACHED
#8 [4/6] COPY pyproject.toml poetry.lock ./
#8 sha256:7ecf0a9ab931cf67405e0a6a1ff5f6fd64bb29608c49e544267d2f416ccc15f6
#8 CACHED
...


Discussion