在 Dockerfile 中设置 USER 会阻止在 Django 中保存文件字段(例如 ImageField)

Setting USER in Dockerfile prevents saving file fields (eg. ImageField) in Django

我正在尝试使用 Dockerfile 和 docker-compose.yml 将 Django 容器化,如下定义。我将 Dockerfile 构建为 (fiifidev/postgres:test) 用于撰写文件。一切正常。但是,每当我尝试使用文件字段(例如 ImageField 或 FileField)保存模型时,我都会收到权限错误 PermissionError: [Errno 13] Permission denied docker.

我怀疑我没有在 Dockerfile 中添加适当的 用户创建 (useradd) 权限(不确定)。但是当我删除 USER 时一切正常。

我该如何解决这个问题,我们将不胜感激。

FROM python:3.10-slim-bullseye as base

# Setup env
ENV LANG C.UTF-8
ENV LC_ALL C.UTF-8
ENV PYTHONDONTWRITEBYTECODE 1
ENV PYTHONFAULTHANDLER 1


FROM base AS python-deps

# Install pipenv and compilation dependencies
RUN pip install pipenv
RUN apt-get update && apt-get install -y --no-install-recommends gcc

# Install python dependencies in /.venv
COPY Pipfile .
COPY Pipfile.lock .
RUN PIPENV_VENV_IN_PROJECT=1 pipenv install --deploy


FROM base AS runtime

# Copy virtual env from python-deps stage
COPY --from=python-deps /.venv /.venv
ENV PATH="/.venv/bin:$PATH"

# Create and switch to a new user
RUN useradd --create-home appuser

WORKDIR /home/appuser/src
USER appuser

# Install application into container
COPY --chown=appuser:appuser . .
version: "3.9"

services:
  web:
    image: fiifidev/postgres:test
    command: sh -c "python manage.py makemigrations &&
      python manage.py migrate &&
      python manage.py initiate_admin &&
      python manage.py runserver  0.0.0.0:8000"
    volumes:
      - .:/home/appuser/src
    networks:
      postgres-network:
    env_file:
      - .env
    ports:
      - ${APP_PORT}:8000
    restart: "on-failure"



networks:
  postgres-network:
    external: true

来自Docker文件:

WORKDIR /home/appuser/src
USER appuser

# Install application into container
COPY --chown=appuser:appuser . .

在这里您要创建一个 src 目录并将您的代码复制到其中。这被烘焙到生成的图像中。

来自 docker-compose.yml:

    volumes:
      - .:/home/appuser/src

此处您将主机上的当前目录挂载在 src 目录之上。安装将优先于图像对目录包含内容的想法,因此这实际上意味着您的 COPY 和 chown 无效。 (那些文件仍然存在于您的图像中,但挂载隐藏了它们;它们不可用。)

这里的权限行为因平台而异。在Windows,我不知道会发生什么。在 Mac 上使用 Docker Desktop 它将“正常工作”,因为 Docker Desktop 在这种情况下或多或少地忽略了权限并使一切都愉快。

但是,在 Linux 上,容器内和容器外的文件所有权必须匹配,您才能写入。可能发生的情况是,挂载目录中的文件所拥有的 uid(您的)与容器中的 'appuser' 不同。因此,您会收到权限错误,因为您无权写入 files/directory.

您可以尝试两种解决方案:

  1. 更改主机目录(容器外)中的文件,使其具有与 'appuser' 容器内相同的 uid。
  2. 或者您可以在创建时指定 'appuser' 的 uid(在映像构建期间)。在这种情况下,请指定 'appuser' 与 Linux 主机上的用户具有相同的 UID。 Linux 用户是否有不同的名字并不重要;如果uid号相同,那么你就有权限了。

编辑:包括评论。 OP 最终在 docker-compose.yml 中通过添加解决了这个问题:

user: "${UID}:${GID}"

这会将服务的 user/group 设置为用户调用 docker-compose 的环境中的 UID 和 GID。即假设shell设置了UID和GID环境变量;并非所有 shell 或操作系统都以完全相同的方式运行。