避免docker挂载时产生root权限文件
在docker挂载磁盘的时候,由于很多容器内使用root运行程序,会导致挂载中产生的文件属于root:root。一般容器外用户并不是root,会让文件共享甚至阅读日志产生不必要的麻烦。本文旨在不更改容器的情况下,从根本上解决产生root权限文件的问题。
docker产生的文件经常需要sudo chmod o+rw *然后访问,虽然麻烦,但好歹有sudo的权限。没有sudo权限的时候就没那么走运了,这时候我发现了三种操作可以解决这个问题。
文章分为三部分,解释了挂载的原理、提供了三种解决原理、就方案进行演示。若仅希望获得推荐的解决方案,可以直接跳到方案演示的使用子用户一节。
文件挂载原理
简而言之,docker的文件挂载中,容器内外uid与gid相同。
最简单的挂载磁盘,例如:docker run -v $PWD:/data bash,就是将当前目录挂载到容器内的/data目录。文件的权限可以通过ls -l查看。
容器内可能有使用root用户和非root用户运行程序的两种情况。1)若容器内使用root运行程序,可以想象,产生的文件属于0:0,也就是root:root。容器外文件也会属于0:0,同样是root:root。这样产生的文件就需要容器外的root权限才可以操作。2)若容器内使用非root运行程序,例如blog:x:1000:1000::/home/blog:/bin/bash,产生的文件属于1000:1000。容器外文件也会属于1000:1000,而容器外uid为1000的用户可能是frank,这是若碰巧你就是frank,你就可以顺利读取这个文件。但若你是uid为1001的david,而且frank是个讨厌鬼,你就告别这个文件了。甚至容器外根本没有uid为1000的用户,那这个文件就不属于任何人。
三种解决原理
限定开启用户
仅部分容器可以使用该方案,且难以判断是否可行。对于这些容易配置权限的容器,这个问题很容易解决,强制容器的运行用户docker run -u blog bash即可。
我们这么定义容易配置权限的容器。
容器内所有用户都可以访问容器内所有需要访问、运行的资源
容器运行时由运行用户生成所有文件
- 由运行用户访问挂载磁盘内需要访问、运行的资源
满足这些要求,会让配置一个稍复杂容器的工作变得复杂许多甚至不可完成。如果你创建过容器,那你一定可以想象。第一点起码可以通过批量更改所有文件的o属性完成。第二点和第三点,容器运行的程序若需要绑定保留端口,就需要特别的各种设置;容器运行的程序若简单的要求需要管理员权限,我们不可能为了创建符合要求的docker更改甚至反编译程序。
而我们大部分时间使用到的容器都是他人配置好的,我们无法判断他人配置的容器是否属于容易配置权限的容器。这种容器若强制容器的运行用户除了无法保证产生文件的权限,还可能让容器意外崩溃。但说不准,bug就莫名奇妙消失了?
使用子用户
若容器内外文件的uid:gid可以不同,这个问题就可以很容易解决。的确有这么一个方案,让容器内所有的uid:gid以一定的规则映射,我推荐使用这一方案。文章的方案演示节中我会演示这一方案。
在官方文档中,这个方案本身是为了解决安全问题,见这里。发生容器挂载磁盘root权限提权也不是一次两次了,这算是一个官方的解决方案。
但这个方案会有一些限制:
- 不可使用
--pid=host或--network=host - 不可使用无法识别或使用用户映射的挂载磁盘
- 若使用
docker run --privileged则必须同时使用--userns=host
都是不大的限制,使用的时候留个心眼即可。
osxfs
有趣的是,OSX中不存在这一问题。
在和朋友讨论的时候,朋友们纷纷反映没有这个问题,不禁让我感叹贫穷限制了我的想象力。如果你使用的是OSX或者和我一样从朋友那里抢来了一台OSX,你可以尝试如下命令:
1 | mkdir data |
尽管OSX版本的docker有各种问题,但起码没有这个问题。这一切要归功于osxfs,官方文档中有一个基本的介绍。
其中Ownership一段提到了解决方案,容器内root映射到容器外运行docker的用户,容器内更改文件所有人的记录保存在com.docker.owner中。具体细节还有一些别的,TL;DR。
Initially, any containerized process that requests ownership metadata of an object is told that its
uidandgidown the object. When any containerized process changes the ownership of a shared file system object, such as by using thechowncommand, the new ownership information is persisted in thecom.docker.ownerextended attribute of the object. Subsequent requests for ownership metadata return the previously set values. Ownership-based permissions are only enforced at the macOS file system level with all accessing processes behaving...
剩余内容已隐藏