Некоторое время я играл с Docker и продолжаю находить ту же проблему при работе с постоянными данными.
Я создаю свой Dockerfile
и выставляю том или использую --volumes-from
для монтирования папки хоста внутри моего контейнера .
Какие разрешения я должен применить к общему объему на хосте?
Я могу придумать два варианта:
До сих пор я предоставил всем доступ на чтение / запись, чтобы я мог писать в папку из контейнера Docker.
Сопоставьте пользователей с хоста в контейнере, чтобы я мог назначить более детальные разрешения. Не уверен, что это возможно, хотя и не нашел много об этом. Пока что все, что я могу сделать, это запустить контейнер как некоторый пользователь:,
docker run -i -t -user="myuser" postgres
но у этого пользователя другой UID, чем у моего хостаmyuser
, поэтому разрешения не работают. Кроме того, я не уверен, что сопоставление пользователей будет представлять некоторую угрозу безопасности.
Есть ли другие альтернативы?
Как вы, ребята, работаете с этой проблемой?
Ответы:
ОБНОВЛЕНИЕ 2016-03-02 : Начиная с Docker 1.9.0, Docker имеет именованные тома, которые заменяют контейнеры только для данных . Приведенный ниже ответ, как и мой пост в блоге, все еще имеет значение в том смысле, как думать о данных внутри докера, но подумайте об использовании именованных томов для реализации описанного ниже шаблона, а не контейнеров данных.
Я считаю, что канонический способ решить эту проблему - использовать контейнеры только для данных . При таком подходе весь доступ к данным тома осуществляется через контейнеры, которые используют
-volumes-from
контейнер данных, поэтому хост uid / gid не имеет значения.Например, один из вариантов использования, приведенный в документации, - резервное копирование тома данных. Для этого используется другой контейнер для резервного копирования через
tar
, и он также использует-volumes-from
для монтирования тома. Поэтому я думаю, что ключевой момент в работе с Grok: вместо того, чтобы думать о том, как получить доступ к данным на хосте с соответствующими разрешениями, подумайте о том, как сделать все, что вам нужно - резервное копирование, просмотр и т. Д. - через другой контейнер. , Сами контейнеры должны использовать согласованные uid / gids, но им не нужно сопоставлять что-либо на хосте, тем самым оставаясь переносимым.Для меня это тоже относительно новый вопрос, но если у вас есть конкретный вариант использования, не стесняйтесь комментировать, и я постараюсь расширить ответ.
ОБНОВЛЕНИЕ : Для данного варианта использования в комментариях у вас может быть изображение
some/graphite
для запуска графита и изображениеsome/graphitedata
в качестве контейнера данных. Таким образом, игнорируя порты и тому подобное,Dockerfile
изображениеsome/graphitedata
выглядит примерно так:Создайте и создайте контейнер данных:
some/graphite
Dockerfile также должен получить тот же UID / GID, поэтому она может выглядеть следующим образом :И это будет работать следующим образом:
Хорошо, теперь это дает нам наш графитовый контейнер и связанный контейнер только для данных с правильной пользователем / группой (обратите внимание, что вы также можете повторно использовать
some/graphite
контейнер для контейнера данных, переопределяя entrypoing / cmd при его запуске, но имея их как отдельные изображения ИМО понятнее).Теперь предположим, что вы хотите редактировать что-то в папке данных. Поэтому вместо того, чтобы привязывать монтирование тома к хосту и редактировать его там, создайте новый контейнер для этой работы. Давай называть это
some/graphitetools
. Также давайте создадим соответствующего пользователя / группу, какsome/graphite
изображение.Вы можете сделать этот СУХОЙ, унаследовав от
some/graphite
илиsome/graphitedata
в Dockerfile, или вместо создания нового образа просто повторно используйте один из существующих (при необходимости переопределяя точку входа / cmd).Теперь вы просто запускаете:
а потом
vi /data/graphite/whatever.txt
. Это прекрасно работает, потому что все контейнеры имеют одного и того же пользователя графита с совпадающим uid / gid.Поскольку вы никогда не установить
/data/graphite
от хозяина, не все равно , как хозяин UID / GID карты к UID / GID определяется внутриgraphite
иgraphitetools
контейнеров. Эти контейнеры теперь могут быть развернуты на любом хосте, и они будут продолжать работать отлично.Отличительной особенностью этого является то
graphitetools
, что у вас могут быть всевозможные полезные утилиты и скрипты, которые теперь вы также можете развернуть в переносном режиме.ОБНОВЛЕНИЕ 2 : После написания этого ответа я решил написать более полный блог об этом подходе. Я надеюсь, что это помогает.
ОБНОВЛЕНИЕ 3 : я исправил этот ответ и добавил больше деталей. Ранее в нем содержались некоторые неверные предположения о владении и привилегиях - владение обычно назначается во время создания тома, т. Е. В контейнере данных, поскольку именно тогда создается том. Смотрите этот блог . Это не является обязательным требованием - вы можете просто использовать контейнер данных в качестве «ссылки / дескриптора» и устанавливать владельца / права доступа в другом контейнере с помощью chown в точке входа, который заканчивается gosu для запуска команды от имени правильного пользователя. Если кто-то заинтересован в этом подходе, пожалуйста, прокомментируйте, и я могу предоставить ссылки на образец, используя этот подход.
источник
/data/newcontainer
? Я предполагаю, что вы работаетеdocker
от имени пользователя root (возможно ли это не делать?) Кроме того, есть ли разница в этих разрешениях, если данные монтируются непосредственно в основной контейнер или через контейнер только для данных ?/var/lib/docker
где-то, но все еще огромная больОчень элегантное решение можно увидеть на официальном изображении Redis и в целом на всех официальных изображениях.
Описано в пошаговом процессе:
Как видно из комментариев Dockerfile:
gosu - это альтернатива
su
/sudo
для легкого отказа от пользователя root. (Redis всегда запускается сredis
пользователем)/data
громкость и установите его как рабочий каталогНастроив том / data с помощью
VOLUME /data
команды, теперь у нас есть отдельный том, который может быть либо док-томом, либо подключенным к каталогу хоста.Конфигурирование его как workdir (
WORKDIR /data
) делает его каталогом по умолчанию, из которого выполняются команды.Это означает, что все выполнения контейнера будут выполняться через сценарий docker-entrypoint, и по умолчанию команда, которую нужно запустить, - это redis-server.
docker-entrypoint
скрипт, выполняющий простую функцию: измените владельца текущего каталога (/ data) и перейдитеroot
кredis
пользователю для запускаredis-server
. (Если выполненная команда не является redis-сервером, она будет запущена непосредственно).Это имеет следующий эффект
Если каталог / data привязан к хосту, точка входа docker подготовит права пользователя перед запуском redis-server под
redis
пользователем.Это дает вам ощущение простоты, что для запуска контейнера в любой конфигурации тома не требуется никаких настроек.
Конечно, если вам нужно разделить объем между различными изображениями, вам нужно убедиться, что они используют один и тот же идентификатор пользователя / groupid, в противном случае последний контейнер перехватит права пользователя из предыдущего.
источник
chown
это внутриENTRYPOINT
скрипта?Возможно, это не лучший способ для большинства обстоятельств, но он еще не упоминался, поэтому, возможно, он кому-то поможет.
Привязать том хоста
Host folder FOOBAR is mounted in container /volume/FOOBAR
Измените скрипт запуска вашего контейнера, чтобы найти GID нужного вам тома
$ TARGET_GID=$(stat -c "%g" /volume/FOOBAR)
Убедитесь, что ваш пользователь входит в группу с этим GID (возможно, вам придется создать новую группу). В этом примере я буду притворяться, что моя программа запускается как
nobody
пользователь, когда находится внутри контейнера, поэтому я хочу убедиться, что онаnobody
принадлежит группе с идентификатором группы, равнымTARGET_GID
Мне это нравится, потому что я могу легко изменять групповые разрешения на томах своего хоста и знать, что эти обновленные разрешения применяются внутри контейнера докера. Это происходит без каких-либо разрешений или изменений владельца моих папок / файлов хоста, что меня радует.
Мне это не нравится, потому что предполагается, что нет опасности добавлять себя в произвольные группы внутри контейнера, которые используют нужный GID. Его нельзя использовать с
USER
предложением в Dockerfile (если, я полагаю, у этого пользователя нет привилегий root). Кроме того, это кричит взломать работу ;-)Если вы хотите быть хардкорным, вы, очевидно, можете расширить его многими способами - например, искать все группы в любых подфайлах, нескольких томах и т. Д.
источник
$TARGET_GID
было бы использоватьgrep ':$TARGET_GID:'
, в противном случае , если контейнер имеет, например , GID 10001 и ваш хозяин 1000, эта проверка будет проходить , но оно не должно.Хорошо, это теперь отслеживается в проблеме докера # 7198
Сейчас я занимаюсь этим, используя ваш второй вариант:
Dockerfile
CLI
ОБНОВЛЕНИЕ Я в настоящее время более склонен к ответу Хэми
источник
id -u <username>
,id -g <username>
,id -G <username>
чтобы получить идентификатор пользователя и идентификатор группы пользователя , определенного вместоПопробуйте добавить команду в Dockerfile
кредиты идут на https://github.com/denderello/symfony-docker-example/issues/2#issuecomment-94387272
источник
Как и вы, я искал способ отобразить пользователей / группы из хоста в докер-контейнеры, и это самый короткий путь, который я нашел до сих пор:
Это выдержка из моего docker-compose.yml.
Идея состоит в том, чтобы смонтировать (в режиме только для чтения) списки пользователей / групп с хоста на контейнер, поэтому после запуска контейнера он будет иметь те же соответствия uid-> username (как и для групп) с хостом. Теперь вы можете настроить параметры пользователя / группы для вашего сервиса внутри контейнера, как если бы он работал в вашей хост-системе.
Когда вы решите переместить свой контейнер на другой хост, вам просто нужно изменить имя пользователя в файле конфигурации службы на то, что у вас есть на этом хосте.
источник
-u $( id -u $USER ):$( id -g $USER )
и вам больше не нужно беспокоиться об имени пользователя. Это хорошо работает для локальных сред разработки, где вы хотите создавать файлы (например, двоичные файлы), к которым у вас есть права на чтение / запись по умолчанию.Вот подход, который все еще использует контейнер только для данных, но не требует его синхронизации с контейнером приложения (с точки зрения наличия того же uid / gid).
Предположительно, вы хотите запустить какое-то приложение в контейнере от имени пользователя US $ без полномочий root без оболочки входа в систему.
В Dockerfile:
Затем в entrypoint.sh:
источник
Для обеспечения безопасности и изменения корня для Docker-контейнера попробуйте использовать Docker host
--uidmap
и--private-uids
опцииhttps://github.com/docker/docker/pull/4572#issuecomment-38400893
Также вы можете удалить несколько возможностей (
--cap-drop
) в контейнере Docker для безопасностиhttp://opensource.com/business/14/9/security-for-docker
ОБНОВЛЕНИЕ поддержка должна прийти
docker > 1.7.0
ОБНОВЛЕНИЕ версии
1.10.0
(2016-02-04) добавить--userns-remap
флаг https://github.com/docker/docker/blob/master/CHANGELOG.md#security-2источник
--uidmap
ни--private-uids
параметров. Похоже, пиар не сделал этого и не был объединен."We apparently do have so some of conflicting designs between libnetwork and user namespaces ... and something we'd like to get in for 1.8.0. So don't think we're dropping this, we're definitely going to take a break after all these, and see how we need to reconsider the current design and integration of libnetwork to make this possible. Thanks!"
github.com/docker/docker/pull/12648 Так что я думаю, что нам следует подождать следующей стабильной версии.Мой подход заключается в том, чтобы обнаружить текущий UID / GID, затем создать такого пользователя / группу внутри контейнера и выполнить скрипт под ним. В результате все файлы, которые он создаст, будут соответствовать пользователю на хосте (который является скриптом):
источник
Базовое изображение
Используйте это изображение: https://hub.docker.com/r/reduardo7/docker-host-user
или
Важно: это разрушает переносимость контейнера между хостами .
1)
init.sh
2)
Dockerfile
3) run.sh
4) Сборка с
docker
4) Беги!
источник
В моем конкретном случае я пытался собрать свой пакет узла с образом докера узла, чтобы мне не пришлось устанавливать npm на сервере развертывания. Это работало хорошо до тех пор, пока вне контейнера и на хост-машине я не попытался переместить файл в каталог node_modules, который создал образ докера узла, на который мне было отказано в разрешениях, поскольку он принадлежал пользователю root. Я понял, что могу обойти это, скопировав каталог из контейнера на хост-машину. Через докер документы ...
Это код bash, который я использовал для смены владельца каталога, созданного в контейнере Docker.
При необходимости вы можете удалить каталог со вторым док-контейнером.
источник
Чтобы разделить папку между хостом Docker и контейнером Docker, попробуйте команду ниже
Флаг -v монтирует текущий рабочий каталог в контейнер. Если каталог хоста подключенного тома тома не существует, Docker автоматически создаст этот каталог на хосте для вас,
Однако здесь есть 2 проблемы:
Решение:
Контейнер: создайте пользователя, скажем «testuser», по умолчанию идентификатор пользователя будет начинаться с 1000,
Хост: создайте группу, скажем «testgroup» с идентификатором группы 1000, и добавьте каталог в новую группу (testgroup
источник
Если вы используете Docker Compose, запустите контейнер в превалирующем режиме:
источник