tag - Каков (лучший) способ управления разрешениями для разделяемых томов Docker?





remove name (12)


Мой подход заключается в обнаружении текущего идентификатора UID / GID, а затем создания такого пользователя / группы внутри контейнера и выполнения сценария под ним, поэтому все файлы, которые он создаст, будут соответствовать пользователю, выполняющему сценарий:

# get location of this script no matter what your current folder is, this might break between shells so make sure you run bash
LOCAL_DIR="$( cd "$( dirname "${BASH_SOURCE[0]}" )" && pwd )"

# get current IDs
USER_ID=$(id -u)
GROUP_ID=$(id -g)

echo "Mount $LOCAL_DIR into docker, and match the host IDs ($USER_ID:$GROUP_ID) inside the container."

docker run -v $LOCAL_DIR:/host_mount -i debian:9.4-slim bash -c "set -euo pipefail && groupadd -r -g $GROUP_ID lowprivgroup && useradd -u $USER_ID lowprivuser -g $GROUP_ID && cd /host_mount && su -c ./runMyScriptAsRegularUser.sh lowprivuser"

Я некоторое время играю с Docker и продолжаю находить ту же проблему при работе с постоянными данными.

Я создаю свой Dockerfile и выставляю тома или использую --volumes-from для монтирования папки хоста внутри моего контейнера .

Какие разрешения следует применять к общему тому на хосте?

Я могу представить два варианта:

  • До сих пор я предоставлял каждому доступ для чтения / записи, поэтому я могу писать в папку из контейнера Docker.

  • Сопоставьте пользователей из хоста в контейнер, поэтому я могу назначить более подробные разрешения. Не уверен, что это возможно, хотя и не нашли много об этом. Пока что все, что я могу сделать, это запустить контейнер как некоторый пользователь: docker run -i -t -user="myuser" postgres , но у этого пользователя есть другой UID, чем мой myuser хозяин, поэтому разрешения не работают. Кроме того, я не уверен, что сопоставление пользователей будет представлять собой некоторые угрозы безопасности.

Существуют ли другие альтернативы?

Как вы, ребята / девушки, занимаетесь этой проблемой?




Очень элегантное решение можно увидеть на официальном изображении redis и вообще на всех официальных изображениях.

Описанный в пошаговом процессе:

  • Создавать пользователя / группу redis перед чем-либо еще

Как видно на комментариях Dockerfile:

сначала добавьте нашего пользователя и группу, чтобы убедиться, что их идентификаторы получаются последовательно, независимо от того, какие зависимости добавляются

  • Установите gosu с Dockerfile

gosu является альтернативой su / sudo для простого перехода от пользователя root. (Redis всегда запускается с пользователем redis )

  • Настроить /data объем /data и установить его как workdir

Конфигурируя том / data с помощью команды VOLUME /data теперь у нас есть отдельный том, который может быть либо докерером, либо привязанным к хосту.

Настройка его как workdir ( WORKDIR /data ) делает его каталогом по умолчанию, из которого выполняются команды.

  • Добавьте файл точки входа в докер и установите его как ENTRYPOINT с помощью redis-сервера CMD по умолчанию

Это означает, что все выполнение контейнера будет выполняться через сценарий точки входа в докер, и по умолчанию команда, которую нужно запустить, является redis-server.

docker-entrypoint - это скрипт, который выполняет простую функцию: изменение владельца текущего каталога (/ data) и redis от root к пользователю redis для запуска redis-server . (Если исполняемая команда не redis-server, она будет запускать команду напрямую.)

Это имеет следующий эффект:

Если каталог / data привязан к узлу хоста, точка входа в докер подготовит права пользователя перед запуском redis-сервера под пользователем redis .

Это дает вам легкость в том, что существует нулевая настройка для запуска контейнера при любой конфигурации тома.

Конечно, если вам нужно разделить объем между разными изображениями, вам нужно убедиться, что они используют один и тот же идентификатор пользователя / groupid, иначе последний контейнер удержит права пользователя от предыдущего.




