команды who и w в контейнере CentOS 8 Docker - PullRequest
3 голосов
/ 16 марта 2020

Во время игры с CentOs 8 на контейнере Docker я обнаружил, что выходные данные команд who и w всегда пусты.

[root@9e24376316f1 ~]# who
[root@9e24376316f1 ~]# w
 01:01:50 up  7:38,  0 users,  load average: 0.00, 0.04, 0.00
USER     TTY      FROM             LOGIN@   IDLE   JCPU   PCPU WHAT

Даже когда я вошел как другой пользователь во втором терминале. Когда я хочу write для этого пользователя, он показывает

[root@9e24376316f1 ~]# write test
write: test is not logged in

Это из-за Docker? Может быть, это работает таким образом, что не позволяет сеансам видеть друг друга? Или, может быть, это другая проблема. Буду очень признателен за некоторые объяснения.

1 Ответ

2 голосов
/ 17 марта 2020

Эти утилиты получают информацию о текущих входах в систему из файла 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 d, механизм контейнера just порождает новый процесс, организует некоторые настройки безопасности, вызывает 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) не найдет внутри себя никаких логинов контейнер.

...