在 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.
您可以尝试两种解决方案:
- 更改主机目录(容器外)中的文件,使其具有与 'appuser' 容器内相同的 uid。
- 或者您可以在创建时指定 'appuser' 的 uid(在映像构建期间)。在这种情况下,请指定 'appuser' 与 Linux 主机上的用户具有相同的 UID。 Linux 用户是否有不同的名字并不重要;如果uid号相同,那么你就有权限了。
编辑:包括评论。 OP 最终在 docker-compose.yml 中通过添加解决了这个问题:
user: "${UID}:${GID}"
这会将服务的 user/group 设置为用户调用 docker-compose
的环境中的 UID 和 GID。即假设shell设置了UID和GID环境变量;并非所有 shell 或操作系统都以完全相同的方式运行。
我正在尝试使用 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.
您可以尝试两种解决方案:
- 更改主机目录(容器外)中的文件,使其具有与 'appuser' 容器内相同的 uid。
- 或者您可以在创建时指定 'appuser' 的 uid(在映像构建期间)。在这种情况下,请指定 'appuser' 与 Linux 主机上的用户具有相同的 UID。 Linux 用户是否有不同的名字并不重要;如果uid号相同,那么你就有权限了。
编辑:包括评论。 OP 最终在 docker-compose.yml 中通过添加解决了这个问题:
user: "${UID}:${GID}"
这会将服务的 user/group 设置为用户调用 docker-compose
的环境中的 UID 和 GID。即假设shell设置了UID和GID环境变量;并非所有 shell 或操作系统都以完全相同的方式运行。