访问docker中的主机目录时拒绝权限

 a13786812476 发布于 2023-01-08 17:03

简而言之:我正在尝试在Docker中安装主机目录,但是我无法从容器内访问它,即使访问权限看起来很好.

细节:

我在做

sudo docker run -i -v /data1/Downloads:/Downloads ubuntu bash

然后

ls -al

它给了我:

total 8892
drwxr-xr-x.  23 root root    4096 Jun 18 14:34 .
drwxr-xr-x.  23 root root    4096 Jun 18 14:34 ..
-rwxr-xr-x.   1 root root       0 Jun 18 14:34 .dockerenv
-rwx------.   1 root root 9014486 Jun 17 22:09 .dockerinit
drwxrwxr-x.  18 1000 1000   12288 Jun 16 11:40 Downloads
drwxr-xr-x.   2 root root    4096 Jan 29 18:10 bin
drwxr-xr-x.   2 root root    4096 Apr 19  2012 boot
drwxr-xr-x.   4 root root     340 Jun 18 14:34 dev
drwxr-xr-x.  56 root root    4096 Jun 18 14:34 etc
drwxr-xr-x.   2 root root    4096 Apr 19  2012 home

还有更多这样的线(我认为这是相关部分).

如果我做

cd /Downloads
ls

结果是

ls: cannot open directory .: Permission denied

主机是Fedora 20,Docker 1.0.0和go1.2.2.

出了什么问题?

