Відмовлено в доступі до каталогу хостів у Docker


283

Коротше кажучи: я намагаюся встановити каталог хостів у Docker, але потім не можу отримати доступ до нього зсередини контейнера, навіть якщо дозволи на доступ виглядають добре.

Деталі:

я роблю

sudo docker run -i -v /data1/Downloads:/Downloads ubuntu bash

і потім

ls -al

Це дає мені:

total 8892
drwxr-xr-x.  23 root root    4096 Jun 18 14:34 .
drwxr-xr-x.  23 root root    4096 Jun 18 14:34 ..
-rwxr-xr-x.   1 root root       0 Jun 18 14:34 .dockerenv
-rwx------.   1 root root 9014486 Jun 17 22:09 .dockerinit
drwxrwxr-x.  18 1000 1000   12288 Jun 16 11:40 Downloads
drwxr-xr-x.   2 root root    4096 Jan 29 18:10 bin
drwxr-xr-x.   2 root root    4096 Apr 19  2012 boot
drwxr-xr-x.   4 root root     340 Jun 18 14:34 dev
drwxr-xr-x.  56 root root    4096 Jun 18 14:34 etc
drwxr-xr-x.   2 root root    4096 Apr 19  2012 home

і ще багато подібних рядків (я думаю, це відповідна частина).

Якщо я це роблю

cd /Downloads
ls

результат є

ls: cannot open directory .: Permission denied

Хост - Fedora 20, з Docker 1.0.0 та go1.2.2.

Що йде не так?

Відповіді:


269

Дивіться цю публікацію в блозі Project Atomic про «Томи» та SELinux для повної історії.

Конкретно:

Це стало простіше нещодавно, оскільки Docker нарешті об'єднав патч, який буде відображатися в docker-1.7 (ми переносили патч в docker-1.6 на RHEL, CentOS та Fedora).

Цей патч додає підтримку "z" та "Z" як опцій на кріпленнях гучності (-v).

Наприклад:

docker run -v /var/db:/var/db:z rhel7 /bin/sh

Автоматично виконає chcon -Rt svirt_sandbox_file_t /var/db описане на сторінці man.

Ще краще, ви можете використовувати Z.

docker run -v /var/db:/var/db:Z rhel7 /bin/sh

Це позначатиме вміст всередині контейнера точною міткою MCS, з якою він буде працювати, в основному він працює chcon -Rt svirt_sandbox_file_t -l s0:c1,c2 /var/dbтам, де s0:c1,c2для кожного контейнера він відрізняється.


18
Це працює як шарм. Інші рішення - це переважно обхідні шляхи.
tuxdna

4
пор. розділ міток обсягу в документації
докера

О, чоловіче, це справді працює. Я нарешті знайшов це. Велике дякую! Чи є офіційна документація з цього приводу?
Кірбі


1
Це можливо виправити дозволу при SELinux при монтажі гучності , як тільки для читання , в той же час, використовуючи обидва варіанти одночасно розділених комою: -v $(pwd):/app:ro,Z. Це слід позначити як правильну відповідь.
Данірод

263

Це проблема SELinux .

Ви можете тимчасово видавати

su -c "setenforce 0"

на хості, щоб отримати доступ або ще додати правило SELinux, запустивши

chcon -Rt svirt_sandbox_file_t /path/to/volume

3
є / шлях / до / обсяг шляху хоста? Якщо так, не здається, що це рішення працюватиме з контейнерами даних?
Roy Truelove

6
не забудьте зробити su -c "setenforce 1" ... інакше це буде працювати лише тому, що SELinux все ще деактивований
vcarel

це вирішило мою проблему. дякую, я сподіваюся, що у них виправлять це.
Хокутосей

19
Додавання правила selinux - це найкращий спосіб, оскільки це не дуже корисна ідея для запуску контейнерів у привілейованому режимі.
Zoro_77

7
Як сказав Zoro_77, додайте правило і stopdisablingselinux.com ;)
GabLeRoux

71

ПОПЕРЕДЖЕННЯ. Це рішення має загрозу безпеці.

Спробуйте запустити контейнер як привілейований:

sudo docker run --privileged=true -i -v /data1/Downloads:/Downloads ubuntu bash

Іншим варіантом (який я не пробував) було б створити привілейований контейнер, а потім створити непривілейовані контейнери всередині нього.


1
@JBernardo Який із двох варіантів вирішив проблему?
користувач100464

@ user100464--privileged=true
JBernardo

