動かざることバグの如し

近づきたいよ 君の理想に

uvで.venvを作らずにシステムのパッケージとしてインストールする方法

例えば以下のような開発用のDockerfileがあったとする。

FROM python:3.12

ENV UV_PROJECT_ENVIRONMENT="/usr/local/"

WORKDIR /app

ADD pyproject.toml ./
ADD uv.lock ./
RUN pip install uv
RUN uv sync --frozen --no-cache

その場合開発時はリアルタイムにファイル内容を更新したいので、ホストのカレントディレクトリと/appをマウントしてコンテナを起動したい。

そうするとDockerfileでビルドした.venvが消えてしまう。

uvはデフォルトでは、プロジェクトごとに隔離された環境、すなわち仮想環境(.venv)を生成する。 これは、Pythonの依存関係をプロジェクトごとに分離し、異なるプロジェクト間でのパッケージの競合を避けるためだ。 uv sync コマンドは、この分離された環境に依存パッケージをインストールする。これにより、システムのPython環境を汚染することなく、プロジェクト固有の依存関係を管理できる。

調べると UV_SYSTEM_PYTHON=true をつけると.venvを作らずにシステムのパッケージとしてインストールされるらしい。

ENV UV_SYSTEM_PYTHON=true

しかし

だが、試してみても依然として.venvはつくられたままだった。調べると uv sync には効かないらしい。

ENV UV_SYSTEM_PYTHON=1 still creates .venv and dependencies aren't able to be found · Issue #9067 · astral-sh/uv

対策

結果的には UV_PROJECT_ENVIRONMENT="/usr/local/" を付与することでシステムのパッケージとしてインストールできた。

FROM python:3.12

ENV UV_PROJECT_ENVIRONMENT="/usr/local/"

WORKDIR /app

ADD pyproject.toml ./
ADD uv.lock ./
RUN pip install uv
RUN uv sync --frozen --no-cache

UV_PROJECT_ENVIRONMENT は、uvが依存パッケージをインストールするベースディレクトリを定義する環境変数だ。 デフォルトでは、プロジェクトディレクトリ内に .venv ディレクトリが作成され、そこにパッケージがインストールされる。 しかし、この環境変数/usr/local/ に設定すると、uvはシステムのパッケージディレクトリ(/usr/local/lib/python3.x/site-packages/)に直接パッケージをインストールするようになる。 これは、実質的に仮想環境を使わずに、システム全体にパッケージをインストールすることと同じだ。 /usr/local/ を指定する理由は、このディレクトリが一般的にシステム管理者がパッケージをインストールする場所として使用され、システムの他のPython環境と競合しにくいためだ。 Docker環境においては、このディレクトリは通常コンテナイメージのレイヤーの一部となり、コンテナ内の全てのプロセスで共有されることになる。