はじめに
先日、社内のPythonプロジェクトのDockerビルドが遅すぎて限界を感じた。
docker build のたびに pip install -r requirements.txt が2〜3分かかる。CIが走るたびに待つ時間が積み重なって、1日あたり結構な時間を無駄にしていることに気づいた。
そこで試したのが uv(Astralが開発しているRust製のPythonパッケージマネージャー)への移行。
結果、ビルド時間が約4分 → 約55秒 になった。この記事ではその移行手順と、実際にハマったポイントをまとめておく。
環境・構成
- Python 3.12
- Docker(マルチステージビルド)
- requirements.txt(50パッケージ程度)
- GitHub Actions(CI)
移行前のDockerfile(pip版)
FROM python:3.12-slim AS builder
WORKDIR /app
COPY requirements.txt .
RUN pip install --no-cache-dir -r requirements.txt
COPY . .
FROM python:3.12-slim
WORKDIR /app
COPY --from=builder /app /app
CMD ["python", "main.py"]
これで pip install 部分だけで約2〜3分かかっていた。
移行後のDockerfile(uv版)
FROM python:3.12-slim AS builder
# uvのインストール
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
WORKDIR /app
# 依存ファイルをコピーしてインストール
COPY requirements.txt .
RUN uv pip install --system -r requirements.txt
COPY . .
FROM python:3.12-slim
# uv自体は実行時イメージに不要なのでコピーしない
COPY --from=builder /app /app
COPY --from=ghcr.io/astral-sh/uv:latest /uv /usr/local/bin/uv
CMD ["python", "main.py"]
実測値の比較
| ステップ | pip | uv |
|---|---|---|
| パッケージインストール | 約185秒 | 約42秒 |
| Dockerイメージビルド全体 | 約240秒 | 約60秒 |
約4倍の高速化。GitHubのCI月間コストも体感で減った(Actions使用分数が削減)。
実際にハマった3つのポイント
1. --system フラグを忘れるとインストール先がズレる
uvはデフォルトで仮想環境(.venv)にインストールしようとする。Dockerコンテナ内でグローバルにインストールしたい場合は --system フラグが必要。
# これだと .venv/ に入ってしまい、CMD実行時にimport errorになる
uv pip install -r requirements.txt
# これが正しい
uv pip install --system -r requirements.txt
最初これを忘れて「なんでimportできないんだ」と30分悩んだ。
2. uv.lock はDockerビルドに不要(requirements.txtで十分)
uv には uv.lock(lockファイル)機能があるが、Dockerビルドでは requirements.txt をそのまま使えば再現性は担保できる。pyproject.toml + uv.lock に完全移行する場合は別だが、既存プロジェクトの移行コストを下げたければ requirements.txt のままで十分。
# requirements.txtから直接インストール(lockファイル不要)
uv pip install --system -r requirements.txt
3. Dockerレイヤーキャッシュの効き方は pip と同じ
COPY requirements.txt . を先にやって、その後ソースコードをコピーする構成は pip と全く同じで問題ない。uvに変えてもDockerのキャッシュ戦略は変える必要がない。
# requirements.txt だけ先にコピー → キャッシュが効く
COPY requirements.txt .
RUN uv pip install --system -r requirements.txt
# コードは後にコピー(変更があってもインストールキャッシュは保持)
COPY . .
GitHub Actionsでの設定例
CI上でもuvを使うと actions/setup-python のキャッシュ機能と組み合わせやすい。
- name: Set up Python
uses: actions/setup-python@v5
with:
python-version: '3.12'
- name: Install uv
run: pip install uv
- name: Install dependencies
run: uv pip install --system -r requirements.txt
あるいは astral-sh/setup-uv アクションを使う方法もある。
- name: Install uv
uses: astral-sh/setup-uv@v3
- name: Install dependencies
run: uv pip install --system -r requirements.txt
まとめ
uvへの移行で得られたもの:
- ビルド時間が約4倍速化(185秒 → 42秒)
- 移行コストは低い(requirements.txt をそのまま使える)
- ハマりポイントは
--systemフラグの1点のみ
Dockerfileの pip install を uv pip install --system に変えるだけで試せるので、まず1プロジェクトで試してみると良いと思う。