【问题标题】:Why does docker container prompt "Permission denied"?为什么docker容器提示“Permission denied”?
【发布时间】:2016-06-07 16:09:19
【问题描述】:

我使用以下命令运行一个 docker 容器,并将一个目录从主机(/root/database)映射到容器(/tmp/install/database):

# docker run -it --name oracle_install -v /root/database:/tmp/install/database bofm/oracle12c:preinstall bash

但是在容器中,我发现我无法使用ls 列出/tmp/install/database/ 中的内容,尽管我是root 并且拥有所有权限:

[root@77eb235aceac /]# cd /tmp/install/database/
[root@77eb235aceac database]# ls
ls: cannot open directory .: Permission denied
[root@77eb235aceac database]# id
uid=0(root) gid=0(root) groups=0(root)
[root@77eb235aceac database]# cd ..
[root@77eb235aceac install]# ls -alt
......
drwxr-xr-x. 7 root root  4096 Jul  7  2014 database

我在主机中查看/root/database,一切似乎都正常:

[root@localhost ~]# ls -lt
......
drwxr-xr-x.  7 root root       4096 Jul  7  2014 database

为什么docker容器提示“Permission denied”?

更新
根本原因与SELinux 有关。其实我去年也遇到过类似的issue

【问题讨论】:

  • 可以尝试将--privileged 添加到docker run 命令并告诉我们权限是否仍然被拒绝。另外,你能(在主机上)表演# ls -lh /tmp/install/database吗?
  • @Auzias:是的,添加--privileged 有效!谢谢!您能否写一个答案并解释在容器中以 root 用户身份工作时使用此选项有什么区别?
  • @Auzias:我在OP更新,请查收,谢谢!
  • 还没有,因为我不确定原因。你能表演(在主机上)# ls -lh /tmp/install/database吗? (您提供了 ls -ldh /root/database 没有 /tmp 之一)。另外,您是在特定设备上@9​​87654339@ 吗?
  • @Auzias:主机上没有/tmp/install/database,它在容器中。

标签: linux docker permissions permission-denied user-permissions


【解决方案1】:

在容器内拒绝共享目录的权限可能是因为此共享目录存储在设备上。默认情况下,容器不能访问任何设备。添加选项$docker run --privileged 允许容器访问所有设备并执行内核调用。 这不被认为是安全的。

更简洁的共享设备方法是使用选项docker run --device=/dev/sdb(如果/dev/sdb 是您要共享的设备)。

来自手册页:

  --device=[]
      Add a host device to the container (e.g. --device=/dev/sdc:/dev/xvdc:rwm)

  --privileged=true|false
      Give extended privileges to this container. The default is false.

      By default, Docker containers are “unprivileged” (=false) and cannot, for example, run a Docker daemon inside the Docker container. This is because by default  a  container is not allowed to access any devices. A “privileged” container is given access to all devices.

      When  the  operator  executes  docker run --privileged, Docker will enable access to all devices on the host as well as set some configuration in AppArmor to allow the container nearly all the same access to the host as processes running outside of a container on the host.

【讨论】:

【解决方案2】:

在使用 docker-compose 将 nfs 挂载点共享为卷时,我遇到了类似的问题。我能够通过以下方式解决问题:

    docker-compose up --force-recreate

即使您发现了问题,这也可能对其他人有所帮助。

【讨论】:

    【解决方案3】:

    我从以下评论中得到答案:Why does docker container prompt Permission denied?

    man docker-run 给出正确答案:

    像 SELinux 这样的标签系统要求在安装到容器中的卷内容上放置适当的标签。如果没有标签,安全系统可能会阻止进程运行 在容器内使用内容。默认情况下,Docker 不会更改操作系统设置的标签。

    要更改容器上下文中的标签,您可以将两个后缀 :z 或 :Z 添加到卷挂载中。这些后缀告诉 Docker 重新标记共享卷上的文件对象。 z 选项告诉 Docker 两个容器共享卷内容。因此,Docker 使用共享内容标签来标记内容。共享卷标允许所有容器 读/写内容。 Z 选项告诉 Docker 使用私有非共享标签标记内容。只有当前容器可以使用私有卷。

    例如:

      docker run -it --name oracle_install -v /root/database:/tmp/install/database:z ...
    

    【讨论】:

    • 如果“默认情况下,Docker不会更改操作系统设置的标签”,那我怎么能在主机上运行某个可执行文件,但是将相同的可执行文件挂载到Docker容器,运行时出现“权限被拒绝”? (并指定:z 确实修复它。)
    • @sschuberth selinux 要求进程标签与它尝试访问的文件的标签匹配。 Docker 在与主机进程不同的上下文中运行,因此它具有不同的进程标签。这就是为什么主机中的进程可以访问可执行文件,但 docker 容器中的进程不能。 :z 会重新标记文件以确保 docker 容器也可以访问该文件。
    【解决方案4】:

    另一个原因是与 UID/GID 不匹配。这通常显示为能够以 root 身份而不是以容器用户身份修改挂载

    您可以设置 UID,因此对于作为 ubuntu 运行的 ubuntu 容器,您可能需要附加 :uid=1000(与 id -u 核对)或根据您的用例在本地设置 UID。

    uid=value 和 gid=value

    设置文件系统中文件的属主和所属组(默认:uid=gid=0)

    这个 tmpfs 示例在这里有一个很好的博客

    docker run \
           --rm \
           --read-only \
           --tmpfs=/var/run/prosody:uid=100 \
           -it learning/tmpfs
    

    http://www.dendeer.com/post/docker-tmpfs/

    【讨论】:

      猜你喜欢
      • 2015-07-17
      • 1970-01-01
      • 2013-06-07
      • 1970-01-01
      • 1970-01-01
      • 2023-03-22
      • 1970-01-01
      • 2015-11-21
      相关资源
      最近更新 更多