docker-compose でキャッシュが効かない?
code:docker-compose.yaml
version: '3.8'
services:
app:
build:
context: .
dockerfile: ./Dockerfile
cache_from:
- build-in-host:latest
code:Dockerfile
FROM alpine:3.12.0
RUN mkdir /workdir
COPY command.ash /workdir
ENV PATH $PATH:/workdir
code:command.ash
echo 1
echo 2
echo 3
のような単純な例、キャッシュ効かないはずないのになと見ていた
例えば docker コマンドでビルドすると2回目移行キャッシュが効いてる(各ステップで Using cache) になっている
code:build
$ docker build -t build-in-host:latest .
Sending build context to Docker daemon 5.12kB
Step 1/5 : FROM alpine:3.12.0
---> a24bb4013296
Step 2/5 : RUN mkdir /workdir
---> Using cache
---> ff6d42c61898
Step 3/5 : COPY command.ash /workdir
---> Using cache
---> 9ba8b6066185
Step 4/5 : ENV PATH $PATH:/workdir
---> Using cache
---> c57bd2498512
---> Using cache
---> 62a56f559959
Successfully built 62a56f559959
Successfully tagged build-in-host:latest
docker build -t build-in-host:latest . 3.43s user 3.56s system 90% cpu 7.758 total
compose build は途中までしか Using cache が出てない
code:compose-build
$ docker-compose build
Building app
Step 1/5 : FROM alpine:3.12.0
---> a24bb4013296
Step 2/5 : RUN mkdir /workdir
---> Using cache
---> ff6d42c61898
Step 3/5 : COPY command.ash /workdir
---> f300f369a17f
Step 4/5 : ENV PATH $PATH:/workdir
---> Running in 31c7a3526287
Removing intermediate container 31c7a3526287
---> 372c132c322e
---> Running in c27766d7239d
Removing intermediate container c27766d7239d
---> fab1b731a315
Successfully built fab1b731a315
Successfully tagged cache-from-compose_app:latest
docker-compose build 3.64s user 3.37s system 86% cpu 8.109 total
元々 Cloud Build 上でキャッシュきかねーなと思ってみていて、dind だしホスト側の image ディレクトリとか sock とかマウントする系なのかな、と思って調べていたけど、ローカルでも普通にキャッシュが効いていないケースがあった COMPOSE_DOCKER_CLI_BUILD=1 で docker CLI にビルドを移譲する
この環境変数は docker-compose で Buildkit を使うならこれだ! と言われているが、あまり正確ではなくて docker CLI に移譲するフラグ、docker CLI は DOCKER_BUILDKIT=1 で Buildkit を利用する、という構造。Buildkit を使っていなくてもよい
$ docker-compose build --help にこう書いてある
--progress string Set type of progress output (auto, plain, tty).
EXPERIMENTAL flag for native builder.
To enable, run with COMPOSE_DOCKER_CLI_BUILD=1)
native じゃない builder とは? compose がなんかやっている系だと思うけど何か
cli.py からは project.up や project.build に cli=True|False で渡ってる
builder = self.client if not cli else _CLIBuilder(progress)
self.client と _CLIBuilder どちらも build インタフェースに色々渡す
実体は from docker import APIClient のインスタンス
_CLIBuilder は docker build のプロセスを立ち上げて出力をつなげてる
まさに docker コマンドに移譲してる
Docker SDK (docker-py) はなにが悪いのか
tar の実装の差異によって同じファイルと判定されなてキャッシュが切れるようだ
docker cli がホストのファイルを tar 化する実装と、docker-py が tar 化する際の差異🦏
issue の議論しか追っていないが、いかにもありそう
COMPOSE_DOCKER_CLI_BUILD=1 docker-compose run ... でビルドが発生する場合にはこの環境変数を使ってくれない
このあたりで project.up(..., cli=native_builder) すれば動きそうだが
別件だけど、docker-compose で cache_from したら効かない問題もある気がする