Skip to content

Instantly share code, notes, and snippets.

@aoirint
Last active April 19, 2025 03:54
Show Gist options
  • Save aoirint/20f01c1abcc942e458fab2755808d0e9 to your computer and use it in GitHub Desktop.
Save aoirint/20f01c1abcc942e458fab2755808d0e9 to your computer and use it in GitHub Desktop.
uvを使ったPythonプロジェクトのDockerイメージ構築例
# License: CC0-1.0
# syntax=docker/dockerfile:1.14
ARG BASE_IMAGE="ubuntu:22.04"
# Pythonバイナリをダウンロードするステージ
FROM "${BASE_IMAGE}" AS download-python-stage
# ダウンロードに必要なwgetとルート証明書をインストール
ARG DEBIAN_FRONTEND="noninteractive"
RUN <<EOF
set -eu
apt-get update
apt-get install -y \
wget \
ca-certificates
apt-get clean
rm -rf /var/lib/apt/lists/*
EOF
# astral-sh/python-build-standaloneからPythonバイナリをダウンロード
ARG PYTHON_VERSION="3.10.17+20250409"
ARG PYTHON_SHA256_DIGEST="ba9e325b2d3ccacc1673f98aada0ee38f7d2d262c52253e2b36f745c9ae6e070"
RUN <<EOF
set -eu
mkdir -p /opt/python-download
cd /opt/python-download
wget -O "python.tar.gz" "https://github.com/astral-sh/python-build-standalone/releases/download/20250409/cpython-${PYTHON_VERSION}-x86_64-unknown-linux-gnu-install_only.tar.gz"
echo "${PYTHON_SHA256_DIGEST} python.tar.gz" | sha256sum -c -
# Extract to ./python
tar xf "python.tar.gz"
mv ./python /opt/python
rm -f "python.tar.gz"
EOF
# Python仮想環境を構築するステージ
FROM "${BASE_IMAGE}" AS build-python-venv-stage
# Pythonライブラリのインストールに必要なgitをインストール
ARG DEBIAN_FRONTEND="noninteractive"
RUN <<EOF
set -eu
apt-get update
apt-get install -y \
git
apt-get clean
rm -rf /var/lib/apt/lists/*
EOF
# ホームディレクトリを持つ作業用ユーザーを作成
ARG BUILDER_UID="999"
ARG BUILDER_GID="999"
RUN <<EOF
set -eu
groupadd --non-unique --gid "${BUILDER_GID}" "builder"
useradd --non-unique --uid "${BUILDER_UID}" --gid "${BUILDER_GID}" --create-home "builder"
EOF
# 作業用ユーザーが使用する作業ディレクトリと出力先ディレクトリを作成
RUN <<EOF
set -eu
mkdir -p "/work"
chown -R "${BUILDER_UID}:${BUILDER_GID}" "/work"
mkdir -p "/cache/uv"
chown -R "${BUILDER_UID}:${BUILDER_GID}" "/cache/uv"
mkdir -p "/opt/python_venv"
chown -R "${BUILDER_UID}:${BUILDER_GID}" "/opt/python_venv"
EOF
# Pythonをインストール
COPY --chown=root:root --from=download-python-stage /opt/python /opt/python
ENV PATH="/home/builder/.local/bin:/opt/python/bin:${PATH}"
# 作業用ユーザーに切り替え
USER "${BUILDER_UID}:${BUILDER_GID}"
WORKDIR "/work"
# uvをインストール
ARG UV_VERSION="0.6.14"
RUN <<EOF
set -eu
pip install --user "uv==${UV_VERSION}"
EOF
# Python仮想環境を構築
COPY ./pyproject.toml ./uv.lock /work/
RUN --mount=type=cache,uid="${BUILDER_UID}",gid="${BUILDER_GID}",target=/cache/uv <<EOF
set -eu
cd "/work"
uv venv "/opt/python_venv"
UV_PROJECT_ENVIRONMENT="/opt/python_venv" uv sync
EOF
# Pythonプログラムのバイトコードをビルドするステージ
FROM "${BASE_IMAGE}" AS compile-source-stage
# Pythonをインストール
COPY --from=download-python-stage /opt/python /opt/python
# Python仮想環境をインストール
COPY --from=build-python-venv-stage /opt/python_venv /opt/python_venv
ENV PATH="/opt/python_venv/bin:/opt/python/bin:${PATH}"
ARG BUILDER_UID="999"
ARG BUILDER_GID="999"
# 作業用ディレクトリを作成
RUN <<EOF
set -eu
mkdir -p "/opt/my_project"
chown -R "${BUILDER_UID}:${BUILDER_GID}" "/opt/my_project"
EOF
# ソースコードをコンテナに追加
COPY --chown="${BUILDER_UID}:${BUILDER_GID}" ./my_project /opt/my_project/my_project
COPY --chown="${BUILDER_UID}:${BUILDER_GID}" ./main.py /opt/my_project/
# 作業用ユーザーに切り替え
USER "${BUILDER_UID}:${BUILDER_GID}"
WORKDIR "/opt/my_project"
# __pycache__を生成
RUN <<EOF
set -eu
python -m compileall .
EOF
# 実行用ステージ
FROM "${BASE_IMAGE}" AS runtime-stage
# Pythonをインストール
COPY --from=download-python-stage /opt/python /opt/python
# Python仮想環境をインストール
COPY --from=build-python-venv-stage /opt/python_venv /opt/python_venv
ENV PATH="/opt/python_venv/bin:/opt/python/bin:${PATH}"
# ソースコードをコンテナに追加
COPY --from=compile-source-stage /opt/my_project /opt/my_project
# 一般ユーザーに切り替え
# NOTE: 実行時にUIDを変更したい場合、docker run --user "1100:1100" のように変更可
USER "1000:1000"
ENTRYPOINT [ "python", "/opt/my_project/main.py" ]
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment