可以看到当前Bash进程和Dockerd进程的名称空间都一样,因为它们都是在同一个名称空间上运行的。另外需要说明的是uip_map的输出,第一个数字是在当前名称里的用户ID,第二个数字是该用户ID在当前名称空间外部被映射到哪个用户ID上,最后一个数字是映射范围。
然后我们启动一个包含两个容器的POD来看一下,如下图:
容器的User namespace和容器外的是一样的,也就是说没有单独为容器创建User namespace,而且容器内的用户ID是0,映射到容器外也是0,这就是意味着容器内的root用户和容器外的root用户拥有相同的权限。说白了就是容器中的进程是以root用户权限运行的,并且这个容器中的root用户和宿主机上的root用户是同一个,看下图,这2个容器进程就是以root运行的:
如果你需要验证,那么你把宿主机上的一个只能由root打开的文件挂载容器中,你看看能不能打开就知道了。
就算你进入容器查看这个sleep 3600其实也是root运行的,简单来说容器内UID为0的root用户就是容器外UID为0的root用户。为什么会是这样呢?在整个系统共享一个内核,而内核只管理一套uid和gid,并且对内核来说只识别uid不识别用户名,也就是说内核在做权限方面它通过uid来做,用户名只是对于用户来讲方便辨认。
不要误认为你在容器中创建一个用户,然后在宿主机也可以看到,因为/etc/password这个文件在不同的文件系统上,容器和宿主机的文件系统还是隔离的。
但有些时候也不要被用户名所迷惑,你应该检查UID,查看容器进程的uid_map中的信息。
让容器进程使用root账号显然不安全,因为它的root就是宿主机的root,所以通常我们会给dockerd进程建立单独的账号或者使用User Namespace。不过推荐使用User Namesapce,因为有些使用容器进程必须以root来运行,如果使用User Namespace的话,我们就可以把宿主机的一个普通用户映射到容器中的root用户,这样容器进程以为自己是root并且在它所在的名称空间内有各种权限,但是在宿主机上它还是普通用户。
如何开启User Namespace呢:
cat /boot/config-3.10.0-957.el7.x86_64 | grep _NS,先检查一下你的内核是否开启了User Namespace
检查一下是否有下面的文件,如果没有就手动建立:
你可以使用系统中有的用户然后添加到这里,最后在docker的启动参数中加入这个账号,也可以让dockerd自己来建立,如果让dockerd自己来完成,在dockerd的启动docker-daemon.json中加入下面的内容,default表示使用dockerd去建立账号,它使用的名字为dockermap,如果你使用自己的就替换dufault:
{ "userns-remap": "default", }在RHEL 7.5版本,上面的配置在dockerd启动的时候会报错"Can't create ID mappings: %!v(MISSING): No subuid ranges found for user "dockremap"",查询之后判断应该是系统BUG,可以看看Redhat官网的Bug说明Bug-1546870,它会在系统中建立dockremap账号然后使用usermod -v参数来设置dockermap用户的ID范围,但是在Centos 7.5版本上的usermod命里没有-v参数。这就意味着RHEL 7.5不支持动态添加subid。所以我们只能手动来做,不过据说其他发行版可以支持比如Ubantu或者Fedora。
向从属用户和组文件中添加范围(如果你使用dockremap账号,那么你无须手动建立,因为dockerd启动的时候就会建立,如果上面的配置是default):
echo "dockremap:10000:65536" > /etc/subuid echo "dockremap:10000:65536" > /etc/subgid一共三个字段:
第一个字段dockremap,这个一个宿主机上的用户名
第二个字段10000,表示子User Namespace中用户ID从哪里开始
第三个字段65536,表示子User Namespace中可以有多少个用户ID