Изменение владельца файла .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, но вам нужно быть осторожным количество разрешений

Вернуться на верх