Это, возможно, не лучший способ для большинства обстоятельств, но он еще не упоминается, поэтому, возможно, это поможет кому-то.

  1. Объединить объем хоста

    Host folder FOOBAR is mounted in container /volume/FOOBAR

  2. Измените сценарий запуска вашего контейнера, чтобы найти GID тома, который вам интересен

    $ TARGET_GID=$(stat -c "%g" /volume/FOOBAR)

  3. Убедитесь, что ваш пользователь принадлежит к группе с этим GID (возможно, вам придется создать новую группу). В этом примере я буду притворяться, что мое программное обеспечение работает как nobody пользователей внутри контейнера, поэтому я хочу, чтобы nobody принадлежал к группе с идентификатором группы, равным TARGET_GID

  EXISTS=$(cat /etc/group | grep $TARGET_GID | wc -l)

  # Create new group using target GID and add nobody user
  if [ $EXISTS == "0" ]; then
    groupadd -g $TARGET_GID tempgroup
    usermod -a -G tempgroup nobody
  else
    # GID exists, find group name and add
    GROUP=$(getent group $TARGET_GID | cut -d: -f1)
    usermod -a -G $GROUP nobody
  fi

Мне это нравится, потому что я могу легко изменять групповые разрешения на своих томах хоста и знать, что эти обновленные разрешения применяются в контейнере докера. Это происходит без каких-либо разрешений или прав собственности на мои папки / файлы хоста, что делает меня счастливым.

Мне это не нравится, потому что он предполагает, что нет никакой опасности добавлять себя к произвольным группам внутри контейнера, которые используют GID, который вы хотите. Он не может использоваться с предложением USER в файле Docker (если у этого пользователя нет привилегий root). Кроме того, он кричит взломать работу ;-)

Если вы хотите быть хардкором, вы можете, очевидно, расширить его по-разному - например, поиск всех групп на любых подфайлах, нескольких томах и т. Д.







То же, что и вы, я искал способ сопоставления пользователей / групп с хостом на контейнеры докеров, и это самый короткий способ, который я нашел до сих пор:

  version: "3"
    services:
      my-service:
        .....
        volumes:
          # take uid/gid lists from host
          - /etc/passwd:/etc/passwd:ro
          - /etc/group:/etc/group:ro
          # mount config folder
          - path-to-my-configs/my-service:/etc/my-service:ro
        .....

Это выдержка из моего docker-compose.yml.

Идея состоит в том, чтобы монтировать (в режиме только для чтения) список пользователей / групп из хоста в контейнер, поэтому после запуска контейнера он будет иметь одинаковые совпадения uid-> username (а также для групп) с хостом. Теперь вы можете настроить параметры пользователя / группы для своей службы внутри контейнера, как если бы она работала на вашей хост-системе.

Когда вы решите переместить свой контейнер на другой хост, вам просто нужно изменить имя пользователя в файле конфигурации службы на то, что у вас есть на этом хосте.




UPDATE 2016-03-02 : Начиная с Docker 1.9.0, Docker назвал тома, которые заменяют контейнеры только для данных . Ответ ниже, а также мое связанное сообщение в блоге по-прежнему имеют значение в смысле того, как думать о данных внутри докеров, но подумайте об использовании именованных томов для реализации шаблона, описанного ниже, а не контейнеров данных.

Я считаю, что канонический способ решить эту проблему - использование контейнеров только для данных . При таком подходе весь доступ к данным тома осуществляется через контейнеры, которые используют -volumes-from контейнера данных, поэтому host uid / gid не имеет значения.

Например, один вариант использования, указанный в документации, представляет собой резервную копию объема данных. Для этого другой контейнер используется для резервного копирования через tar , и он также использует -volumes-from для монтирования тома. Поэтому я считаю, что ключевым моментом для этого является: вместо того, чтобы думать о том, как получить доступ к данным на хосте с соответствующими разрешениями, подумайте о том, как делать все, что вам нужно - резервные копии, просмотр и т. Д. - через другой контейнер , Сами контейнеры должны использовать согласованные uid / gids, но им не нужно отображать что-либо на хосте, оставаясь при этом переносимым.

Это относительно новое для меня, но если у вас есть конкретный случай использования, не стесняйтесь комментировать, и я попытаюсь расширить ответ.

ОБНОВЛЕНИЕ : для данного варианта использования в комментариях у вас может быть изображение some/graphite для запуска графита и изображение some/graphitedata в качестве контейнера данных. Таким образом, игнорируя порты и т. Д., Dockerfile образа some/graphitedata выглядит примерно так:

FROM debian:jessie
# add our user and group first to make sure their IDs get assigned consistently, regardless of other deps added later
RUN groupadd -r graphite \
  && useradd -r -g graphite graphite
RUN mkdir -p /data/graphite \
  && chown -R graphite:graphite /data/graphite
VOLUME /data/graphite
USER graphite
CMD ["echo", "Data container for graphite"]

Создайте и создайте контейнер данных:

docker build -t some/graphitedata Dockerfile
docker run --name graphitedata some/graphitedata

