在 docker daemon 启用用户隔离的功能前,新创建的容器进程和宿主机上的进程在相同的 user namespace 中。也就是说 docker 并没有为容器创建新的 user namespace:
上图中的容器进程 sleep 和宿主机上的进程在相同的 user namespace 中(没有开启用户隔离功能的场景)。
在 docker daemon 启用用户隔离的功能后,让我们查看容器中进程的 user namespace:
上图中的 4404 就是我们刚启动的容器中 sleep 进程的 PID。可以看出,docker 为容器创建了新的 user namespace。在这个 user namespace 中,容器中的用户 root 就是天神,拥有至高无上的权力!
访问数据卷中的文件我们可以通过访问数据卷中的文件来证明容器中 root 用户究竟具有什么样的权限?创建四个文件,分别属于用户 root 、165536 和 nick。rootfile 只有 root 用户可以读写,用户 nick 具有 nickfile 的读写权限,uid 165536 具有文件 165536file 的读写权限,任何用户都可以读写 testfile 文件:
下面把这几个文件以数据卷的方式挂载到容器中,并检查从容器中访问它们的权限:
$ docker run -it --name test -w=/testv -v $(pwd)/testv:/testv ubuntu
容器中的 root 用户只能访问 165536file 和 testfile,说明这个用户在宿主机中只有非常有限的权限。
在容器中禁用 user namespace一旦为 docker daemon 设置了 "userns-remap" 参数,所有的容器默认都会启用用户隔离的功能(默认创建一个新的 user namespace)。有些情况下我们可能需要回到没有开启用户隔离的场景,这时可以通过 --userns=host 参数为单个的容器禁用用户隔离功能。--userns=host 参数主要给下面三个命令使用:
docker container create
docker container run
docker container exec
比如执行下的命令:
$ docker run -d --userns=host --name sleepme ubuntu sleep infinity
查看进程信息:
进程的有效用户又成 root 了,并且也没有为进程创建新的 user namespace:
已知问题
User namespace 属于比较高级的功能,目前 docker 对它的支持还算不上完美,下面是已知的几个和现有功能不兼容的问题:
共享主机的 PID 或 NET namespace(--pid=host or --network=host)
外部的存储、数据卷驱动可能不兼容、不支持 user namespace
使用 --privileged 而不指定 --userns=host
总结