Docker-compose设置挂载卷的用户和组。

186

我正在尝试将一个卷挂载到docker-compose中的apache镜像上。问题是,我的docker中的apache是在www-data:www-data下运行的,但挂载的目录是在root:root下创建的。怎样指定挂载目录的用户?

我尝试了运行命令setupApacheRights.shchown -R www-data:www-data /var/www,但它显示chown: changing ownership of '/var/www/somefile': Permission denied

services:
    httpd:
        image: apache-image
        ports:
            - "80:80"
        volumes:
            - "./:/var/www/app"
        links:
            - redis
        command: /setupApacheRights.sh

我希望能指定挂载用户,这可行吗?


https://blog.giovannidemizio.eu/2021/05/24/how-to-set-user-and-group-in-docker-compose/ - Eugen Konkov
请参考这里的好资料:https://jtreminio.com/blog/running-docker-containers-as-current-host-user/ - undefined
6个回答

93
为了在不改变宿主系统的拥有者/权限的情况下实现所需的行为,请按照以下步骤进行操作:
  1. 在您的宿主系统上执行id命令,获取所需用户和/或组的ID。此命令将显示当前用户的UID和GID以及用户所在的所有组的所有ID。

  2.  $ id
    
  3. 将定义添加到您的docker-compose.yml文件中

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

    那么您的文件可能看起来像这样

     php: # this is my service name
         user: "${UID}:${GID}" # we added this line to get a specific user / group id
         image: php:7.3-fpm-alpine # this is my image
     # and so on
    
  5. 设置您的.env文件中的值

  6.  UID=1000
     GID=1001
    

3a. 或者你可以通过以下方式扩展你的~/.bashrc文件:

    export UID GID

为了全局定义而不是在每个项目的.env文件中定义它。

如果这对你不起作用(比如在我的当前发行版上,GID没有被设置),请使用以下两行:

    export UID=$(id -u)
    export GID=$(id -g)

感谢 @SteenSchütt 提供的全局定义UID / GID的简单解决方案。

现在,在容器中,您的用户的ID为1000,组为1001,并且您可以为每个环境设置不同的值。

注意: 请使用您在主机系统上找到的用户/组ID替换我使用的ID。由于我无法知道您的系统使用哪些ID,因此我提供了一些示例组和用户ID。

如果您不使用docker-compose或想要了解更多实现此目的的不同方法,请阅读我的信息来源:https://dev.to/acro5piano/specifying-user-and-group-in-docker-i2e

如果您的卷挂载文件夹在计算机上不存在,Docker会创建它(使用root用户),因此请确保它已经存在并且由您想要使用的用户ID/组ID拥有所有权。

我添加了一个dokuwiki容器的示例以更好地解释它:

version: '3.5'
services:
  dokuwiki:
    user: "${UID}" # set a specific user id so the container can write in the data dir
    image: bitnami/dokuwiki:latest
    ports:
      - '8080:8080'
    volumes:
      - '/home/manuel/docker/dokuwiki/data:/bitnami/dokuwiki/'
    restart: unless-stopped
    expose:
      - "8080"

如果dokuwiki容器没有对主机目录/home/manuel/docker/dokuwiki/data的写访问权限,它将无法正确初始化。

如果在启动时该目录不存在,Docker将为我们创建它,但它将具有root:root作为用户和组。因此,容器启动将失败。

如果在启动容器之前我们创建了这个文件夹

mkdir -P /home/manuel/docker/dokuwiki/data

然后检查一下

ls -nla /home/manuel/docker/dokuwiki/data| grep ' \.$'

检查文件夹的uid和gid,并确保它们与我们在步骤3中放入.env文件中的相匹配。


4
在我的情况下,容器无法发现它的名称,因为www-data用户具有gid和uid 33,这给我带来了其他问题。 - k0pernikus
1
对我不起作用(版本3.7)。我不得不在我的主机上创建一个新的1000组,并将我的用户添加到1000组中。 - bpile
1
我发现只需将 export UID GID 添加到我的 .bashrc 中,而不是为每个项目在 .env 文件中定义它,这样会更简单。 - Steen Schütt
1
@k0pernikus,有一个名为libnss-unknown的软件包(Debian和Ubuntu都有),您可以在容器中安装它,然后任何不在容器内的/etc/passwd中的用户都将获得一个根据环境设置的合成pwent主目录。这使得在具有任意用户ID的容器中使用getpwent的应用程序能够正常工作。 - Jan Hudec
1
进一步扩展我之前的建议,导出GID - 有些发行版可能没有定义该变量,但可能使用另一个名称,例如GROUP,在这种情况下,您可以在bashrc或等效文件中执行export UID GID="$GROUP" :) - Steen Schütt
显示剩余11条评论

57

坏消息是,volume 没有所有者/组/权限设置。好消息是,以下技巧将让您将其嵌入到配置中,因此完全自动化。

在 Dockerfile 中,在正确的位置创建一个空目录并进行所需设置。

这样,当 docker-compose 挂载到该位置时,该目录已经存在。当服务器在启动时(基于 docker-compose),挂载操作会高兴地保持那些权限不变。

Dockerfile:

# setup folder before switching to user
RUN mkdir /volume_data
RUN chown postgres:postgres /volume_data
VOLUME /volume_data
USER postgres

