Docker中使用Apache HTTP服务器开发时如何解决文件权限问题?
How to solve file permission issues when developing with Apache HTTP server in Docker?
我的 Dockerfile 扩展自 php:8.1-apache
。开发时发生以下情况:
- 应用程序创建日志文件(如
www-data
、33:33
)
- 我在容器中创建文件(作为图像的默认用户
root
、0:0
)
这些文件安装在我作为 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).
中找到更多相关信息
我的 Dockerfile 扩展自 php:8.1-apache
。开发时发生以下情况:
- 应用程序创建日志文件(如
www-data
、33:33
) - 我在容器中创建文件(作为图像的默认用户
root
、0:0
)
这些文件安装在我作为 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).