7 个回答
  • 有关完整故事,请参阅有关Volumes和SELinux的Project Atomic博客文章.

    特别:

    由于Docker最终合并了一个将在docker-1.7中出现的补丁(我们一直在RHEL,CentOS和Fedora上的docker-1.6中运行补丁),最近这变得容易了.

    此补丁添加了对"z"和"Z"的支持,作为卷安装(-v)上的选项.

    例如:

    docker run -v /var/db:/var/db:z rhel7 /bin/sh
    

    将自动执行chcon -Rt svirt_sandbox_file_t /var/db 手册页中描述的内容.

    更好的是,你可以使用Z.

    docker run -v /var/db:/var/db:Z rhel7 /bin/sh
    

    这将使用容器将运行的确切MCS标签标记容器内的内容,基本上它chcon -Rt svirt_sandbox_file_t -l s0:c1,c2 /var/dbs0:c1,c2每个容器的不同位置运行.

    2023-01-08 17:05 回答
  • 这是一个selinux问题.

    你可以暂时发出

    su -c "setenforce 0"
    

    在主机上访问或者通过运行添加selinux规则

    chcon -Rt svirt_sandbox_file_t /path/to/volume
    

    2023-01-08 17:05 回答
  • 警告:此解决方案存在安全风险.

    尝试以特权运行容器:

    sudo docker run --privileged=true -i -v /data1/Downloads:/Downloads ubuntu bash
    

    另一个选项(我还没试过)是创建一个特权容器,然后在其中创建非特权容器.

    2023-01-08 17:05 回答
  • 通常,主机卷装入的权限问题是因为根据主机上文件的uid / gid权限,容器内的uid / gid无法访问该文件。但是,此特定情况不同。

    许可权字符串末尾的点drwxr-xr-x.表示已配置SELinux。与SELinux一起使用主机安装时,需要在卷定义的末尾传递一个额外的选项:

    z选项指示绑定安装内容在多个容器之间共享。

    Z选项指示绑定安装内容是私有的且未共享。

    您的volume mount命令将如下所示:

    sudo docker run -i -v /data1/Downloads:/Downloads:z ubuntu bash
    

    在以下网址查看有关使用SELinux进行主机安装的更多信息:https : //docs.docker.com/storage/#configure-the-selinux-label


    对于其他看到以其他用户身份运行容器的问题,您需要确保容器内用户的uid / gid有权访问主机上的文件。在生产服务器上,这通常是通过控制映像构建过程中的uid / gid来匹配具有访问文件权限的主机上的uid / gid来完成的(甚至更好的是,不要在生产环境中使用主机挂载)。

    主机挂载通常首选命名卷,因为命名卷将从映像目录初始化卷目录,包括所有文件所有权和权限。当卷为空并且使用命名卷创建容器时,会发生这种情况。

    MacOS用户现在拥有OSXFS,它可以在Mac主机和容器之间自动处理uid / gid。其中一个无济于事的地方是嵌入式VM内的文件已挂载到容器中,例如/var/lib/docker.sock。

    对于每个开发人员可能更改主机uid / gid的开发环境,我的首选解决方案是使用以root身份运行的入口点启动容器,将用户的uid / gid固定在容器内以匹配主机卷uid / gid,并然后用于gosu从根用户拖放到容器用户,以在容器内运行应用程序。重要的脚本fix-perms在我的基本图像脚本中,可以在以下位置找到:https : //github.com/sudo-bmitch/docker-base

    fix-perms脚本的重要部分是:

    # update the uid
    if [ -n "$opt_u" ]; then
      OLD_UID=$(getent passwd "${opt_u}" | cut -f3 -d:)
      NEW_UID=$(stat -c "%u" "$1")
      if [ "$OLD_UID" != "$NEW_UID" ]; then
        echo "Changing UID of $opt_u from $OLD_UID to $NEW_UID"
        usermod -u "$NEW_UID" -o "$opt_u"
        if [ -n "$opt_r" ]; then
          find / -xdev -user "$OLD_UID" -exec chown -h "$opt_u" {} \;
        fi
      fi
    fi
    

    这样会将用户的uid和文件的uid放入容器内,如果不匹配,则调用usermod以调整uid。最后,它会进行递归查找以修复所有未更改uid的文件。我比使用带有-u $(id -u):$(id -g)标志的容器更好,因为上面的入口点代码不需要每个开发人员都运行脚本来启动容器,并且用户拥有的卷之外的任何文件都将得到其权限更正。


    您还可以让docker通过使用执行绑定安装的命名卷从映像初始化主机目录。该目录必须预先存在,并且您需要提供主机目录的绝对路径,这与可能是相对路径的撰写文件中的主机卷不同。该目录也必须为空,以便docker对其进行初始化。定义绑定卷的命名卷的三个不同选项如下所示:

      # create the volume in advance
      $ docker volume create --driver local \
          --opt type=none \
          --opt device=/home/user/test \
          --opt o=bind \
          test_vol
    
      # create on the fly with --mount
      $ docker run -it --rm \
        --mount type=volume,dst=/container/path,volume-driver=local,volume-opt=type=none,volume-opt=o=bind,volume-opt=device=/home/user/test \
        foo
    
      # inside a docker-compose file
      ...
      volumes:
        bind-test:
          driver: local
          driver_opts:
            type: none
            o: bind
            device: /home/user/test
      ...
    

    最后,如果尝试使用用户名称空间,则会发现主机卷存在权限问题,因为容器的uid / gid已转移。在这种情况下,避免主机卷而仅使用命名卷可能是最容易的。

    2023-01-08 17:05 回答
  • 尝试docker volume create

    mkdir -p /data1/Downloads
    docker volume create --driver local --name hello --opt type=none --opt device=/data1/Downloads --opt o=uid=root,gid=root --opt o=bind
    docker run -i -v hello:/Downloads ubuntu bash
    

    看看文档https://docs.docker.com/engine/reference/commandline/volume_create/

    2023-01-08 17:05 回答
  • 我确认它chcon -Rt svirt_sandbox_file_t /path/to/volume 确实有效,您不必作为特权容器运行.

    这是:

    Docker版本0.11.1-dev,build 02d20af/0.11.1

    centos7作为启用了selinux的主机和容器.

    2023-01-08 17:05 回答
  • 来自access.redhat.com:Sharing_Data_Across_Containers:

    主机卷设置不可移植,因为它们与主机相关,可能无法在任何其他计算机上运行.因此,没有Dockerfile等效于将主机目录挂载到容器.另外,请注意主机系统不了解容器SELinux策略.因此,如果强制执行SELinux策略,则无论rw设置如何,装入的主机目录都不可写入容器.目前,您可以通过将正确的SELinux策略类型分配给主机目录来解决此问题:"

    chcon -Rt svirt_sandbox_file_t host_dir

    其中host_dir是安装到容器的主机系统上的目录的路径.

    它似乎只是一种解决方法,但我尝试了它的工作原理

    2023-01-08 17:07 回答
撰写答案
今天,你开发时遇到什么问题呢?
立即提问
热门标签
PHP1.CN | 中国最专业的PHP中文社区 | PNG素材下载 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有