Docker中使用Apache HTTP服务器开发时如何解决文件权限问题?

How to solve file permission issues when developing with Apache HTTP server in Docker?

我的 Dockerfile 扩展自 php:8.1-apache。开发时发生以下情况:

这些文件安装在我作为 user (1000:1000) 的主机上。当然,我现在 运行 正在处理文件权限问题。我想 update/delete 在我主机上的容器中创建的文件,反之亦然。


我目前的解决方案是将图像的用户设置为 www-data。这样,所有创建的文件都属于它。然后,我将其用户和组 ID 从 33 更改为 1000。这解决了我的文件权限问题。

然而,这会导致另一个问题:
我在入口点和命令前加上 sudo -E。我这样做是因为它们通常 运行 以 root 身份运行,而我的自定义入口点需要 root 权限。 但是这样一来,停止信号就停止工作了,当我想让它停止时,容器必须被杀死:

~$ time docker-compose down
Stopping test_app ... done
Removing test_app ... done
Removing network test_default

real    0m10,645s
user    0m0,167s
sys     0m0,004s

这是我的 Dockerfile:

FROM php:8.1-apache AS base

FROM base AS dev
COPY entrypoint.dev.sh /usr/local/bin/custom-entrypoint.sh

ARG user_id=1000
ARG group_id=1000

RUN set -xe \
    # Create a home directory for www-data
    && mkdir --parents /home/www-data \
    && chown --recursive www-data:www-data /home/www-data \
    # Make www-data's user and group id match my host user's ones (1000 and 1000)
    && usermod --home /home/www-data --uid $user_id www-data \
    && groupmod --gid $group_id www-data \
    # Add sudo and let www-data execute it without asking for a password
    && apt-get update \
    && apt-get install --yes --no-install-recommends sudo \
    && rm --recursive --force /var/lib/apt/lists/* \
    && echo "www-data ALL=(ALL) NOPASSWD: ALL" > /etc/sudoers.d/www-data

USER www-data

# Run entrypoint and command as sudo, as my entrypoint does some config substitution and both normally run as root
ENTRYPOINT [ "sudo", "-E", "custom-entrypoint.sh" ]
CMD [ "sudo", "-E", "apache2-foreground" ]

这是我的习惯-entrypoint.sh

#!/bin/sh
set -e

sed --in-place 's@^RemoteIPTrustedProxy.*@RemoteIPTrustedProxy '"$REMOTEIP_TRUSTED_PROXY"'@' $APACHE_CONFDIR/conf-available/remoteip.conf

exec docker-php-entrypoint "$@"

我需要做什么才能让容器再次捕捉到停止信号(对于 Apache 服务器是 SIGWINCH)?或者有没有更好的方法来处理文件权限问题,所以我不需要 运行 入口点和命令 sudo -E?

您可以使用 user namespace 将您 docker 中的不同 user/group 映射到主机上的您。

例如,容器中的组www-data/33可以是主机上的组docker-www-data/100033,你只要在组中访问日志文件。

What do I need to do to make the container catch the stop signal (it is SIGWINCH for the Apache server) again?

首先,删除 sudo,如果您需要在您的容器中成为 root,运行 它作为 root 并在您的 Dockerfile 中 USER root。容器中的 sudo 几乎没有什么价值,因为它应该是 运行 一个应用程序的环境,而不是多用户通用 Linux 主机。

Or is there a better way to handle the file permission issues, so I don't need to run the entrypoint and command with sudo -E?

我采用的模式是让开发人员以 root 身份启动容器,让入口点检测已安装卷的 uid/gid,并调整容器中用户的 uid/gid在 运行ning gosu 之前匹配该 ID 以删除权限并 运行 作为该用户。我在我的 base image example (note the fix-perms script that tweaks the uid/gid). Another example of that pattern is in my jenkins-docker 图像中包含了很多这种逻辑。

您仍然需要将 root 的登录名 shell 配置为在容器内自动 运行 gosu,或者记住在执行时始终传递 -u www-data您的图像,但现在 uid/gid 将匹配您的主机。

这主要是为了开发。在生产中,您可能不需要主机卷,而是使用命名卷,或者至少硬编码图像中用户的 uid/gid 以匹配生产主机上所需的 ID。这意味着 Dockerfile 仍将具有 USER www-data,但开发人员的 docker-compose.yml 将具有 user: root,这在生产中的组合文件中不存在。您可以在我的 DockerCon 2019 talk (video here).

中找到更多相关信息