这些实用程序从utmp文件 ( /var/run/utmp
)中获取有关当前登录的信息。您可以轻松地检查在普通情况下(例如在桌面系统上)该文件是否包含类似以下字符串(这qazer
是我的登录名,tty7
是我的桌面环境运行的 TTY):
$ cat /var/run/utmp
tty7:0qazer:0�o^�
而在容器中,这个文件(通常)是空的:
$ docker run -it centos
[root@5e91e9e1a28e /]# cat /var/run/utmp
[root@5e91e9e1a28e /]#
为什么?
该utmp
文件通常由验证用户并启动会话的程序修改:login(1)
, sshd(8)
, lightdm(1)
. 但是容器引擎不能依赖它们,因为它们在容器文件系统中可能不存在,所以“登录”和“代执行”以最原始、最直接的方式实现,避免依赖容器内部的任何东西.
当任何容器启动或在其中执行任何命令exec
时,容器引擎只是生成新进程,安排一些安全设置,调用setgid(2)
/setuid(2)
强制(无需任何身份验证)更改进程的 UID/GID,然后执行所需的二进制文件(入口点、命令等)。
比如说,我启动 CentOS 容器,代表 UID 运行它的主进程42
:
docker run -it --user 42 centos
然后尝试在sleep 1000
其中执行:
docker exec -it $CONTAINER_ID sleep 1000
容器引擎将执行如下操作:
[pid 10170] setgid(0) = 0
[pid 10170] setuid(42) = 0
...
[pid 10170] execve("/usr/bin/sleep", ["sleep", "1000"], 0xc000159740 /* 4 vars */) = 0
不会有对 的写入/var/run/utmp
,因此它将保持为空,并且who(1)
/w(1)
不会在容器内找到任何登录。