1
Не допомагайте в моєму випадку. Debian Whezzy з підтримуваним ядром 3.16, але не активована конфігурація SELinux. :(
aholbreich

якщо ваш користувач докер-композитор додасть "привілейований: правда"
Ліонель Моррісон

35
Не роби цього. --privilegedє ризиком для безпеки
Навін

38

Зазвичай проблеми з правами на кріплення тома хоста виникають через те, що uid / gid всередині контейнера не має доступу до файлу відповідно до дозволів uid / gid для файлу на хості. Однак цей конкретний випадок інший.

Крапка в кінці рядка дозволу drwxr-xr-x., вказує, що SELinux налаштований. Використовуючи кріплення хоста з SELinux, вам потрібно пройти додаткову опцію до кінця визначення гучності:

  • The zПараметр вказує на те, що зміст прив'язка змонтованого розподіляється між декількома контейнерами.
  • ZПараметр вказує на те, що зміст прив'язка змонтованого є приватним і нерозділене.

Тоді ваша команда встановлення гучності виглядатиме так:

sudo docker run -i -v /data1/Downloads:/Downloads:z ubuntu bash

Докладніше про кріплення хостів із SELinux за посиланням: https://docs.docker.com/storage/#configure-the-selinux-label


Для інших, хто бачить цю проблему з контейнерами, які працюють як інший користувач, вам потрібно переконатися, що uid / gid користувача всередині контейнера має дозволи на файл на хості. На виробничих серверах це часто робиться шляхом керування uid / gid у процесі збирання зображення, щоб відповідати uid / gid на хості, який має доступ до файлів (а ще краще, не використовуйте кріплення хостів у виробництві).

Іменований том часто віддають перевагу хост-версій, оскільки він ініціалізує каталог томів із каталогу зображень, включаючи будь-які права власності на файли та дозволи. Це відбувається, коли обсяг порожній і контейнер створюється з названим томом.

Зараз користувачі MacOS мають OSXFS, який автоматично обробляє uid / gid між хостом Mac та контейнерами. Одне місце, якому воно не допомагає, - це файли з всередині вбудованої VM, яка встановлюється в контейнер, як-от /var/lib/docker.sock.

Для середовищ розробки, де uid / gid хоста може змінюватись на кожного розробника, моїм кращим рішенням є запуск контейнера з точкою входу, що працює як корінь, виправлення uid / gid користувача всередині контейнера, щоб відповідати обсягу ходу uid / gid, і потім скористайтесь gosuдля переходу з кореня на користувача контейнера, щоб запустити програму всередині контейнера. Важливий сценарій для цього - fix-permsу моїх сценаріях базового зображення, які можна знайти за посиланням: https://github.com/sudo-bmitch/docker-base

Важливий біт fix-permsсценарію:

# update the uid
if [ -n "$opt_u" ]; then
  OLD_UID=$(getent passwd "${opt_u}" | cut -f3 -d:)
  NEW_UID=$(stat -c "%u" "$1")
  if [ "$OLD_UID" != "$NEW_UID" ]; then
    echo "Changing UID of $opt_u from $OLD_UID to $NEW_UID"
    usermod -u "$NEW_UID" -o "$opt_u"
    if [ -n "$opt_r" ]; then
      find / -xdev -user "$OLD_UID" -exec chown -h "$opt_u" {} \;
    fi
  fi
fi

Це отримує uid користувача всередині контейнера, а uid файлу, і якщо вони не відповідають, викликає usermodкоригування uid. Нарешті, це рекурсивна знахідка, щоб виправити будь-які файли, які не змінили uid's. Мені це подобається краще, ніж запускати контейнер з -u $(id -u):$(id -g)прапором, оскільки вищевказаний код точки введення не вимагає, щоб кожен розробник запустив скрипт для запуску контейнера, і будь-які файли поза томом, які належать користувачеві, будуть виправлені їх дозволи.


Ви також можете мати докер ініціалізувати каталог хостів із зображення, використовуючи названий том, який виконує кріплення прив’язки. Цей каталог повинен існувати заздалегідь, і вам потрібно надати абсолютний шлях до каталогу хостів, на відміну від томів хостів у складеному файлі, який може бути відносним шляхом. Каталог також повинен бути порожнім, щоб докер ініціалізував його. Три різні варіанти визначення названого гучності для прив’язки кріплення виглядають так:

  # create the volume in advance
  $ docker volume create --driver local \
      --opt type=none \
      --opt device=/home/user/test \
      --opt o=bind \
      test_vol

  # create on the fly with --mount
  $ docker run -it --rm \
    --mount type=volume,dst=/container/path,volume-driver=local,volume-opt=type=none,volume-opt=o=bind,volume-opt=device=/home/user/test \
    foo

  # inside a docker-compose file
  ...
  volumes:
    bind-test:
      driver: local
      driver_opts:
        type: none
        o: bind
        device: /home/user/test
  ...

Нарешті, якщо ви спробуєте скористатись просторами імен користувачів, ви побачите, що в томах хостів є проблеми з дозволом, оскільки uid / gid контейнерів зміщуються. У такому сценарії, мабуть, найпростіше уникнути томів хосту і використовувати лише названі томи.


32

Від access.redhat.com:Sharing_Data_Across_Containers :

Налаштування гучності хоста не є портативними, оскільки вони залежать від хоста і можуть не працювати на будь-якій іншій машині. З цієї причини не існує еквівалента Dockerfile для монтажу каталогів хоста до контейнера. Також майте на увазі, що хост-система не знає політики контейнерів SELinux. Тому, якщо застосовується політика SELinux, змонтований каталог хостів не є доступним для запису в контейнер, незалежно від налаштування rw. В даний час ви можете обійти це, призначивши правильний тип політики SELinux до каталогу хостів ":

chcon -Rt svirt_sandbox_file_t host_dir

Де host_dir - це шлях до каталогу в хост-системі, який встановлений до контейнера.

Здається, це лише обхід, але я спробував, і це працює.


14

Я це перевірив chcon -Rt svirt_sandbox_file_t /path/to/volume це працює, і вам не потрібно запускатись як привілейований контейнер.

Це на:

  • Докер версія 0.11.1-dev, збірка 02d20af / 0.11.1
  • CentOS 7 як хост і контейнер з включеною SELinux.

2
Дивіться сторінку github.com/docker/docker/pull/5910 для отримання офіційної підтримки для відновлення міток у Docker.
cpuguy83

13

Спробуйте docker volume create.

mkdir -p /data1/Downloads
docker volume create --driver local --name hello --opt type=none --opt device=/data1/Downloads --opt o=uid=root,gid=root --opt o=bind
docker run -i -v hello:/Downloads ubuntu bash

Погляньте на документ https://docs.docker.com/engine/reference/commandline/volume_create/


3
Спробував багато відповідей щодо цього питання на SO, але насправді це допомогло. Дякую!
Пол,

Він вирішив помилку дозволу. Але тепер, якщо я намагаюся встановити фізичне місце, він монтує voulme ???? @ cupen
kunal verma

1
@kunalverma Так. Якщо вам це не подобається, ось простіша відповідь. stackoverflow.com/a/31334443/4909388
cupen

4

У мене була подібна проблема, моє було викликано невідповідністю між UID хостом і UID користувача контейнера. Виправлення полягало в тому, щоб передати UID користувача в якості аргументу збірці докера та створити користувача контейнера з тим самим UID.

У DockerFile:

ARG UID=1000
ENV USER="ubuntu"
RUN useradd -u $UID -ms /bin/bash $USER

На етапі збирання:

docker build <path/to/Dockerfile> -t <tag/name> --build-arg UID=$UID

Після цього запуск контейнера та команд згідно з ОП дав мені очікуваний результат.


1
Що робити, якщо ви не знаєте UID до часу запуску? (Я будую зображення для колег, щоб упакувати деякі інструменти, які записуються до їх файлової системи, але вони мають різні UID). Я думаю, що я міг би зберегти його корінь і лише аддусер у бігу?
інгер

На жаль, я не маю гарної відповіді на це. Якщо у когось іншого є рішення, я також був би зацікавлений у ньому. Я підозрюю, що функція Docker entrypoint може запропонувати рішення.
RoboCop87

0

Я вирішив цю проблему, використовуючи контейнер даних, це також має перевагу в ізоляції даних із рівня додатків. Ви можете запустити його так:

docker run --volumes-from=<container-data-name> ubuntu

Цей підручник дає хороше пояснення щодо використання контейнерів даних.


-1

У моїй ситуації проблема була іншою. Я не знаю чому, але навіть якщо на ньому розміщувався каталог хосту chmod 777, всередині докера було видно як755 .

Пробіг всередині контейнера sudo chmod 777 my_volume_dirзафіксував його.


5
chmod 777навряд чи коли-небудь щось виправляє.
Еркі

Вибачте, але ви пропустили суть. Справа в тому, що всередині привілеїв контейнера було знижено і його неможливо було виправити ззовні.
CodeSandwich

-2

sudo -s зробив трюк для мене на MAC


1
Якщо ви виступаєте проти, залиште коментар та поясніть чому. Я зіткнувся з точно таким же питанням, і мені вдалося вирішити це через sudo -s.
Nachiket Joshi

Не у кожному зображенні докера є судо, і це неможливо в кожному сценарії.
SOFe

2
Не встановлюйте судо на контейнери. Зловмисник може використовувати судо всередині контейнера.
Арнольд
Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.