maybe daily dev notes

私の開発日誌

Dockerfileが複数のBuild contextをサポートするようになった

はてな記事執筆機能の素振りがてら書いてみる。

序論

最近Dockerfileをビルドする際に複数のBuild contextを指定できるようになったらしい。

www.docker.com

これを使うと、例えば共通モジュールが別ディレクトリに切り出されているような場合に、よりきれいにビルドコンテキストを渡すことができる。 以下に簡単な例とともに紹介する。

従来の問題

例えばこんなディレクトリ構成の場合:

.
├── app1
│   ├── Dockerfile
│   └── index.py
├── app2
│   ├── Dockerfile
│   └── index.py
└── common
    └── util.py

従来だと app1 をビルドする際に common ディレクトリもBuild contextに含めたい場合、ルートディレクトリをBuild contextに含める必要があった。

# ビルド実行
docker build .

これだとDockerfile内でファイルを参照する際もルートディレクトリからの相対パスとなり、美しくない。また、Build contextに関係のないディレクトリ (app2) が含まれるのも(実害はなさそうだが)気になる。

FROM python:3.9.12-buster
COPY app1/index.py ./
COPY common/util.py ./
CMD ["python3", "index.py"]

この課題感はこちらのIssueでも議論されていた。 How to include files outside of Docker's build context? - Stack Overflow

新しいMulti build context機能

一方、新しいMulti build context機能を使うと、以下のように書ける。

# syntax=docker/dockerfile:1.4
FROM python:3.9.12-buster
# app1からの相対パスで解決
COPY index.py ./
# commonディレクトリは別のBuild contextから読み込み
COPY --from=common util.py ./
CMD ["python3", "index.py"]
# ビルド実行
cd app1
docker buildx build . --build-context common=../common

このように、buildx build コマンドの --build-context オプションにより、任意の数のBuild contextを名前付きで追加できる。これらのBuild contextは、上の例のように COPY --from などで指定可能 (Multi-stage buildで使う記法に似ている。)

これにより、単一Build contextしか渡せなかった従来の問題が解決されている。

その他

今のところ --build-context オプションは buildx build コマンドでのみ利用でき、 docker build コマンドでは利用できない。

docker buildx build | Docker Documentation

docker build | Docker Documentation

このため、既存ツールと連携したい場合は工夫が必要/不可能かもしれない。

自分は最近Docker buildをもっぱらAWS CDKから呼び出しているので、CDKが対応しない限りは使えなさそう。いずれはそういったところも対応してくれたらなーと思う。