Изменение владельца файла .venv, созданного uv внутри Docker
У меня есть приложение Django, созданное с помощью uv, работающее внутри Docker. Я монтирую локальную файловую систему как том в контейнере, используя Docker Compose, чтобы изменения в исходном коде локально запускали перезагрузку приложения в контейнере. Это почти работает.
Проблема в том, что каталог .venv, созданный uv, принадлежит пользователю root контейнера Docker. Это означает, что я не могу редактировать эти файлы из своей локальной файловой системы без доступа root.
В прошлом я обходил это с помощью pip/pipenv/poetry/pdm, устанавливая venv от имени пользователя, не являющегося пользователем root, который имеет те же uid и guid-код, что и мой локальный пользователь (эти значения передаются в Docker через .env файл). Но я не могу понять, как это сделать для uv.
Dockerfile:
FROM python:3.12-slim-trixie
# create non-root user
RUN addgroup --system app && adduser --system --group app
# set work directory
WORKDIR /app
# environment variables
ENV PYTHONDONTWRITEBYTECODE=1 \
PYTHONUNBUFFERED=1 \
UV_LINK_MODE=copy \
UV_PYTHON_DOWNLOADS=never \
UV_PROJECT_ENVIRONMENT=$APP_HOME/.venv
# install uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
# install system dependencies
RUN apt-get update
RUN apt-get install -y --no-install-recommends \
build-essential netcat-traditional \
python-is-python3 python3-gdal python3-psycopg2
# switch to app user [THIS MAKES THE NEXT COMMAND FAIL]
# USER app
# synchronise project dependencies
COPY pyproject.toml uv.lock ./
RUN --mount=type=cache,target=/root/.cache \
uv sync --all-groups --frozen --no-install-project
# run entrypoint script
COPY ./entrypoint.sh .
RUN chmod +x entrypoint.sh
ENTRYPOINT ["/app/entrypoint.sh"]
docker-compose.yml:
services:
server:
build:
context: .
command: uv run manage.py runserver 0.0.0.0:8000
tty: true
environment:
DJANGO_SETTINGS_MODULE: config.settings
volumes:
- ./:/app/
ports:
- "8000:8000"
env_file:
- .env
entrypoint.sh:
#!/bin/sh
set -euo pipefail
cd /app
# ensure "app" user in the container has same ids as local user outside the container
if [ ! -z ${RUN_AS_UID} ]; then usermod --uid $RUN_AS_UID app; fi
if [ ! -z ${RUN_AS_GID} ]; then groupmod --gid $RUN_AS_GID app; fi
# setup django
uv run ./manage.py migrate
uv run ./manage.py collectstatic --no-input --link
# run whatever command was passed to the container (from docker-compose)
exec "$@"
.env:
RUN_AS_UID=1001
RUN_AS_GID=1001
Возможно, вам просто нужно указать владельца /app после того, как вы создадите его как , как указано в комментариях
RUN chown --recursive appuser:root /app
Часто бывает полезно перейти от минимального оттока зависимостей к максимальному, чтобы избежать перестроек, и увеличить привилегии до минимума (что вы в основном и делаете!)
- первые пакеты на уровне операционной системы (через apt и др.)
- создайте, а затем удалите привилегии
- установите пакеты пользовательского уровня
- небольшие локальные исправления, такие как chmod
У меня нет подходящей настройки, чтобы попробовать это прямо сейчас, но оптимизация и упрощение или удаление кэширования, а затем добавление его позже, может оказать огромную помощь
FROM python:3.12-slim-trixie
ENV # ...
# install/update apt dependencies and tidy
RUN # apt-get update && apt-get install ... && apt-get clean
# install uv
COPY --from=ghcr.io/astral-sh/uv:latest /uv /uvx /bin/
# drop to unprivileged user
RUN useradd --create-home appuser
RUN mkdir -p /app # has this already been created?
RUN chown --recursive appuser:root /app
WORKDIR /app
USER appuser
# copy user files (prefer whole local directory?)
COPY pyproject.toml ./ # uv lock just caching?
COPY entrypoint.sh ./
RUN chmod +x entrypoint.sh
# synchronize project dependencies
# configure caching once working!
RUN # uv sync ...
# run entrypoint script
ENTRYPOINT ["/app/entrypoint.sh"]
<время работы/>
Однако позже при создании файла compose у вас могут возникнуть проблемы, поскольку вы /app!
Что должно быть внутри каталога во время выполнения? Вероятно, venv и структура из вашего кода? Должен ли ваш код быть собран во время выполнения или его нечего собирать и он полностью интерпретирован?
Подумайте, что вы хотите сохранить или передать с помощью compose
- конфигурация? (скорее всего, это сделано с помощью переменных env)
- venv? (маловероятно, избегайте сбоев
.venvили установите в другом месте и вставьте символическую ссылку во время выполнения?) - пользовательские файлы? (вероятно, вы захотите сохранить его между запусками и очистить вручную, если это какой-то вложенный каталог, например
/app/tmpили/tmp/app?) - локальный (в пространстве хоста) встроенный или несозданный пакет? (зависит от варианта использования, например, при тестировании)
При тестировании на самом деле может быть удобно сохранять venv в пространстве хоста и поддерживать его и / или вносить постепенные изменения в свой пакет с заданными command: или ENTRYPOINT, но вам нужно быть осторожным количество разрешений