🐍

uv on Docker をやっている

に公開

TL;DR

本記事に記載するコードは下記のリポジトリよりダウンロードいただけます。(⭐おまちしております)

https://github.com/shunsock/uv_on_docker_playground

コンテナの実行。

uv_on_docker_playground (main) » docker run -it uv_on_docker
Bytecode compiled 1 file in 59ms
Hello World

開発用コンテナとして利用する。

$ docker compose watch app
$ docker compose exec app bash
$ root@393b1996df7c:/app# uv run hello
Bytecode compiled 1 file in 39ms
# Hello World

前書き

以前、uv on Dockerをやっているという記事を投稿しました。

https://zenn.dev/shundeveloper/articles/bd90f3677fead1

この時点では、「使ってみた程度」のレベルで投稿していたのですが、定期的にアクセスが来ています。今見ると色々修正したい部分があるので新しく書き直すことにしました。

※ 本記事ではuvとは何か、uvコマンドの使い方は解説しません。GitHubのドキュメント貼るので読んでみてください。

https://github.com/astral-sh/uv

Dockerfile

次は、開発用コンテナの設定です。(のちに本番に有効な設定を紹介します)

FROM ghcr.io/astral-sh/uv:python3.12-bookworm-slim

WORKDIR /app

ENV UV_COMPILE_BYTECODE=1
ENV UV_LINK_MODE=copy

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-dev

ADD . /app
RUN --mount=type=cache,target=/root/.cache/uv \
    uv sync --frozen

ENV PATH="/app/.venv/bin:$PATH"

ENTRYPOINT []

CMD ["uv", "run", "hello"]

Docker Image

DockerのImageですが有用なものが配布されています。distroless, alpine, debianと複数の選択肢があります。今回はdebianを利用しています。

# distroless
ghcr.io/astral-sh/uv:latest
ghcr.io/astral-sh/uv:{major}.{minor}.{patch}, e.g., ghcr.io/astral-sh/uv:0.6.14
ghcr.io/astral-sh/uv:{major}.{minor}, e.g., ghcr.io/astral-sh/uv:0.6 (the latest patch version)

# alpine:3.20:
ghcr.io/astral-sh/uv:alpine
ghcr.io/astral-sh/uv:alpine3.20

# Based on debian:bookworm-slim:
ghcr.io/astral-sh/uv:debian-slim
ghcr.io/astral-sh/uv:bookworm-slim

# Based on buildpack-deps:bookworm:
ghcr.io/astral-sh/uv:debian
ghcr.io/astral-sh/uv:bookworm

# Based on python3.x-alpine:
ghcr.io/astral-sh/uv:python3.13-alpine
ghcr.io/astral-sh/uv:python3.12-alpine
...
# Based on python3.x-bookworm:
ghcr.io/astral-sh/uv:python3.13-bookworm
ghcr.io/astral-sh/uv:python3.12-bookworm
...
# Based on python3.x-slim-bookworm:
ghcr.io/astral-sh/uv:python3.13-bookworm-slim
ghcr.io/astral-sh/uv:python3.12-bookworm-slim
...

全て確認する場合は、次のリンクをご参照ください。
https://docs.astral.sh/uv/guides/integration/docker/#available-images

キャッシュ

uv sync --no-install-project は、プロジェクト自体ではなく、その依存関係のみをインストールします。プロジェクトと異なり、依存関係は一般的に静的なのでこの設定を利用しています。

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-dev

なお、本番環境などで実行するときは --no-editable オプションが有用です。これを利用すると、あるステージで同期された仮想環境にプロジェクトを含め、その後最終イメージへはソースコードではなく仮想環境のみをコピーすることが可能です。

マルチステージビルドの事例
# Install uv
FROM python:3.12-slim AS builder
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/

# Change the working directory to the `app` directory
WORKDIR /app

# Install dependencies
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

# Copy the project into the intermediate image
ADD . /app

# Sync the project
RUN --mount=type=cache,target=/root/.cache/uv \
    uv sync --frozen --no-editable

FROM python:3.12-slim

# Copy the environment, but not the source code
COPY --from=builder --chown=app:app /app/.venv /app/.venv

# Run the application
CMD ["/app/.venv/bin/hello"]

ByteCode Compilation

uvでは sync するときに Python Interpreterの中間表現にビルドするかを指定できます。ビルドする関係でインストール時の実行時間が伸びますが、パッケージの初回呼び出しを高速化可能です。

RUN uv sync --compile-bytecode

また次のように記述するとDockerfile内で実行されるすべての命令がこの設定の影響を受け、結果として全体がコンパイル対象になります。

ENV UV_COMPILE_BYTECODE=1

compose.yml

services:
  app:
    build: .
    tty: true
    working_dir: /app
    command: ["tail", "-f", "/dev/null"]
    develop:
      watch:
        - action: sync
          path: .
          target: /app
          ignore:
            - .venv/
        - action: rebuild
          path: ./uv.lock

watch の部分はお好みで。ファイル変更の監視して、差分を検知すると自動でsyncやrebuildが走ります。

pyproject.toml

[project]
name = "app"
version = "0.1.0"
description = "Add your description here"
readme = "README.md"
requires-python = ">=3.12"
dependencies = []

[build-system]
requires = ["hatchling"]
build-backend = "hatchling.build"

[project.scripts]
hello = "app:hello"

特に手を入れていない設定です。今回紹介したプロジェクトは以前のuvのバージョンで初期化したため、hello.pyになっています。現在(>=v0.6.0)では、uv init projectするとmain.pyが生成されます。

Prior to v0.6.0, uv created a file named hello.py instead of main.py.

https://docs.astral.sh/uv/concepts/projects/init/#applications

Dependabot

Dependabotで簡単に依存関係の管理ができます。Dependabotはuvの依存関係まで含めたバージョン管理用のファイル uv.lock をサポートしています。次のように.github/dependabot.ymlを設定すれば大丈夫です。

version: 2
updates:
  - package-ecosystem: "github-actions"
    directory: "/"
    schedule:
      interval: "monthly"
  - package-ecosystem: "uv"
    directory: "/"
    schedule:
      interval: "monthly"
    allow:
      - dependency-name: "pydantic"
    ignore:
      - dependency-name: "pydantic"
        update-types:
          - "version-update:semver-patch"

https://github.com/shunsock/fizzbuzz/blob/main/.github/dependabot.yml

この機能は2025年3月13日にreleaseされたものです。

https://github.blog/changelog/2025-03-13-dependabot-version-updates-now-support-uv-in-general-availability/

あとがき

uv使い始めた方の参考になれば幸いです。

なお、最近は nix developで開発することが多いです。Nixで開発しておけば、配布も楽なのでおすすめです。

{
  description = "uv 環境の開発シェル (Python 3.13)";

  inputs = {
    nixpkgs.url = "github:NixOS/nixpkgs/nixos-unstable";
    flake-utils.url = "github:numtide/flake-utils";
  };

  outputs = { self, nixpkgs, flake-utils }:
    flake-utils.lib.eachDefaultSystem (system:
      let
        pkgs = import nixpkgs { inherit system; };
      in {
        devShell = pkgs.mkShell {
          buildInputs = [
            pkgs.python313
            pkgs.uv
          ];
          shellHook = ''
            echo "uv version: $(uv --version)"
            echo "python version: $(python --version)"
          '';
        };
      });
}

参考文献

https://docs.astral.sh/uv/guides/integration/docker/

https://github.blog/changelog/2025-03-13-dependabot-version-updates-now-support-uv-in-general-availability/

https://github.com/astral-sh/uv-docker-example

Discussion