some/graphite Dockerfile должно также получать одинаковые uid / gids, поэтому оно может выглядеть примерно так:

FROM debian:jessie
# add our user and group first to make sure their IDs get assigned consistently, regardless of other deps added later
RUN groupadd -r graphite \
  && useradd -r -g graphite graphite
# ... graphite installation ...
VOLUME /data/graphite
USER graphite
CMD ["/bin/graphite"]

И он будет работать следующим образом:

docker run --volumes-from=graphitedata some/graphite

Итак, теперь это дает нам наш графитовый контейнер и связанный контейнер с данными только с правильным пользователем / группой (обратите внимание, что вы можете повторно использовать контейнер some/graphite для контейнера данных, переопределяя ввод / cmd при его запуске, но имея их в виде отдельных изображений IMO, яснее).

Теперь скажем, вы хотите что-то редактировать в папке с данными. Поэтому вместо того, чтобы связывать установку с хостом и редактировать его там, создайте новый контейнер для выполнения этой задачи. Давайте назовем его some/graphitetools . Позволяет также создать соответствующий пользователь / группу, точно так же, как изображение с some/graphite изображениями.

FROM debian:jessie
# add our user and group first to make sure their IDs get assigned consistently, regardless of other deps added later
RUN groupadd -r graphite \
  && useradd -r -g graphite graphite
VOLUME /data/graphite
USER graphite
CMD ["/bin/bash"]

Вы можете сделать это DRY, наследуя от some/graphite или some/graphitedata графических файлов в файле Docker, или вместо создания нового изображения просто повторно используйте один из существующих (переопределяя точку входа / cmd при необходимости).

Теперь вы просто запускаете:

docker run -ti --rm --volumes-from=graphitedata some/graphitetools

а затем vi /data/graphite/whatever.txt . Это работает отлично, потому что все контейнеры имеют один и тот же графитовый пользователь с соответствующими uid / gid.

Поскольку вы никогда не монтируете /data/graphite с хоста, вам все равно, как хост uid / gid сопоставляется с uid / gid, определенным внутри контейнеров graphite и graphitetools . Теперь эти контейнеры могут быть развернуты на любом хосте, и они будут продолжать работать отлично.

Уверенная вещь в том, что graphitetools может иметь всевозможные полезные утилиты и скрипты, которые теперь можно развернуть переносимым образом.

ОБНОВЛЕНИЕ 2 : после написания этого ответа я решил написать более полное сообщение в блоге об этом подходе. Я надеюсь, что это помогает.

ОБНОВЛЕНИЕ 3 : Я исправил этот ответ и добавил больше деталей. Ранее он содержал некоторые неправильные предположения о владении и perms - право собственности обычно присваивается при создании тома, то есть в контейнере данных, потому что именно тогда создается тома. Смотрите container42.com/2014/11/18/data-only-container-madness . Однако это не является обязательным требованием - вы можете просто использовать контейнер данных в качестве «ссылки / дескриптора» и установить права собственности / perms в другом контейнере через chown в точке входа, которая заканчивается gosu, чтобы запустить команду как правильный пользователь. Если кто-то заинтересован в этом подходе, прокомментируйте, и я могу предоставить ссылки на образец, используя этот подход.




Для обеспечения безопасности и изменения корневого --uidmap для докер-контейнера хост-докеры попробуйте использовать --uidmap и --private-uids

https://github.com/docker/docker/pull/4572#issuecomment-38400893

Также вы можете удалить несколько возможностей ( --cap-drop ) в контейнере --cap-drop для обеспечения безопасности

http://opensource.com/business/14/9/security-for-docker

Поддержка UPDATE должна появиться в docker > 1.7.0

UPDATE Версия 1.10.0 (2016-02-04) add --userns-remap flag https://github.com/docker/docker/blob/master/CHANGELOG.md#security-2




Если вы используете Docker Compose, запустите контейнер в превалированном режиме:

wordpress:
    image: wordpress:4.5.3
    restart: always
    ports:
      - 8084:80
    privileged: true



Хорошо, теперь это отслеживается при выпуске докеров # 7198

На данный момент я имею дело с этим, используя ваш второй вариант:

Отображать пользователей из хоста в контейнер

Dockerfile

#=======
# Users
#=======
# TODO: Idk how to fix hardcoding uid & gid, specifics to docker host machine
RUN (adduser --system --uid=1000 --gid=1000 \
        --home /home/myguestuser --shell /bin/bash myguestuser)

CLI

# DIR_HOST and DIR_GUEST belongs to uid:gid 1000:1000
docker run -d -v ${DIR_HOST}:${DIR_GUEST} elgalu/myservice:latest

