Dockerでuvを使用する
はじめに
Tip
Dockerでアプリケーションをビルドする際のベストプラクティスの例として、uv-docker-example
プロジェクトを参照してください。
コンテナ内でuvを実行する
ビルド済みのuvが利用可能なDockerイメージが公開されています。コンテナ内でuvコマンドを実行するには:
利用可能なイメージ
uvはuv
バイナリを含むdistroless Dockerイメージを提供しています。以下のタグが公開されています:
ghcr.io/astral-sh/uv:latest
ghcr.io/astral-sh/uv:{major}.{minor}.{patch}
, e.g.,ghcr.io/astral-sh/uv:0.5.1
ghcr.io/astral-sh/uv:{major}.{minor}
, e.g.,ghcr.io/astral-sh/uv:0.5
(the latest patch version)
さらに、uvは以下のイメージも公開しています:
alpine:3.20
ベース:ghcr.io/astral-sh/uv:alpine
ghcr.io/astral-sh/uv:alpine3.20
debian:bookworm-slim
ベース:ghcr.io/astral-sh/uv:debian-slim
ghcr.io/astral-sh/uv:bookworm-slim
buildpack-deps:bookworm
ベース:ghcr.io/astral-sh/uv:debian
ghcr.io/astral-sh/uv:bookworm
python3.x-alpine
ベース:ghcr.io/astral-sh/uv:python3.13-alpine
ghcr.io/astral-sh/uv:python3.12-alpine
ghcr.io/astral-sh/uv:python3.11-alpine
ghcr.io/astral-sh/uv:python3.10-alpine
ghcr.io/astral-sh/uv:python3.9-alpine
ghcr.io/astral-sh/uv:python3.8-alpine
python3.x-bookworm
ベース:ghcr.io/astral-sh/uv:python3.13-bookworm
ghcr.io/astral-sh/uv:python3.12-bookworm
ghcr.io/astral-sh/uv:python3.11-bookworm
ghcr.io/astral-sh/uv:python3.10-bookworm
ghcr.io/astral-sh/uv:python3.9-bookworm
ghcr.io/astral-sh/uv:python3.8-bookworm
python3.x-slim-bookworm
ベース:ghcr.io/astral-sh/uv:python3.13-bookworm-slim
ghcr.io/astral-sh/uv:python3.12-bookworm-slim
ghcr.io/astral-sh/uv:python3.11-bookworm-slim
ghcr.io/astral-sh/uv:python3.10-bookworm-slim
ghcr.io/astral-sh/uv:python3.9-bookworm-slim
ghcr.io/astral-sh/uv:python3.8-bookworm-slim
As with the distroless image, each image is published with uv version tags as
ghcr.io/astral-sh/uv:{major}.{minor}.{patch}-{base}
and
ghcr.io/astral-sh/uv:{major}.{minor}-{base}
, e.g., ghcr.io/astral-sh/uv:0.5.1-alpine
.
詳細については、GitHub Containerページを参照してください。
uvのインストール
uvが事前にインストールされた上記のイメージのいずれかを使用するか、公式のdistroless Dockerイメージからバイナリをコピーしてuvをインストールします:
または、インストーラーを使用します:
FROM python:3.12-slim-bookworm
# インストーラーはリリースアーカイブをダウンロードするためにcurl(および証明書)を必要とします
RUN apt-get update && apt-get install -y --no-install-recommends curl ca-certificates
# 最新のインストーラーをダウンロード
ADD https://astral.sh/uv/install.sh /uv-installer.sh
# インストーラーを実行して削除
RUN sh /uv-installer.sh && rm /uv-installer.sh
# インストールされたバイナリが `PATH` にあることを確認
ENV PATH="/root/.local/bin/:$PATH"
この方法ではcurl
が利用可能である必要があります。
いずれの場合も、特定のuvバージョンに固定することがベストプラクティスです。例:
または、インストーラーを使用する場合:
プロジェクトのインストール
uvを使用してプロジェクトを管理している場合、イメージにコピーしてインストールできます:
# プロジェクトをイメージにコピー
ADD . /app
# 凍結されたロックファイルを使用して新しい環境にプロジェクトを同期
WORKDIR /app
RUN uv sync --frozen
Important
プロジェクトの仮想環境はローカルプラットフォームに依存しており、イメージ内で新たに作成する必要があるため、リポジトリ内の.dockerignore
ファイルに.venv
を追加することがベストプラクティスです。
次に、デフォルトでアプリケーションを起動するには:
Tip
Dockerイメージのビルド時間を改善するために、依存関係のインストールとプロジェクト自体のインストールを分離する中間レイヤーを使用することがベストプラクティスです。
完全な例はuv-docker-example
プロジェクトで確認できます。
環境の使用
プロジェクトがインストールされたら、仮想環境のバイナリディレクトリをパスの先頭に配置してプロジェクト仮想環境を_アクティブ化_することができます:
または、環境を必要とするコマンドにはuv run
を使用できます:
Tip
代わりに、プロジェクト環境パスの設定を行うUV_PROJECT_ENVIRONMENT
設定を同期前に設定して、システムPython環境にインストールし、環境のアクティブ化をスキップすることもできます。
インストールされたツールの使用
インストールされたツールを使用するには、ツールバインディレクトリがパスに含まれていることを確認します:
$ docker run -it $(docker build -q .) /bin/bash -c "cowsay -t hello"
_____
| hello |
=====
\
\
^__^
(oo)\_______
(__)\ )\/\
||----w |
|| ||
Note
ツールバインディレクトリの場所は、コンテナ内でuv tool dir --bin
コマンドを実行して確認できます。
代わりに、一定の場所に設定することもできます:
muslベースのイメージでのPythonのインストール
uvは互換性のあるPythonバージョンをインストールしますが、muslベースのディストリビューション用のPythonのインストールはまだサポートしていません。例えば、PythonがインストールされていないAlpine Linuxベースのイメージを使用している場合、システムパッケージマネージャーで追加する必要があります:
コンテナでの開発
開発時には、プロジェクトディレクトリをコンテナにマウントすることが有用です。このセットアップでは、プロジェクトへの変更がイメージを再ビルドすることなくコンテナ化されたサービスに即座に反映されます。ただし、プロジェクト仮想環境(.venv
)をマウントに含めないことが重要です。仮想環境はプラットフォーム固有であり、イメージ用にビルドされたものを保持する必要があります。
docker run
でプロジェクトをマウントする
作業ディレクトリ内のプロジェクトを/app
にバインドマウントし、匿名ボリュームで.venv
ディレクトリを保持します:
Tip
コンテナが終了したときにコンテナと匿名ボリュームがクリーンアップされるように、--rm
フラグを含めています。
完全な例はuv-docker-example
プロジェクトで確認できます。
docker compose
でのwatch
の設定
Docker composeを使用する場合、コンテナ開発のためのより高度なツールが利用可能です。
watch
オプションは、バインドマウントよりも細かい粒度での設定が可能であり、ファイルが変更されたときにコンテナ化されたサービスの更新をトリガーすることができます。
Note
この機能は、Docker Desktop 4.24にバンドルされているCompose 2.22.0が必要です。
プロジェクトディレクトリを仮想環境を同期せずにマウントし、構成が変更されたときにイメージを再ビルドするようにwatch
を設定します:
services:
example:
build: .
# ...
develop:
# アプリを更新するための`watch`設定を作成
#
watch:
# 作業ディレクトリをコンテナ内の`/app`ディレクトリと同期
- action: sync
path: .
target: /app
# プロジェクト仮想環境を除外
ignore:
- .venv/
# `pyproject.toml`の変更時にイメージを再ビルド
- action: rebuild
path: ./pyproject.toml
次に、開発セットアップでコンテナを実行するにはdocker compose watch
を実行します。
完全な例はuv-docker-example
プロジェクトで確認できます。
最適化
バイトコードのコンパイル
バイトコードへのPythonソースファイルのコンパイルは、通常、インストール時間が増加する代わりに起動時間を改善するため、プロダクションイメージにとって望ましいです。
バイトコードのコンパイルを有効にするには、--compile-bytecode
フラグを使用します:
または、UV_COMPILE_BYTECODE
環境変数を設定して、Dockerfile内のすべてのコマンドがバイトコードをコンパイルするようにします:
キャッシュ
キャッシュマウントを使用して、ビルド間のパフォーマンスを向上させることができます:
デフォルトのUV_LINK_MODE
を変更すると、キャッシュと同期ターゲットが別のファイルシステム上にあるため、ハードリンクを使用できないことに関する警告が表示されなくなります。
キャッシュをマウントしていない場合、--no-cache
フラグを使用するかUV_NO_CACHE
を設定して、イメージサイズを削減できます。
Note
キャッシュディレクトリの場所は、コンテナ内でuv cache dir
コマンドを実行して確認できます。
代わりに、一定の場所に設定することもできます:
中間レイヤー
uvを使用してプロジェクトを管理している場合、--no-install
オプションを使用して推移的依存関係のインストールを独自のレイヤーに移動することで、ビルド時間を改善できます。
uv sync --no-install-project
はプロジェクトの依存関係をインストールしますが、プロジェクト自体はインストールしません。プロジェクトは頻繁に変更されますが、その依存関係は一般的に静的であるため、これは大きな時間の節約になります。
# uvのインストール
FROM python:3.12-slim
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
# 作業ディレクトリを`app`ディレクトリに変更
WORKDIR /app
# 依存関係のインストール
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --frozen --no-install-project
# プロジェクトをイメージにコピー
ADD . /app
# プロジェクトの同期
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen
pyproject.toml
はプロジェクトのルートと名前を識別するために必要ですが、プロジェクトの_内容_は最終的なuv sync
コマンドまでイメージにコピーされません。
Tip
ワークスペースを使用している場合、プロジェクト_および_ワークスペースメンバーを除外する--no-install-workspace
フラグを使用します。
同期から特定のパッケージを除外する場合は、--no-install-package <name>
を使用します。
非編集可能なインストール
デフォルトでは、uvはプロジェクトとワークスペースメンバーを編集可能モードでインストールし、ソースコードへの変更が環境に即座に反映されるようにします。
uv sync
およびuv run
はどちらも--no-editable
フラグを受け入れ、uvにプロジェクトを非編集可能モードでインストールするよう指示し、ソースコードへの依存を削除します。
マルチステージDockerイメージのコンテキストでは、--no-editable
を使用して、あるステージから同期された仮想環境にプロジェクトを含め、最終イメージには仮想環境のみ(ソースコードは含まない)をコピーできます。
例:
# uvのインストール
FROM python:3.12-slim AS builder
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
# 作業ディレクトリを`app`ディレクトリに変更
WORKDIR /app
# 依存関係のインストール
RUN --mount=type=cache,target=/root/.cache/uv \
--mount=type=bind,source=uv.lock,target=uv.lock \
--mount=type=bind,source=pyproject.toml,target=pyproject.toml \
uv sync --frozen --no-install-project --no-editable
# プロジェクトを中間イメージにコピー
ADD . /app
# プロジェクトの同期
RUN --mount=type=cache,target=/root/.cache/uv \
uv sync --frozen --no-editable
FROM python:3.12-slim
# ソースコードではなく環境をコピー
COPY --from=builder --chown=app:app /app/.venv /app/.venv
# アプリケーションの実行
CMD ["/app/.venv/bin/hello"]
一時的にuvを使用する
最終イメージでuvが不要な場合、各呼び出しでバイナリをマウントできます:
pipインターフェースの使用
パッケージのインストール
コンテナはすでに隔離されているため、このコンテキストでシステムPython環境を安全に使用できます。--system
フラグを使用してシステム環境にインストールします:
デフォルトでシステムPython環境を使用するには、UV_SYSTEM_PYTHON
変数を設定します:
代わりに、仮想環境を作成してアクティブ化できます:
RUN uv venv /opt/venv
# 仮想環境を自動的に使用
ENV VIRTUAL_ENV=/opt/venv
# エントリーポイントを環境の先頭に配置
ENV PATH="/opt/venv/bin:$PATH"
仮想環境を使用する場合、uvの呼び出しから--system
フラグを省略する必要があります:
要件のインストール
要件ファイルをインストールするには、コンテナにコピーします:
プロジェクトのインストール
要件と一緒にプロジェクトをインストールする場合、要件のコピーをプロジェクト自体のコピーから分離することがベストプラクティスです。これにより、プロジェクトの依存関係(頻繁には変更されない)をプロジェクト自体(非常に頻繁に変更される)とは別にキャッシュできます。