pex でマルチステージビルドを行う
Pants で Python アプリケーションを pex にまとめるとき、ソースと外部パッケージを別々に構築して Docker のキャッシュを使いやすくします。BUILDファイルと Dockerfile の例を使い、マルチステージビルドの構成を説明します。
マルチステージビルドとは
マルチステージビルドとは、Dockerfile のビルドステージを複数に分けるビルド手法です。ビルドに必要なファイルと実行に必要なファイルを分離できます。ファイル分離により、最終的なイメージサイズを小さくしたり、キャッシュを効きやすくしたりできます。
pex でマルチステージビルドを行う
pex は、Python の依存パッケージを含めた実行可能な単一ファイルを作成するツールです。 この例では、ソースコードと外部パッケージを分けて pex を構築し、Dockerfile の別々のステージで処理します。依存パッケージが変わらなければ、その部分のキャッシュを再利用できるため、ビルド時間の短縮が期待できます。
例
Pants を使った次のようなディレクトリ構成を想定します。
| .
├── Dockerfile
├── requirements.txt
├── BUILD
└── main.py
|
次のように pex を構築すると、ソースと 3rd party パッケージを分離できます。
| BUILD |
|---|
| pex_binary(
name="binary-deps",
execution_mode="venv",
entry_point="main.py",
layout="packed",
include_sources=False,
include_tools=True,
)
pex_binary(
name="binary-srcs",
execution_mode="venv",
entry_point="main.py",
layout="packed",
include_requirements=False,
include_tools=True,
)
|
| BUILD |
|---|
| docker_image(
name="img-deps",
registries=["foo"],
repository="deps",
image_tags=[
"latest",
],
instructions=[
"FROM python:3.11-slim",
"COPY binary-deps.pex /binary-deps.pex",
"RUN PEX_TOOLS=1 python3.11 /binary-deps.pex venv --scope=deps --compile /bin/app",
],
)
docker_image(
source=None,
name="img-srcs",
registries=["foo"],
repository="srcs",
image_tags=[
"latest",
],
instructions=[
"FROM python:3.11-slim",
"COPY binary-srcs.pex /binary-srcs.pex",
"RUN PEX_TOOLS=1 python3.11 /binary-srcs.pex venv --scope=srcs --compile /bin/app",
],
)
docker_image(
source="Dockerfile",
name="final-image",
registries=["foo"],
repository="bar",
image_tags=["latest"],
dependencies=[
":img-srcs",
":img-deps",
],
)
|
| Dockerfile |
|---|
| FROM python:3.11-slim
COPY --from=foo/deps:latest /bin/app /bin/app
COPY --from=foo/srcs:latest /bin/app /bin/app
ENTRYPOINT ["/bin/app/pex"]
|
上記のコードを使ってコンテナイメージをビルドします。キャッシュが効きやすくなり、ビルド時間の短縮も期待できます。
注意点
ビルド時と実行時で、Python のパスが違うと動かない場合があります。パスが異なる場合は、pex 構築のオプションでshebangを指定するか、シンボリックリンクを張るなどの対応が必要です。