Докер с использованием gosu vs USER
Docker всегда существовала команда USER
для запуска процесса как конкретного пользователя, но в целом многое должно было выполняться как ROOT.
Я видел много изображений, которые используют ENTRYPOINT
с gosu
для отмены процесса для запуска.
Я все еще немного запутался в необходимости gosu
. Должно ли ПОЛЬЗОВАТЕЛЯ быть достаточно?
Я знаю, что с точки зрения безопасности с Docker 1.10 я немного изменился, но я до сих пор не совсем понимаю, как использовать этот процесс в контейнере докеров.
Может кто-нибудь объяснить, когда я буду использовать gosu
vs. USER
?
Спасибо
EDIT:
Руководство Docker не очень понятно: в нем говорится, что если процесс может работать без привилегий, используйте USER
, если вам нужно sudo, вы можете использовать gosu
.
Это сбивает с толку, потому что можно установить всевозможные вещи как ROOT в Dockerfile
, затем создать пользователя и предоставить ему соответствующие привилегии, а затем, наконец, переключиться на этого пользователя и запустить CMD
в качестве этого пользователя.
Итак, зачем нам sudo или gosu
тогда?
Ответы
Ответ 1
Dockerfiles предназначены для создания изображений. Я вижу gosu более полезным как часть инициализации контейнера, когда вы больше не можете изменять пользователей между командами запуска в вашем файле Docker.
После создания изображения что-то вроде gosu позволяет отбрасывать права root в конце вашей точки входа внутри контейнера. Первоначально вам может потребоваться доступ root для выполнения некоторых этапов инициализации (исправление разрешений на использование uid, хоста и т.д.). Затем после инициализации вы запускаете окончательную службу без привилегий root и как pid 1 обрабатываете сигналы чисто.
Изменить:
Вот простой пример использования gosu в изображении для докеров и дженкинсов: https://github.com/bmitch3020/jenkins-docker
Entrypoint.sh просматривает gid файла /var/lib/docker.sock и обновляет подсказку пользователя докера в контейнере, чтобы он соответствовал. Это позволяет переносить изображение на другие хосты докеров, где gid на хосте может отличаться. Для изменения группы требуется корневой доступ внутри контейнера. Если бы я использовал USER jenkins
в файле dockerfile, я бы застрял в god группы докеров, как это определено в изображении, которое не сработало бы, если оно не соответствует тому, на котором он работает. Но root-доступ можно отбросить при запуске приложения, в которое входит gosu.
В конце script вызов exec запрещает оболочке открывать gosu, и вместо этого он заменяет pid 1 этим процессом. Gosu, в свою очередь, делает то же самое, переключая uid, а затем выполняет процесс jenkins так, чтобы он принимался за pid 1. Это позволяет правильно обрабатывать сигналы, которые в противном случае игнорировались бы оболочкой как pid 1.
Ответ 2
Я использую gosu и entrypoint.sh, потому что я хочу, чтобы пользователь в контейнере имел тот же UID, что и пользователь, создавший контейнер.
Объемы и разрешения Docker.
Целью контейнера, который я создаю, является разработка. Мне нужно собрать для Linux, но я все еще хочу все возможности локального (OS X) редактирования, инструментов и т.д. Мое сохранение идентификаторов UID внутри и снаружи контейнера делает владение файлом намного более разумным и предотвращает некоторые ошибки ( пользователь контейнера не может редактировать файлы в подключенном томе и т.д.)
Ответ 3
Преимуществом использования gosu
является также обработка сигналов. Вы можете trap
, например, SIGHUP
для перезагрузки процесса, как обычно достигаете с помощью systemctl reload <process>
или такого.
Ответ 4
Я пытался решить проблему с разрешениями в Docker-контейнере без GOSU-зависимости. Совсем. Мой подход заключается в том, чтобы изменить идентификатор пользователя контейнера на лету, перестроив контейнер в задании jenkins (или там, где мне нужно развернуть мои приложения).
Здесь ниже я приведу пример, как я это сделал.
Образец Dockerfile:
FROM imageWhereIWantToSetSameUidAsOnMyHostMachine
USER root
RUN usermod -u {{UID}} www-data
USER www-data
Перед созданием контейнера (скажем, в задании jenkins) с использованием этого Dockerfile я использую команду sed, чтобы заменить заполнитель идентификатора пользователя {{UID}}:
CURRENT_UID=id -u $(whoami)
sed -i -e "s/{{UID}}/$CURRENT_UID/g" Dockerfile
затем я строю контейнер:
docker build -t myImageWithFixedPermissions .
В результате myImageWithFixedPermissions первоначально будет иметь идентификатор пользователя хост-машины, и проблем с разрешениями не будет.
Я полагаю, что основным преимуществом этого является избавление от дополнительных зависимостей gosu, которые каким-то образом уменьшат размер образа докера (кажется правильным способом сохранить как можно меньше зависимостей в контейнере докера). Возможно, самым большим недостатком является то, что сборка контейнера (даже с такой низкой сложностью, как у последнего) потребует некоторого дополнительного времени развертывания.
Ваши комментарии и предложения по улучшению или критике этого подхода очень приветствуются, так как я хочу, чтобы я выяснил, что лучше: быть Госу или не быть в моих контейнерах.
Заранее спасибо за ответ!