Невозможно добавить нового пользователя в 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
Другие вопросы по тегам