docker-compose.yml

volumes:
   - /home/me/postgres_data:/volume_data

来源


4
错误:chown: /volume_data: No such file or directory. 对我不起作用。我认为这是因为docker文件在进行chown之前声明了卷。参考:https://dev59.com/b18e5IYBdhLWcg3wEG7A - Timofey Drozhzhin
如果之前的mkdir顺利运行,那么这是非常奇怪的情况。我会尝试添加一个短暂的睡眠命令和一个测试命令来验证目录是否存在,但在这里都不应该是必要的。 - mahemoff
59
无法运行,挂载点上的UID/GID会被主机权限覆盖。 - DuBistKomisch
1
@RohanWarwar 你所说的声明卷是什么意思?它会创建volume_data文件夹,然后设置其权限。 - mahemoff
4
对我来说效果非常好。 - Maxim Schmidt
显示剩余7条评论

38

首先确定www-data用户的uid:

$ docker exec DOCKER_CONTAINER_ID id
uid=100(www-data) gid=101(www-data) groups=101(www-data)

然后,在您的Docker主机上,使用uid(本示例中为100)更改已挂载目录的所有者:

chown -R 100 ./

动态扩展

如果你正在使用docker-compose,你可以像这样进行操作:

$ docker-compose exec SERVICE_NAME id
uid=100(www-data) gid=101(www-data) groups=101(www-data)
$ chown -R 100 ./

你可以将它放在一行中:

$ chown -R $(docker-compose exec SERVICE_NAME id -u) ./

-u 标志仅将 uid 打印到标准输出(stdout)。

编辑:修复了CLI标志的大小写错误。感谢 @jcalfee314!


25
谢谢您的回复。但这并不是非常灵活的解决方案。我认为设置这个的主要目标应该是不需要进一步的定制。然而,没有其他方法来解决它,或者至少我找不到。我会尝试构建Apache,以便它可以在根用户下运行,这也可能有效。 - simPod
@simPod,请审核我的答案。此外,请调整你的问题。 - Arne L.
我之前试图使用www-data的uid挂载音量时,感到非常疯狂,结果却非常简单...太棒了! - Francesco Marchetti-Stasi
7
@ArneL。我可能过于严厉了,但问题确实存在。 Docker-compose文件的想法是多个开发人员可以获取一些代码,并且只要安装了Docker,就可以“运行”。 一旦您使用特定于主机的内容(在本例中为主机用户ID),它就会失败。 给出的建议可能适用于Linux,但下一个使用Windows或Mac的人可能就运气不佳了。 Bind挂载有其用处,但对于这个特定的问题,我认为人们使用标准Docker卷会更容易解决。 - MikeyT
你是不是想说 chown -Rchown: invalid option -- 'r' - jcalfee314
显示剩余4条评论

12

将“rw”添加到卷挂载的末尾对我有效:

services:
    httpd:
        image: apache-image
        ports:
            - "80:80"
        volumes:
            - "./:/var/www/app:rw"
        links:
            - redis
        command: /setupApacheRights.sh

嗨John,这在我的环境中不起作用。你有没有一个包括Dockerfile和完整的docker-compose.yml文件的示例?谢谢! - Manfred
我认为它实际上是一个非常特定的Docker容器 - 我正在使用Docker4Drupal镜像,因此我没有Dockerfile - 这是我对compose文件所做的更改。 - John
6
你是否以非root用户身份运行该服务? - Jaykul
非常感谢,我的问题已经通过使用这个得到了解决。 - Ageng D. Prastyawan
非常好的答案。这解决了我所有的问题。 - Devin Norgarb
简单而优雅,我不必要去破解这个和那个。谢谢。 - Aman

5

为此Compose服务设置用户www-data

    user: "www-data:www-data"

例子:

 wordpress:
    depends_on:
      - db
    image: wordpress:5.5.3-fpm-alpine
    user: "www-data:www-data"
    container_name: wordpress
    restart: unless-stopped
    env_file: 
      - .env
    volumes:
      - ./wordpress/wp-content:/var/www/html/wp-content
      - ./wordpress/wp-config-local.php:/var/www/html/wp-config.php

1
没有起作用,容器一直在重新启动。 - user2573099
@user2573099 如果您的容器一直重新启动,那么很可能是由于某些权限问题导致的,这可能表明您的镜像存在一些问题。 - Jiří

2
如果您的卷存在所有权问题,则需要通过下列方式查找您的卷挂载路径:
cmd: docker volume ls

接下来,识别您的卷名称,然后检查挂载路径。

cmd: docker volume inspect <volume name>

请检查您的挂载点并在Docker主机上挂载该挂载点。

此外,还需要检查卷的所有权:

cmd: ls -l

如果建议使用root:root,则在此处更改所有权为您的Docker用户。
cmd: chown docker_user_id:docker_group_id -R volume_path

注意:您可以进入Docker Bash并输入“id”命令来查找您的Docker用户ID和用户组ID。
cmd: docker-compose run --rm <container_name> bash
cmd: id
output: uid=102(www-data) gid=102(www-data) groups=102(www-data)

在这里找到相似的线程。https://www.hamaraweb.com/sms/407/docker-volume-ownership-issue-errno-13-permission-denied-bgb6ld/


这并没有回答问题,你在解释一种替代方案。 - reinierpost

网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接