ОБНОВЛЕНИЕ В настоящее время я склонен к answer Хами




Базовый образ

Используйте это изображение: https://hub.docker.com/r/reduardo7/docker-host-user

или же

Важно: это разрушает контейнерную переносимость между узлами .

1) init.sh

#!/bin/bash

if ! getent passwd $DOCKDEV_USER_NAME > /dev/null
  then
    echo "Creating user $DOCKDEV_USER_NAME:$DOCKDEV_GROUP_NAME"
    groupadd --gid $DOCKDEV_GROUP_ID -r $DOCKDEV_GROUP_NAME
    useradd --system --uid=$DOCKDEV_USER_ID --gid=$DOCKDEV_GROUP_ID \
        --home-dir /home --password $DOCKDEV_USER_NAME $DOCKDEV_USER_NAME
    usermod -a -G sudo $DOCKDEV_USER_NAME
    chown -R $DOCKDEV_USER_NAME:$DOCKDEV_GROUP_NAME /home
  fi

sudo -u $DOCKDEV_USER_NAME bash

2) Dockerfile

FROM ubuntu:latest
# Volumes
    VOLUME ["/home/data"]
# Copy Files
    COPY /home/data/init.sh /home
# Init
    RUN chmod a+x /home/init.sh

3) run.sh

#!/bin/bash

DOCKDEV_VARIABLES=(\
  DOCKDEV_USER_NAME=$USERNAME\
  DOCKDEV_USER_ID=$UID\
  DOCKDEV_GROUP_NAME=$(id -g -n $USERNAME)\
  DOCKDEV_GROUP_ID=$(id -g $USERNAME)\
)

cmd="docker run"

if [ ! -z "${DOCKDEV_VARIABLES}" ]; then
  for v in ${DOCKDEV_VARIABLES[@]}; do
    cmd="${cmd} -e ${v}"
  done
fi

# /home/usr/data contains init.sh
$cmd -v /home/usr/data:/home/data -i -t my-image /home/init.sh

4) Построить с docker

4) Беги!

sh run.sh



Чтобы обмениваться папкой между докером-хостом и контейнером докеров, попробуйте выполнить команду ниже

$ docker run -v "$ (pwd): $ (pwd)" -i -t ubuntu

Флаг -v устанавливает текущий рабочий каталог в контейнер. Если каталог хоста подключенного тома не существует, Docker автоматически создаст этот каталог на хосте для вас,

Однако есть две проблемы, которые мы имеем здесь:

  1. Вы не можете писать на том, смонтированный, если вы не являетесь пользователем root, потому что общий файл будет принадлежать другому пользователю в хосте,
  2. Вы не должны запускать процесс внутри своих контейнеров как root, но даже если вы запускаете его как некорректного пользователя, он все равно не будет соответствовать пользователю на вашем ноутбуке / Jenkins,

Решение:

Контейнер: создайте пользователя «testuser», по умолчанию идентификатор пользователя будет начинаться с 1000,

Хост: создайте группу, скажем «testgroup» с идентификатором группы 1000, и запустите каталог в новую группу (тестовая группа




[ДОПОЛНЕНО] Начиная с ~ июня 2017 года, Docker для Mac заботится обо всех досадных частях этого, где вам нужно общаться с VirtualBox. Он позволяет отображать в основном все на вашем локальном узле с использованием префикса /private . Больше информации here . [/ОБНОВИТЬ]

Все текущие ответы говорят о Boot2docker. Так как это теперь устарело в пользу докер-машины, это работает на докер-машине:

Во-первых, ssh в docker-machine vm и создайте папку, в которую мы будем сопоставлять:

docker-machine ssh $MACHINE_NAME "sudo mkdir -p \"$VOL_DIR\""

Теперь поделитесь папкой с VirtualBox:

WORKDIR=$(basename "$VOL_DIR")
vboxmanage sharedfolder add "$MACHINE_NAME" --name "$WORKDIR" --hostpath "$VOL_DIR" --transient

Наконец, ssh в docker-machine снова и смонтируйте папку, которую мы только что разделили:

docker-machine ssh $MACHINE_NAME "sudo mount -t vboxsf -o uid=\"$U\",gid=\"$G\" \"$WORKDIR\" \"$VOL_DIR\""

Примечание: для UID и GID вы можете в принципе использовать любые целые числа, если они еще не приняты.

Это проверено как на докер-машине 0.4.1 и докер 1.8.3 на OS X El Capitan.







docker