Runner in the High

技術のことをかくこころみ

Earthlyがもつ2種類のキャッシュ機構(inline, explicit)について

izumisy.work

前回はあまりキャッシュについて触れることができなかったので、今回はEarthlyが持つキャッシュ機構だけにフォーカスして書く。

Earthlyにおけるキャッシュ

Earthlyは環境に依存しない実行環境を提供するため、キャッシュにおいてもローカルファイルキャッシュのようなホストマシンに依存するタイプのキャッシュ機構*1を提供しない。代わりに、ビルドプロセスの中で SAVE IMAGE を呼んでいるターゲットの成果物をDockerイメージ化してキャッシュしコンテナレジストリに格納する。ビルドの実行時にはEarthlyが必要なDockerイメージのキャッシュをコンテナレジストリから取得する。

キャッシュイメージをpushするコンテナレジストリとして、使える人はDockerhubを使うのがいいとは思うものの、Dockerhubは無料プランだとレートリミットがかなり厳しくキャッシュとしてreadが頻繁に行われるとすぐ上限に達してしまう。なので、個人利用でEarthlyを使うのならばGithub Container Registryをキャッシュ用のコンテナレジストリとして使うのがおすすめ。

www.kaizenprogrammer.com

ここからは、Earthlyがキャッシュの機能として2種類提供しているInline cacheExplicit cacheについて説明する。

Inline cache

ターゲットの成果物であるDockerイメージを個別にキャッシュする。

以下を例としてIzumiSy/go-cleanarchitectureのEarthfile から抜粋。

deps:
  RUN apk add --no-cache build-base
  COPY go.mod go.sum .
  RUN go mod download
  SAVE IMAGE --cache-hint

build:
  FROM +deps
  COPY . .
  RUN go build -o build/go-cleanarchitecture main.go
  SAVE ARTIFACT build/go-cleanarchitecture AS LOCAL build/go-cleanarchitecture

image:
  COPY +build/go-cleanarchitecture .
  EXPOSE 8080
  ENTRYPOINT ["/go-cleanarchitecture/go-cleanarchitecture"]
  SAVE IMAGE --push ghcr.io/izumisy/go-cleanarchitecture:cache

上記のEarthfileのうち一番最後の行の SAVE IMAGE --push ghcr.io/izumisy/go-cleanarchitecture:cache の箇所がInline cacheに該当する。SAVE IMAGE コマンドは --push オプションをつけることでリモートのコンテナレジストリにキャッシュとしてのイメージをpushする*2ようになる。なお、キャッシュのソースとなるイメージを別で指定する --cache-from というオプションもあり、キャッシュのpushとpullでそれぞれ別イメージを指定することもできる。

以上のEarthfileに対して以下のコマンドを実行すると、初回実行時はghcr.io/izumisy/go-cleanarchitecture:cacheにキャッシュイメージが作られ、以降は実行時にキャッシュイメージが使用される。

$ earthly --use-inline-cache --save-inline-cache --push +image

Explicit cache

上のInline cacheの例で抜粋したEarthfileのうち、SAVE IMAGE --cache-hintの箇所がExplicit cacheに該当するもの。

deps:
  RUN apk add --no-cache build-base
  COPY go.mod go.sum .
  RUN go mod download
  SAVE IMAGE --cache-hint

Earthlyの実行時には以下のように --remote-cache オプションでExplicit cacheを格納するDockerイメージの名前を指定する。こちらも --push オプションがあればキャッシュがコンテナレジストリへpushされる。

$ earthly --push --remote-cache=ghcr.io/izumisy/go-cleanarchitecture-explicit:cache +image

Explicit cacheはEarthfileを通してひとつしか存在しない。Inline cacheのようにEarthfile中に複数異なる名前でキャッシュイメージを指定することはできず、--cache-hint を指定しているすべてのターゲットのレイヤキャッシュが実行時に --remote-cache で向けられているキャッシュイメージへすべて格納される。

もしEarthlyの実行時にEarthfile内でExplicit cacheが指定されている場合には、Earthlyは一番最初にこのキャッシュを取得するような動作をする(たぶん)

Inline cacheとExplicit cacheの併用

自分が試した0.6.2時点では、ソースとしての併用はできるが--pushオプションで両方をpushすることはできない。

なので、自分のCircleCIの設定ではコンテナレジストリへのInline cacheイメージのpushはローカルから実行するようにし、CI上ではExplicit cacheのみをpushするようにしている。--use-inline-cacheのオプションはExplicit cacheと併用できる。

jobs:
  integration-test:
    machine: true
    resource_class: large
    steps:
      - run:
          name: Setup docker with ghcr.io
          command: |
            docker login ghcr.io --username "izumisy" --password "$DOCKERUSER_TOKEN"
      - run:
          name: Setup earthly
          command: |
            wget https://github.com/earthly/earthly/releases/download/v0.6.1/earthly-linux-amd64 -O /tmp/earthly
            chmod +x /tmp/earthly
            /tmp/earthly bootstrap
            /tmp/earthly --version
      - checkout
      - run:
          name: Run earthly
          command: |
            /tmp/earthly --use-inline-cache --push \
              --remote-cache=ghcr.io/izumisy/go-cleanarchitecture-explicit:cache \
              +integration-test

ローカルからのInline cacheイメージのpushをするコマンドは次のような雰囲気

$ earthly --push --save-inline-cache +images

*1:前回の記事で「あったらいいのに」とか書いたけど冷静に考えたらEarthlyの思想的にはありえなかった...

*2:ちなみに--pushオプションがなくてもローカルにはキャッシュが作られる