Невозможно добавить нового пользователя в Docker-контейнер с подключенными /etc/passwd и /etc/shadow
Пример проблемы:
docker run -ti -v my_passwd:/etc/passwd -v my_shadow:/etc/shadow --rm centos
[root@681a5489f3b0 /]# useradd test # does not work !?
useradd: failure while writing changes to /etc/passwd
[root@681a5489f3b0 /]# ll /etc/passwd /etc/shadow # permission check
-rw-r--r-- 1 root root 157 Oct 8 10:17 /etc/passwd
-rw-r----- 1 root root 100 Oct 7 18:02 /etc/shadow
Аналогичная проблема возникает при использовании passwd:
[root@681a5489f3b0 /]# passwd test
Changing password for user test.
New password:
BAD PASSWORD: The password is shorter than 8 characters
Retype new password:
passwd: Authentication token manipulation error
Я попытался использовать образ Ubuntu, но возникает та же проблема.
Я могу вручную редактировать файл passwd и теневой файл из контейнера.
Я получаю ту же проблему на следующих двух машинах:
ОС хоста: CentOS 7 - SELinux отключен
Версия Docker: 1.8.2, сборка 0a8c2e3
Хост ОС: CoreOS 766.4.0
Версия докера: 1.7.1, сборка df2f73d-dirty
Я также открыл вопрос на GitHub: https://github.com/docker/docker/issues/16857
2 ответа
Это терпит неудачу, потому что passwd
манипулирует временным файлом, а затем пытается переименовать его в /etc/shadow
, Это не удается, потому что /etc/shadow
является точкой монтирования, которую нельзя заменить, что приводит к этой ошибке strace
):
102 rename("/etc/nshadow", "/etc/shadow") = -1 EBUSY (Device or resource busy)
Вы можете воспроизвести это тривиально из командной строки:
# cd /etc
# touch foo
# mv foo shadow
mv: cannot move 'foo' to 'shadow': Device or resource busy
Вы можете обойти это, подключив каталог, содержащий my_shadow
а также my_passwd
где-то еще, а затем символические ссылки /etc/passwd
а также /etc/shadow
в контейнере соответственно:
$ docker run -it --rm -v $PWD/my_etc:/my_etc centos
[root@afbc739f588c /]# ln -sf /my_etc/my_passwd /etc/passwd
[root@afbc739f588c /]# ln -sf /my_etc/my_shadow /etc/shadow
[root@afbc739f588c /]# ls -l /etc/{shadow,passwd}
lrwxrwxrwx. 1 root root 17 Oct 8 17:48 /etc/passwd -> /my_etc/my_passwd
lrwxrwxrwx. 1 root root 17 Oct 8 17:48 /etc/shadow -> /my_etc/my_shadow
[root@afbc739f588c /]# passwd root
Changing password for user root.
New password:
Retype new password:
passwd: all authentication tokens updated successfully.
[root@afbc739f588c /]#
Я столкнулся с этой проблемой сегодня. Перепробовав практически все, я пришел к печальному выводу, что не существует хорошего способа сделатьpasswd
,useradd
,groupadd
и т.д. все устраивает без монтирования всего каталога. Единственным преимуществом является то, что он, вероятно, не займет слишком много места, если вы используете свернутую базу (например, alpine, bitnami/minideb).
Ниже приведена таблица того, что я пробовал, и почему каждый из них потерпел неудачу:
В конце концов мне просто пришлось вздохнуть, взять L и смонтировать весь каталог. Честно говоря, я рекомендую вам сделать то же самое — это не стоит ни моего времени, ни вашего.
Если вы делаете это, вы, вероятно, захотите скопировать содержимое образа на свой хост перед первым запуском контейнера, иначе у вас будет просто пустое монтирование. Для этого вы можете использовать этот трюк .
Если вы используетеdocker-compose
илиpodman-compose
вы можете использовать подстановку переменных , чтобы временно смонтировать пустой каталог хоста в/tmp/etc
(или где-нибудь еще, если уж на то пошло), чтобы это не затмило настоящую/etc
когда вы выполняете копирование:
services:
my-service:
container_name: my-container
volumes:
- /dir/on/host:${DIVERT_DIR}/etc
# I'm using podman but it's the same thing with docker
# create temporary container without shadowing /etc
DIVERT_DIR=/tmp podman-compose up --no-start
# copy /etc to host
podman cp my-container:/etc /dir/on/host
# tear down temporary container
podman rm my-container
# create and start the actual container
podman-compose up