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

Posted

技术标签:

【中文标题】在 Docker 中使用 Apache HTTP 服务器开发时如何解决文件权限问题?【英文标题】:How to solve file permission issues when developing with Apache HTTP server in Docker? 【发布时间】:2022-01-16 20:47:49 【问题描述】:

我的 Dockerfile 扩展自 php:8.1-apache。开发过程中会发生以下情况:

应用程序创建日志文件(如www-data33:33) 我在容器中创建文件(作为图像的默认用户root0:0

这些文件安装在我作为user (1000:1000) 的主机上。当然,我现在遇到了文件权限问题。我想更新/删除在我主机上的容器中创建的文件,反之亦然。


我目前的解决方案是将图像的用户设置为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" ]

这是我的 custom-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运行入口点和命令?

【问题讨论】:

你在 Docker 中根本不需要sudo;甚至不要安装它。如果您希望主容器进程以 root 身份运行,请在末尾指定 USER root 而不是其他用户。 root 是默认用户,所以 USER root 甚至都不是必需的。但是当我进入容器(docker-compose exec app bash)并创建一个文件(touch test)时,该文件属于root,我无法在主机上修改/删除它。 您可以直接在主机上编辑文件,而无需在容器内间接获取调试外壳。或者您可以docker-compose exec -u 替代用户。 我在容器中创建文件的实际方法是使用 Laravel 的 make 命令:php artisan make:model User。这将创建一个带有蓝图的新类文件。我无法在主机上运行该命令,因为没有安装 PHP。如果我使用 docker-compose exec -u www-data 而不是我当前的解决方案,www-data 的用户和组 id 仍然是 33,因此我的主机用户的权限仍然不匹配。此外,我一定不要忘记每次都输入-u www-data 【参考方案1】:

我需要做什么才能让容器再次捕捉到停止信号(对于 Apache 服务器是 SIGWINCH)?

首先,去掉sudo,如果你需要在你的容器中以root身份运行它,在你的Dockerfile中使用USER root以root身份运行它。容器中的sudo 几乎没有什么价值,因为它应该是一个运行一个应用程序的环境,而不是一个多用户通用 Linux 主机。

或者有没有更好的方法来处理文件权限问题,所以我不需要使用 sudo -E 运行入口点和命令?

我采用的模式是让开发人员以 root 身份启动容器,并让入口点检测已安装卷的 uid/gid,并在运行前调整容器中用户的 uid/gid 以匹配该 id gosu 删除权限并以该用户身份运行。我在base image example 中包含了很多这种逻辑(注意调整uid/gid 的fix-perms script)。该模式的另一个例子是我的jenkins-docker 图像。

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

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

【讨论】:

谢谢,我看了你的演讲并阅读了一些关于gosu 的帖子(其中一些是你写的)并拉入了你的修复烫发脚本!我剩下两个问题:1.) Composer/Maven 等工具在用户的主目录中创建缓存。所以我仍然需要创建/home/www-data 并把它交给www-data,对吧?或者你怎么处理这个? 2.) 在运行docker-compose exec app bash 时,我找不到将root 的登录shell 配置为www-data 的方法。你有什么提示吗? @user10517872 1 - 是的,您需要容器中的主目录,当 fix-perms 修改容器 /etc/passwd 中的 uid 时,它还会调整该 uid 拥有的文件。 2 - 这应该可以通过容器中的 /root/.bashrc 中的条目来执行类似exec gosu www-data bash 的操作。我会检查文件中通常存在的“交互式”检查,并在检查后添加您的命令。 1.) /var/wwwwww-data 的默认主页,但归 root 所有。我正在将我的文件挂载到/var/www/html。一个简单的chown就解决了问题,我不用在/home/www-data下新建一个家了! 2.)我一直试图将其添加到/root/.profile!谢谢!【参考方案2】:

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

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

【讨论】:

谢谢!似乎需要进行很多配置才能开始使用它。当同事需要对我的项目进行更改时,他不太可能阅读文档并设置重新映射。不过我一定会试试的!

以上是关于在 Docker 中使用 Apache HTTP 服务器开发时如何解决文件权限问题?的主要内容,如果未能解决你的问题,请参考以下文章

利用Ansible部署运行Apache(http)的Docker容器

在apache或aws上使用docker部署反应构建

docker化 springboot项目

Docker-compose apache guacamole 卡住了

Yum安装mesos+zookeeper+marathon管理docker集群

Docker容器无法读取http链接 - 驼峰