Moby: Добавить возможность монтировать том от имени пользователя, отличного от root

Созданный на 17 окт. 2013  ·  157Комментарии  ·  Источник: moby/moby

Вариант использования: смонтировать том с хоста в контейнер для использования apache в качестве пользователя www.
Проблема в том, что в настоящее время все монтирования монтируются как root внутри контейнера.
Например, эта команда
docker run -v /tmp:/var/www ubuntu stat -c "%U %G" /var/www
напечатает "корень корень"

Мне нужно смонтировать его как пользователя www внутри контейнера.

areapi arekernel arevolumes exexpert kinenhancement

Самый полезный комментарий

Могу ли я сказать «нет» — принуждение пользователей к добавлению вспомогательного сценария,

#!/bin/sh
chown -R redis:redis /var/lib/redis
exec sudo -u redis /usr/bin/redis-server

(спасибо @bfirsh за ваш пример)

довольно ужасно.

Это означает, что контейнер должен запускаться от имени пользователя root, а не от предполагаемого пользователя redis . (как намекнул @aldanor )

и это означает, что пользователь не может сделать что-то вроде:

docker run -v /home/user/.app_cfg/ -u user application_container application :(

Все 157 Комментарий

Если вы chown том (на стороне хоста) до его монтирования привязки, он будет работать.
В этом случае вы можете сделать:

mkdir /tmp/www
chown 101:101 /tmp/www
docker run -v /tmp/www:/var/www ubuntu stat -c "%U %G" /var/www

(Предположим, что 101:101 — это UID:GID пользователя www-data в вашем контейнере.)

Другая возможность - выполнить привязку, а затем chown внутри контейнера.

@mingfang Чаун тебе не подойдет?

Было бы полезно иметь ярлык для этого. Я часто ловлю себя на том, что пишу сценарии run , которые просто устанавливают разрешения для тома:

https://github.com/orchardup/docker-redis/blob/07b65befbd69d9118e6c089e8616d48fe76232fd/run

Что делать, если у вас нет прав на это chown ?

Решит ли эту проблему вспомогательный скрипт, который chown объем? Этот скрипт может быть ENTRYPOINT вашего Dockerfile.

Могу ли я сказать «нет» — принуждение пользователей к добавлению вспомогательного сценария,

#!/bin/sh
chown -R redis:redis /var/lib/redis
exec sudo -u redis /usr/bin/redis-server

(спасибо @bfirsh за ваш пример)

довольно ужасно.

Это означает, что контейнер должен запускаться от имени пользователя root, а не от предполагаемого пользователя redis . (как намекнул @aldanor )

и это означает, что пользователь не может сделать что-то вроде:

docker run -v /home/user/.app_cfg/ -u user application_container application :(

Есть _один_ способ заставить это работать, но вам нужно заранее подготовиться в вашем Dockrfile.

RUN mkdir -p /var/lib/redis ; chown -R redis:redis /var/lib/redis
VOLUME ["/var/lib/redis"]
ENTRYPOINT ["usr/bin/redis-server"]
USER redis

(Я не тестировал этот пример, я работаю над контейнером хрома, который затем отображается в контейнере _separate_ X11, который ....)

И, конечно же, этот метод работает только для прямых новых томов, а не для привязки.
смонтированные или тома-из томов. ;)

Кроме того, несколько контейнеров, использующих volumes-from , будут иметь разные uid/gid для одного и того же пользователя, что также усложняет ситуацию.

@SvenDowideit @tianon этот метод тоже не работает. Полный пример:

FROM ubuntu
RUN groupadd -r redis    -g 433 && \
useradd -u 431 -r -g redis -d /app -s /sbin/nologin -c "Docker image user" redis 
RUN mkdir -p /var/lib/redis
RUN echo "thing" > /var/lib/redis/thing.txt
RUN chown -R redis:redis /var/lib/redis
VOLUME ["/var/lib/redis"]
USER redis
CMD /bin/ls -lah /var/lib/redis

Два прогона, с томом -v и без него:

bash-3.2$ docker run -v `pwd`:/var/lib/redis voltest 
total 8.0K
drwxr-xr-x  1 root root  102 Aug  7 21:30 .
drwxr-xr-x 28 root root 4.0K Aug  7 21:26 ..
-rw-r--r--  1 root root  312 Aug  7 21:30 Dockerfile
bash-3.2$ docker run  voltest 
total 12K
drwxr-xr-x  2 redis redis 4.0K Aug  7 21:30 .
drwxr-xr-x 28 root  root  4.0K Aug  7 21:26 ..
-rw-r--r--  1 redis redis    6 Aug  7 21:26 thing.txt
bash-3.2$ 

Мы сталкиваемся с проблемой, которая будет решена этим (я думаю). У нас есть общий ресурс NFS для домашних каталогов нашего разработчика. Разработчики хотят смонтировать /home/dev/git/project в Docker, но не могут, потому что у нас включен Root Squash.

Это запрещает root доступ к /home/dev/git/project , поэтому, когда я пытаюсь запустить установку докера /home/dev/git/project , я получаю ошибку lstat permission denied .

@frankamp Это связано с тем, что в настоящее время докер предпочитает не изменять хост-вещи, которые не находятся в пределах собственного контроля Докера.

Ваше определение "VOLUME" перезаписывается вашим -v pwd`:/var/lib/reds`.
Но во втором запуске используется том, управляемый докером, который создается в /var/lib/docker. Когда контейнер запускается, докер копирует данные из образа в том, а затем chown том с uid:gid каталога, для которого был указан том.

Я не уверен, что здесь можно многое сделать, и, к сожалению, монтирование привязки не поддерживает (насколько я могу судить) монтирование как другой uid/gid.

Мое решение состояло в том, чтобы сделать то, что SvenDowideit сделал выше (создать нового пользователя и указать его в файле dockerfile), но затем вместо монтирования хост-тома использовать контейнер только для данных и скопировать хост-том, который я хотел смонтировать, в контейнер с tar cf - . | docker run -i --volumes-from app_data app tar xvf - -C /data . Это станет немного проще после объединения https://github.com/docker/docker/pull/13171docker cp работает в обе стороны), но, возможно, это может стать альтернативой -v host_dir:container_dir , т.е. возможно, -vc host_dir:container_dir (vc для копирования тома), при этом содержимое host_dir будет скопировано в контейнер данных. Хотя я не могу сказать, что понимаю, почему/как скопированные файлы наследуют разрешения пользователя контейнера, из того, что я могу сказать, что они это делают, и это единственное разумное решение, которое мне удалось придумать, которое не разрушает переносимость.

Что с аккл?

Есть ли какое-либо исправление или обходной путь? Я столкнулся с той же проблемой с OpenShift, смонтированная папка принадлежит пользователю root: root , а предварительно созданные образы не будут работать.

Я тоже ищу обходной путь. Если все подключенные тома принадлежат root , это делает невозможным запуск ваших контейнеров Docker с любым пользователем, кроме root .

Ну можно попробовать s6-overlay . Он включает в себя функции, специально предназначенные для решения подобных проблем.

@dreamcat4 : Спасибо за указатель. Исправление прав собственности и разрешений кажется интересным обходным путем, но разве мне не нужно запускать контейнер Docker от имени пользователя root, чтобы это работало?

@ brikis98 Да, это правда. Однако s6-overlay также имеет еще одну функцию, которая позволяет вам снова сбрасывать разрешения при запуске ваших серверов / демонов.

@dreamcat4 А, понял, спасибо.

У меня один и тот же uid/gid внутри и снаружи контейнера, и вот что я получаю:

nonroot$ ls -l .dotfiles/
ls: cannot access .dotfiles/byobu: Permission denied
ls: cannot access .dotfiles/config: Permission denied
ls: cannot access .dotfiles/docker: Permission denied
ls: cannot access .dotfiles/vim: Permission denied
ls: cannot access .dotfiles/bashrc: Permission denied
ls: cannot access .dotfiles/muse.yml: Permission denied
ls: cannot access .dotfiles/my.cnf: Permission denied
ls: cannot access .dotfiles/profile: Permission denied
total 0
-????????? ? ? ? ?            ? bashrc
d????????? ? ? ? ?            ? byobu
d????????? ? ? ? ?            ? config
d????????? ? ? ? ?            ? docker
-????????? ? ? ? ?            ? muse.yml
-????????? ? ? ? ?            ? my.cnf
-????????? ? ? ? ?            ? profile
d????????? ? ? ? ?            ? vim
nonroot$ ls -l .ssh
ls: cannot access .ssh/authorized_keys: Permission denied
total 0
-????????? ? ? ? ?            ? authorized_keys
nonroot$

@darkermatter не могли бы вы открыть отдельную тему?

не проблема, а здесь это не актуально?

@darkermatter это запрос функции, а не отчет об ошибке, смешивание вашего случая с другими делами затрудняет отслеживание обсуждения, также ваша проблема может не иметь прямого отношения

@thaJeztah , как и @frankamp и другие, я просто демонстрировал, что происходит после запуска chmod и т. Д. Внутри Dockerfile. Я отправлю его как отчет об ошибке, но он имеет отношение к этому обсуждению.

аналогично тому, что предложил @ebuchman , без копирования тома хоста вы можете сначала создать контейнер только для данных, который выполняет
chown 1000:1000 /volume-mount как root при запуске.
Например, в синтаксисе docker compose v2

version: '2'
services:
  my-beautiful-service:
    ...
    depends_on:
      - data-container
    volumes_from:
      - data-container

  data-container:
    image: same_base_OS_as_my-beautiful-service
    volumes:
      - /volume-mount
    command: "chown 1000:1000 /volume-mount"

Таким образом, ваш контейнер может работать как пользователь без полномочий root. Контейнер только для данных запускается только один раз.
Предполагая, что вы заранее знаете uid и gid, которые использует my-beautiful-service. Обычно это 1000,1000.

Поскольку вы можете (в 1.11) указать параметры монтирования для тома, который будет использоваться в вашем docker volume create , я бы сказал, что это кажется довольно близким к тому, чтобы быть готовым к закрытию.

Вы не можете просто указать uid/gid напрямую, потому что это не поддерживается при монтировании с привязкой, но многие файловые системы, которые вы можете использовать с новыми параметрами монтирования, могут работать с параметрами uid/gid.

Я думаю, что проблема все еще существует в тех случаях, когда вы хотите смонтировать диск CIFS внутри своего контейнера, однако, может быть, это должен быть другой билет?

@ michaeljs1990 michaeljs1990 Вы можете сделать это, но не для каждого контейнера (если только вы не создадите отдельные тома для каждой желаемой комбинации uid/gid).

@cpuguy83 cpuguy83 , не могли бы вы пояснить, как нужно использовать docker volume create , чтобы избежать этой проблемы?

Я только что столкнулся с этой проблемой сегодня с докером 1.11, и мне пришлось сделать болезненную перенастройку, чтобы убедить образ докера позволить мне писать в файлы на смонтированном диске. Было бы очень хорошо, если бы мне никогда не пришлось делать это снова, не говоря уже о том, чтобы пытаться объяснить это кому-то другому.

Не уверен, что это то, о чем вы спрашиваете, но...

FROM busybox
RUN mkdir /hello && echo hello > /hello/world && chown -R 1000:1000 /hello

Создайте изображение выше с именем «тест»

$ docker volume create --name hello
$ docker run -v hello:/hello test ls -lh /hello

И /hello , и /hello/world в приведенном выше примере будут принадлежать 1000:1000.

Я понимаю. Итак, я сделал что-то похожее, но немного другое, поэтому, возможно, стоит поделиться. По сути, я добавил пользователя в Dockerfile, который поделился моим UID, GID, именем пользователя и группой для пользователя вне контейнера. Все <...> заменены соответствующими значениями.

FROM <some_image>
RUN groupadd -g <my_gid> <my_group> && \
    useradd -u <my_uid> -g <my_gid> <my_user>

После этого можно либо переключиться с помощью USER , либо с помощью su в какой-то более поздний момент (например, сценарий точки входа или при использовании оболочки). Это позволило мне писать на подключенный том, поскольку я был тем же пользователем, который создал. Можно дополнительно использовать chown внутри контейнера, чтобы убедиться, что у него есть разрешения на соответствующие вещи. Кроме того, установка sudo , как правило, также является разумным шагом.

Хотя это решает проблему, я не знаю, нравится ли мне это, поскольку это нужно сделать для любого пользователя. Кроме того, я жестко закодировал вещи (фу!), но, возможно, можно использовать шаблоны, чтобы сделать это немного более плавным. Интересно, может ли эта прокладка каким-то образом впитаться в docker run . Если уже есть лучший способ сделать это, мне было бы очень интересно узнать, что это такое.

Существует возможность сопоставить uid/gid пользователей хоста с uid/gid пользователей контейнера с помощью --userns-remap . Лично я не пробовал. См. хорошее обсуждение этой темы http://stackoverflow.com/questions/35291520/docker-and-userns-remap-how-to-manage-volume-permissions-to-share-data-betwee .

@cpuguy83 :

Вы не можете просто указать uid/gid напрямую, потому что это не поддерживается при монтировании с привязкой, но многие файловые системы, которые вы можете использовать с новыми параметрами монтирования, могут работать с параметрами uid/gid.

О каких файловых системах вы думаете, что они могут принимать аргументы uid/gid? Я знаю, что FAT может, но это кажется таким же хакерским, как и все остальное, предлагаемое в этой теме.

ИМО, у Docker есть два варианта:

  1. Официальная поддержка монтирования томов в качестве указанного пользователя/группы (с использованием имени пользователя/группы, определенного внутри контейнера, не требуя от хоста знания внутреннего устройства контейнера).
  2. Или... избавьтесь от директивы USER (и связанных с ней флагов времени выполнения).

Возможность запуска от имени пользователя без полномочий root при возможности монтирования только томов, принадлежащих пользователю root, является недостатком. Совместное использование uid/gid между хостом и контейнером — еще одна ошибка.

Тома @mehaase получают право собственности на все, что уже находится на пути в контейнере. Если местоположение в контейнере принадлежит root, то том получит root. Если местоположение в контейнере принадлежит кому-то другому, том получит это.

Какой-то обходной путь для этого был бы отличным. Если контейнер специально этого не ожидает, _очень_ сложно добавлять тома в стандартные контейнеры, такие как elasticsearch, Redis, CouchDB и многие другие, без написания собственного Dockerfile, который устанавливает разрешения. В основном это делает команду docker run -v или директиву volume: в docker-compose бесполезной.

@chrisfosterelli почему бесполезно? Я не думаю, что это что-то необычное — устанавливать права собственности на файлы/каталоги, которые вы собираетесь использовать.

@cpuguy83 cpuguy83 Потому что невозможно установить право собственности без использования пользовательского файла Docker, который устанавливает разрешения и тома, поэтому думаю, что они бесполезны для определения томов. Я не привязываю контейнеры к моей файловой системе хоста, если это уместно.

@chrisfosterelli Но все эти стандартные файлы Dockerfile должны иметь уже установленные разрешения.

Я думаю, что @chrisfosterelli пытается сказать, @cpuguy83 (и, пожалуйста, поправьте меня, если я ошибаюсь @chrisfosterelli), стало ясно, что эти переменные (UID, GID и т. д.) являются динамическими и должны быть установлены в во время выполнения (особенно в отношении файлов, находящихся во внутренней собственности, и из смонтированных томов), но в настоящее время у нас нет способа сделать это. Ответ до сих пор, кажется, заключается в том, что они не должны определяться во время выполнения, но это игнорирует фундаментальную проблему удобства использования, представленную таким предложением. Опять же, если я неправильно понимаю что-либо из этого, пожалуйста, поправьте меня.

@jakirkham Должно быть, я не понимаю, в чем проблема юзабилити.
Файлы находятся в образе, они должны иметь права собственности и разрешения, необходимые для запуска приложения. К самому объему это не имеет никакого отношения. Громкость просто принимает то, что было установлено на изображении.

@cpuguy83 cpuguy83 Я еще немного покопался и выделил это: скажем, у меня есть контейнер elasticsearch, который при запуске создаст каталог /data (если данных нет), а затем используйте docker run -v /data elasticsearch . Каталог /data становится владельцем root:root , и демон, работающий под именем elasticsearch внутри контейнера, теперь не запустится, потому что он не может писать в /data .

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

@chrisfosterelli в списках рассылки ядра ходят разговоры о наличии оверлея, такого как драйвер, который может сменить владельца, но мы мало что можем сделать без чего-то подобного. Мне любопытно, можете ли вы просто сделать так, чтобы все файлы в вашем мире томов читались и записывались, и правильно установили umasks, чтобы новые файлы тоже были? (я еще не пробовал).

@justincormack Думаю, да, но я думаю, что это не работает, когда я ожидаю, что контейнер создаст данные в томе (а не на хосте). Я понимаю, что это довольно странная проблема, поэтому в настоящее время я решаю ее, исправляя ее в самом восходящем Dockerfile в каталоге mkdir -p && chmod .

@chrisfosterelli вот почему я сказал установить umask, если ваш umask равен 000 (в контейнере), все новые файлы будут создаваться с разрешениями 666 или 777 , и если точка монтирования 777 для начала это должно быть в порядке? Если разрешения всегда мировые для чтения и записи, uid и gid не должны иметь значения?

@justincormack Да, это звучит правильно ... как я могу это сделать при создании док-контейнера с томом, не смонтированным на хосте?

@chrisfosterelli хм, это хороший вопрос. Мне кажется, что разрешения для нового тома — это то, что дает umask по умолчанию, поэтому вы можете попробовать запустить демон докеров с umask 000 и посмотреть, доступен ли тогда том для записи во всем мире. Возможно, у нас должны быть какие-то параметры разрешений на docker volume create .

(вы можете исправить это с помощью корневого контейнера, который сделал chmod и тоже вышел, но это уродливо)

При создании не годится. Проблема в том, что если у контейнера нет пути, путь создается с помощью root. Возможно, это может быть сделано как любой переданный пользователь.

@ cpuguy83 cpuguy83 Я думаю, было бы более разумно создать его, когда пользователь передал с -u, поскольку это, вероятно, был бы пользователь, пытающийся записать том из контейнера, верно?

Я смог смонтировать пользователя по своему выбору, выполнив следующие шаги:

  • Создайте пользователя внутри Docker с тем же UID/GID, что и у пользователя, которому принадлежат файлы на хосте.
  • Заранее создайте точки монтирования и отправьте их целевому пользователю в контейнере.

Цитата @chrisfosterelli :

Я еще немного покопался и выделил это: скажем, у меня есть контейнер elasticsearch, который создаст каталог /data при запуске (если данных нет), а затем используйте docker run -v /data elasticsearch. Каталог /data становится владельцем root:root , и демон, который работает как elasticsearch внутри контейнера, теперь не запустится, потому что он не может писать в /data.

Это отличный пример! У меня есть аналогичный пример с изображением Solr. Solr требуется одно или несколько «ядер», каждое из которых представляет собой набор связанных файлов конфигурации и фрагментов индекса. Каждое ядро ​​размещается внутри каталога с указанным пользователем именем. Например, если я хочу создать ядро ​​с именем products , путь будет /opt/solr/server/solr/products . Имя ядра выбрано мной, поэтому мейнтейнер образа Solr не может предварительно создать эту директорию в образе.

Я хочу, чтобы мои данные индекса были сохранены, чтобы я мог обновить свой образ до более новой версии Solr без необходимости повторной индексации всех моих документов, но если я смонтирую том в /opt/solr/server/solr/products , то он будет принадлежать root и Solr (работающий как solr ) не могут на самом деле ничего записать в него. Родительский каталог /opt/solr/server/solr содержит другие файлы, поэтому я также не могу смонтировать туда том. (Я полагаю, что в последнем языке Docker мои тома называются «именованными томами», то есть томами, которые не подключены к указанному пути на хосте, но полностью управляются Docker для меня.)

Я говорил об этом с сопровождающим образа Solr, и есть несколько обходных путей (и он внес некоторые изменения в образ, чтобы помочь), но все это довольно хакерское и требует индивидуальных изменений в исходном образе. Наличие функции, обсуждаемой в этой теме, сделало бы _все изображения_ более расширяемыми без необходимости создания нового файла Dockerfile.

@ctindel может быть ... если каталог еще не существует.

@ cpuguy83 Это правда, я согласен. Это определенно был мой вариант использования. Кажется, нет смысла создавать каталог как root, если он не существует, когда идентификатор пользователя был явно указан для запуска контейнера.

@ cpuguy83 это работает только для именованного тома.

@kamechen Что просто работает?

@cpuguy83 cpuguy83 Когда вы используете именованный том, файлы монтируются под нужным вам пользователем.

@ecuca Ну .... это зависит. Если именованный том был пуст или данные в именованном томе были созданы тем же пользователем, который вам нужен.

Было ли когда-нибудь решение проблемы, поднятой @andrewmichaelsmith?

Мы сталкиваемся с проблемой, которая будет решена этим (я думаю). У нас есть общий ресурс NFS для домашних каталогов нашего разработчика. Разработчики хотят смонтировать /home/dev/git/project в Docker, но не могут, потому что у нас включен Root Squash.

Это запрещает root доступ к /home/dev/git/project, поэтому, когда я пытаюсь запустить установку докера /home/dev/git/project, я получаю ошибку отказа в разрешении lstat.

Я думаю, что это можно обойти с помощью bindfs .
Использование докера -v ... для монтирования тома во временном месте, а затем bindfs для монтирования его там, где это необходимо, от имени другого пользователя.

@piccaso , как я понял @andrewmichaelsmith , проблема в том, что привязка на стороне хоста не работает из-за rootquash. Но на самом деле bindfs все еще можно использовать в качестве обходного пути, но на этот раз на стороне хоста. Во-первых, на хосте вы привязываете и монтируете общий ресурс nfs во временное место в качестве пользователя без полномочий root с помощью FUSE, а затем монтируете эту временную папку в докере с помощью -v ... .

Имейте в виду, что у bindfs (по крайней мере, с FUSE) довольно много ресурсов процессора.

Да, bindfs очень нежелателен. Это медленнее, чем даже файловые системы CoW.
В ядре выполняется некоторая работа, позволяющая смещать uid/gid при монтировании, что может помочь.

В ядре выполняется некоторая работа, позволяющая смещать uid/gid при монтировании, что может помочь.

Это, вероятно, также поможет только в случае использования, когда я хочу переназначить uid/gid внутри контейнера. Само монтирование, выполняемое демоном докера, по-прежнему будет выполняться от имени пользователя root на хосте. Насколько я понимаю, монтирование с привязкой ядра может быть создано только с правами root. Не уверен, что есть работа, чтобы изменить это, чтобы позволить пользователям без полномочий root выполнять монтирование (я мало знаю о том, как Linux обрабатывает монтирование, чтобы судить, имеет ли это вообще смысл).

@NikolausDemmel Я сомневаюсь, что это изменится. Для системного вызова mount требуется CAP_SYS_ADMIN, который не предоставляется пользователю без полномочий root и даже не предоставляется пользователю root в контейнере.

@ cpuguy83 Спасибо за разъяснения. Это означает, что монтирование томов докеров в папки хоста, которые являются монтированиями NFS с помощью root-squash, не будут работать в обозримом будущем (из-за ограничений системного вызова монтирования, как вы говорите), за исключением использования обходных путей, таких как FUSE с bindfs .

Извините, это было немного OT, так как OP спрашивал об изменении UID/GID внутри контейнера. Но это своего рода обратная сторона медали, и это всплыло в обсуждении выше. Просто хотел уточнить это различие.

Я запускаю Docker для Mac и смонтировал том, но не могу получить разрешения, установленные для веб-службы, для доступа к файлам. Как мне это исправить? Я попытался изменить права и установить группу персонала, но, похоже, у Alpine нет группы персонала.

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

@NikolausDemmel : мы пытаемся использовать Docker для некоторых работ по биоинформатике. У нас есть несколько огромных файловых систем, смонтированных с корневым доступом через NFS. Мы считываем огромные последовательности данных (fastq) и записываем BAM-файл несколько меньшего размера с геномными чтениями, выровненными по хранилищу данных. В настоящее время мы можем использовать докер, создав пользовательский образ для создания пользователя внутри контейнера и используя USER в конце, чтобы заставить его работать, но это проблематично по нескольким причинам:

  1. Если мы хотим использовать чужой образ Docker, нам нужно перестроиться с помощью пользовательского файла Dockerfile.
  2. Нам либо нужно создать собственный образ докера для каждого локального пользователя, либо мы используем единую «служебную» учетную запись, и мы не сможем различать действия пользователя в ФС.

Могут ли Bindfs или userNS обойти это?

Я думаю, что столкнулся с той же проблемой, мой вариант использования:
Образы Docker содержат наши портативные инструменты сборки для данного проекта, мы используем монтирование томов с относительными путями либо с чем-то вроде docker run -v ./:/src/ image , либо с эквивалентом в файле docker-compose. Сборка запускается автоматически, и в подпапке связанного тома создаются новые файлы.
Иногда нам нравится использовать эти встроенные файлы с хоста, но тот факт, что они по-прежнему принадлежат пользователю в докере, а не пользователю хоста, запустившему докер, усложняет ситуацию.

Я делаю что-то особенно неправильно здесь?

@rlabrecque см. мой пост ранее о сопоставлении идентификатора пользователя докера с идентификатором хоста. Я использовал этот подход, и он очень хорошо работает для нас. По сути, запустите HOST_UID=$(id -u) и HOST_GID=$(id -g) и сгенерируйте Dockerfile, который расширяет $HOST_GID и $HOST_UID в следующих двух командах:

RUN groupadd -g $HOST_GID mygroup
RUN useradd -l -u $HOST_UID -g mygroup myuser

Используйте сгенерированный файл Dockerfile с заполненным идентификатором, чтобы создать образ.

@haridsv Я сделал нечто подобное, и оно отлично работает в Linux. Но, похоже, это не работает для меня в Windows: файлы внутри монтирования по-прежнему принадлежат пользователю root.

Я решил это, используя inotifywait . Вам нужно будет установить inotify-tools, чтобы запустить его внутри вашего образа докера. Вместо этого его можно запустить на вашей хост-системе, но мне нужно портативное решение.

RUN export DEBIAN_FRONTEND=noninteractive \
  && apt -y update \
  && apt -y install inotify-tools \
  && inotifywait -m -r /mount -e create --format '%w%f' \
    | while read f; do chown $(stat -c '%u' /mount):$(stat -c '%g' /mount) $f; done

Это работает, инструктируя inotifywait следить за любыми новыми файлами или каталогами, созданными в каталоге /mount. Когда он замечает один из них, он меняет владельца на того же пользователя и группу, что и папка /mount. Я использовал целочисленное представление обоих, на случай, если хост-пользователь/группа не существует в контейнере. Внутри контейнера не имеет значения, кто им владеет, потому что все работает как root. Вне контейнера файловая система хоста показывает то же право собственности, что и любой каталог, смонтированный в /mount.

Я намеренно разработал его, чтобы установить права собственности только на вновь созданные файлы и каталоги, чтобы сохранить права собственности на уже существующие файлы и каталоги. Это безопаснее, чем сбрасывать все это с помощью инструкции chown -R каждый раз, когда монтируется файловая система. Если унифицированные разрешения подходят для вашего проекта и вам нужно более простое решение, которое работает более эффективно, обратите внимание на inotify-hookable .

Предупреждение. Поскольку для каждого подкаталога будет установлено одно наблюдение за inotify, возможно, будет достигнуто максимальное количество наблюдателей за inotify на пользователя. Максимальное значение по умолчанию — 8192; его можно увеличить, написав в /proc/sys/fs/inotify/max_user_watches.

Мы использовали сценарий на стороне хоста для chown смонтированного тома, что позволяет избежать необходимости перестраивать образ:

#!/bin/bash
set -e

DOCKER_IMAGE=<docker_image>
COMMAND=<internal_command>

DOCKER_USER=docker-user
DOCKER_GROUP=docker-group

HOME_DIR=/work
WORK_DIR="$HOME_DIR/$(basename $PWD)"

PARAMS="$PARAMS -it --rm"
PARAMS="$PARAMS -v $PWD:$WORK_DIR"
PARAMS="$PARAMS -w $WORK_DIR"

USER_ID=$(id -u)
GROUP_ID=$(id -g)

run_docker()
{
  echo \
    groupadd -f -g $GROUP_ID $DOCKER_GROUP '&&' \
    useradd -u $USER_ID -g $DOCKER_GROUP $DOCKER_USER '&&' \
    chown $DOCKER_USER:$DOCKER_GROUP $WORK_DIR '&&' \
    sudo -u $DOCKER_USER HOME=$HOME_DIR $COMMAND
}

if [ -z "$DOCKER_HOST" ]; then
    docker run $PARAMS $DOCKER_IMAGE "$(run_docker) $*"
else
    docker run $PARAMS $DOCKER_IMAGE $COMMAND "$*"
fi

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

@thaJeztah @justincormack @cpuguy83

@kamechen , похоже, прав в том, что названные тома «просто работают». В случае именованных томов существующие разрешения «обратно действуют» и изменяют разрешения тома, и я лично считаю это ошибкой (# 28041).

@thegecko , почему бы не использовать этот подход дальше и не создавать пользователей в точке входа?

Вот мой пример, он определяет владельца смонтированного каталога, создает пользователя с таким же UID и запускает команду как под этим пользователем:

Докерфайл

FROM ubuntu

RUN mkdir /project
VOLUME /project

ENV GOSU_VERSION 1.9
RUN set -x \
    && apt-get update && apt-get install -y --no-install-recommends ca-certificates wget && rm -rf /var/lib/apt/lists/* \
    && dpkgArch="$(dpkg --print-architecture | awk -F- '{ print $NF }')" \
    && wget -O /usr/local/bin/gosu "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch" \
    && wget -O /usr/local/bin/gosu.asc "https://github.com/tianon/gosu/releases/download/$GOSU_VERSION/gosu-$dpkgArch.asc" \
    && export GNUPGHOME="$(mktemp -d)" \
    && gpg --keyserver ha.pool.sks-keyservers.net --recv-keys B42F6819007F00F88E364FD4036A9C25BF357DD4 \
    && gpg --batch --verify /usr/local/bin/gosu.asc /usr/local/bin/gosu \
    && rm -r "$GNUPGHOME" /usr/local/bin/gosu.asc \
    && chmod +x /usr/local/bin/gosu \
    && gosu nobody true \
    && apt-get purge -y --auto-remove ca-certificates wget

ADD entrypoint.sh /

ENTRYPOINT ["/entrypoint.sh"]

CMD /project/run.sh

точка входа.sh

#!/bin/sh

USER=dockeruser
VOLUME=/project
UID="$(stat -c '%u' $VOLUME)" && \
useradd --uid "$UID" "$USER" && \
ls -l "$VOLUME" && \
exec gosu "$USER" "$@"

запустить.ш

#!/bin/sh

echo "Running as \"$(id -nu)\""

Когда я запускаю sudo docker build -t test . && sudo docker run --rm -v /tmp/docker-test/:/project test:latest , он выводит:

total 12
-rw-r--r-- 1 dockeruser dockeruser 990 Dec 12 10:55 Dockerfile
-rwxr-xr-x 1 dockeruser dockeruser 156 Dec 12 11:03 entrypoint.sh
-rwxr-xr-x 1 dockeruser dockeruser  31 Dec 12 11:01 run.sh
Running as "dockeruser"

Кто-нибудь рассматривал этот вопрос? Убедитесь, что ваши тома имеют тот же gid и uid, что и ваши контейнеры, что затрудняет управление вашими контейнерами, чтобы не использовать root. Лучшие практики Docker рекомендуют не запускать службы с правами root, если это возможно, но не нужно ли настраивать gid и uid на хосте, а также контейнеры, чтобы победить простоту использования, которая сделала Docker популярным?

@AndreasBackx Использование томов работает только при условии, что в образе есть данные по пути, к которому вы подключаетесь.
При использовании привязок используется UID/GID пути хоста.

В настоящее время нет способа (как и при отсутствии поддержки ядра) сопоставить или изменить UID/GID файла/каталога на что-то другое без изменения оригинала, если только не использовать что-то вроде FUSE, что ужасно медленно.

Но давайте сделаем шаг назад на мгновение.
Docker на самом деле не усложняет ситуацию.
UID/GID в контейнере совпадает с UID/GID на хосте. Даже если имена пользователей/групп не совпадают, здесь важен UID/GID.
Как и без докера, вам нужно придумать uid/gid, который вы хотите использовать для своих служб, и использовать его вне соглашения.
Помните, что uid/gid не обязательно должен существовать в /etc/passwd или /etc/group , чтобы ему было присвоено право собственности на файл.

@ cpuguy83 спасибо за объяснение.

Я столкнулся с этой проблемой сегодня при создании конвейера node , UID моего хост-пользователя равен 1000, а изображение node создает пользовательского пользователя с этим конкретным UID , есть даже проблема с этим

Я бы использовал пользователя узла и пошел дальше, но он кажется немного грязным. Я действительно разделяю то, что вы написали @cpuguy83 о том, что «давайте вернемся на мгновение назад», но иногда это может стать трудно решить проблему.

Только что обнаружил опцию -o на usermod , позволяющую дублировать IDS, кажется законной опцией.

RUN usermod -o -u 1000 <user>

Непонятно, почему это не было исправлено каким-либо разумным образом.

docker run -it -u 1000:4211 -v /home/web/production/nginx_socks:/app/socks -e SOCKS_PATH=/app/socks --name time_master  time_master

войдите, чтобы увидеть:

drwxr-xr-x    8 geodocr_ geodocr       4096 Jun  4 18:51 .
drwxr-xr-x   57 root     root          4096 Jun  6 21:17 ..
-rwxrwx---    1 geodocr_ geodocr        140 Jun  4 18:49 .env
-rwxrwx--x    1 geodocr_ geodocr         78 Jun  4 18:49 entrypoint.sh
drwxrwxr-x    2 geodocr_ geodocr       4096 Jun  4 18:51 handlers
-rwxrwx---    1 geodocr_ geodocr        242 Jun  4 18:49 requirements.txt
-rwxrwx---    1 geodocr_ geodocr       1270 Jun  4 18:49 server.py
drwxr-xr-x    2 root     root          4096 Jun  6 21:00 socks
drwxr-xr-x   10 geodocr_ geodocr       4096 Jun  4 18:51 utils

dokefile специально делает

RUN adduser  -D -u 1000 $USER 
#
RUN addgroup $GROUP -g 4211 
#
RUN addgroup $USER $GROUP 
RUN mkdir /app/socks
USER $USER  
#

Нет смысла монтировать этот том как root, когда не выбран ни пользователь в контейнере, ни пользователь, запускающий команду. Я мог бы понять, монтируется ли команда RUN как пользователь, выполняющий команду, или пользователь, которому принадлежит каталог, или даже пользователь, указанный в Dockerfile.

Ни один из них не является корневым, поэтому установка с правами root кажется ошибкой.

Также только что проверил, создает том, затем монтирует его. Так что еще баг.

@disArticle Если вы хотите, чтобы путь к хосту отличался от root, вам следует изменить путь к хосту.

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

Казалось бы, здесь правильно было бы создать том с правами владения, принадлежащими USER изображения.

@jalaziz, что ему делать, если пользователь контейнера не существует на хосте? Одним из основных преимуществ контейнеров является то, что вам не нужно раскрывать их зависимости (включая пользователей) хосту.

@taybin Я ожидаю, что Docker просто создаст папку с uid:gid пользователя контейнера ИЛИ, если папка существует внутри контейнера, он создаст папку хоста с тем же uid:gid и маской.

ПРИМЕЧАНИЕ. Я не ожидаю разрешения на изменение Docker, если папка уже существует на хосте.

@taybin Точно так, как описал @frol . Он должен просто использовать uid:gid из контейнера.

Однако это показывает мою общую проблему с текущим подходом. Мне нужно знать uid, который контейнер использует для разрешения записи и установки разрешений для каталогов хоста на основе этого uid:gid. Если вышестоящий автор когда-либо изменит uid, разрешения будут нарушены. Все это кажется очень хрупким.

В моем случае у меня не обязательно был явный контроль над используемым образом Docker (я не мог просто отредактировать Dockerfile по своему вкусу).

Итак, я попробовал это:

docker run -it -u $(id -u $USER):$(id -g $USER) -v $(pwd):/src -w /src node:latest npm run build

Что создает папку с именем ./built-app . Однако владелец по-прежнему был root со строгими разрешениями.

Мой обходной путь был следующим:

docker run -it -v $(pwd):/src -w /src node:latest /bin/bash -c "npm run build; chmod -R 777 ./built-app"

У которого все еще есть владелец root , но с ослабленными разрешениями. Затем моя хост-ОС (Ubuntu) смогла получить доступ к ./built-app без привилегий sudo.

@rms1000watt Вы пробовали следующую команду?

docker run -it -v $(pwd):/src -w /src node:latest /bin/bash -c "npm run build; chown -R ${UID}:${GID} ./built-app"

Это должно работать, поскольку он будет использовать UID и GID вашего хоста непосредственно в самих файлах. Использование chmod -R 777 обычно является плохой практикой.

@saada Упс! Хороший звонок. Я попробую.

Я мог бы выполнить свой подход, прочитав это и поняв, как _UID и GID работают в контейнерах Docker_
https://medium.com/@mccode/understanding-how-uid-and-gid-work-in-docker-containers-c37a01d01cf

По сути, есть одно ядро ​​​​и один общий пул uid и gid, что означает, что корень вашей локальной машины такой же, как корень вашего контейнера, они оба имеют один и тот же UID


У меня есть сервер apache, и я хочу поделиться своими файлами webapp с контейнером apache, чтобы изменить его на хосте (разработка, изменить их с помощью текстового редактора) и просмотреть результаты процесса, запущенного в контейнере. Иногда этот процесс, запись новых файлов, и если я не изменю поведение по умолчанию с привилегиями, файлы генерируются пользователем root, и мой локальный пользователь больше не может их изменять.

Что я сделал, так это сгенерировал собственное изображение, добавив это в свой файл докеров:

RUN adduser -D -u 1002 dianjuar -G www-data
USER dianjuar

Возможно, чтобы сделать мой docker-compose.yml переносимым, чтобы его мог использовать любой, нужно задать некоторые параметры процесса сборки.

Вот шаблон контейнера для назначения идентификатора пользователя/группы во время выполнения таким образом, чтобы его можно было легко перенести. https://github.com/Graham42/mapped-uid-докер

Путь, которым я следовал:

1- создайте каталог на хост-сервере
2- измените его разрешения на пользователя с идентификатором пользователя и идентификатором группы = 1000
3- запустить docker-compose up
контейнер проверил, все в порядке.

Примечание. Я использовал пользователя root на хост-сервере, и я предполагаю, что если бы я использовал пользователя без полномочий root с uid = 1000, я смог бы смонтировать том, не беспокоясь о разрешении, но я еще не проверял это. Кто-нибудь следовал подобному пути?

Типичная проблема:

  • docker swarm, поэтому CAPP_ADD недоступен, bind-mount не является решением
  • два контейнера двух разных образов используют один и тот же том, поэтому разные базы данных пользователей/групп на обоих
  • например надо иметь права доступа к www-данным (т.е. давайте зашифруем загрузчик сертификатов)
  • другой также использует www-данные (т.е. nginx)
  • но третий требует доступа от пользователя openldap (т.е. сервера openldap)
  • такой простой chmod ist тоже не решение

Это означает, что у меня есть веб-сервер, который получает SSL-сертификаты для своих доменов от let's encrpt, и сервер OpenLDAP для того же домена, где я хочу повторно использовать сертификаты.

Есть и другие комбинации, которые сталкиваются с точно такой же проблемой.

Любая идея, как это решить?

Как бы вы решили это без Docker? Это не специфично для Docker
проблема.

В пятницу, 12 января 2018 г., в 10:24, Марк Векерлин, [email protected]
написал:

Типичная проблема:

  • docker swarm, поэтому CAPP_ADD недоступен, bind-mount не является
    решение
  • два контейнера двух разных изображений имеют один и тот же объем, поэтому
    разные базы данных пользователей/групп на обоих
  • например надо иметь права доступа к www-данным (т.е. давайте зашифруем
    загрузчик сертификатов)
  • другой также использует www-данные (т.е. nginx)
  • но третий требует доступа от пользователя openldap (т.е. openldap
    сервер)
  • такой простой chmod ist тоже не решение

Это означает, что у меня есть веб-сервер, который получает SSL-сертификаты для своих доменов.
от let's encrpt и сервер OpenLDAP для того же домена, где я хочу
для повторного использования сертификатов.

Есть и другие комбинации, которые сталкиваются с точно такой же проблемой.

Любая идея, как это решить?


Вы получаете это, потому что вас упомянули.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/moby/moby/issues/2259#issuecomment-357267193 или отключить звук
нить
https://github.com/notifications/unsubscribe-auth/AAwxZgyvdCwGGVkUqCxK9nDFw1zxSKjUks5tJ3kXgaJpZM4BGxv9
.

--

  • Брайан Гофф

Даже без swarm я смог решить это в докере: bind-mount.

Это проблема, связанная с роем докеров, потому что CAP_ADD отсутствует.

Крепления привязки @mwaeckerlin не могут сопоставляться с разными идентификаторами пользователей.
Но даже с роем можно привязать mount... зачем нужен CAP_ADD?

Без CAP_ADD монтирование внутри докера не выполняется.

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

  • создать группу с явно заданным общим идентификатором группы во всех файлах Dockerfiles
  • дать права группе

@mwaeckerlin Зачем вам нужно монтировать внутри контейнера?

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

Идея, указанная выше, заключалась в следующем: Bind-mount внутри контейнера, затем chown на цели не должен менять источник.

@mwaeckerlin Если вы измените это, оно изменится везде. В этом суть проблемы в данном вопросе.
Chowning/Chmoding файла/каталога, смонтированного привязкой, меняет оба места.

Также нет необходимости иметь возможность монтировать внутри контейнера, вы можете --mount type=bind,source=/foo,target=/bar

Да, я только что проверил это вне докера, так что идея выше неверна.

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

Вот что-то вроде этого, по крайней мере, помогло бы в некоторых случаях: --mount type=bind,source=/foo,target=/bar,user=me,group=mine

Любые рекомендации или лучшие практики по этой теме: пользователь общего тома разными пользователями в разных образах в рое докеров?

  1. Не делитесь томами
  2. Синхронизируйте свои uid/gids
  3. Убедитесь, что разрешения достаточны для всех, кто делится
  4. Используйте плавкие предохранители на хосте для привязки к разным uid/gid для каждого контейнера.

Можно поподробнее по пункту 4?
Может быть, практический пример того, как это сделать?

Пт, 12 января 2018 г., 17:27 Брайан Гофф, уведомления@github.com написал:

>

  1. Не делитесь томами
  2. Синхронизируйте свои uid/gids
  3. Убедитесь, что разрешения достаточны для всех, кто делится
  4. Используйте плавкие предохранители на хосте для привязки к разным uid/gid для каждого
    контейнер


Вы получаете это, потому что подписаны на эту тему.
Ответьте на это письмо напрямую, просмотрите его на GitHub
https://github.com/moby/moby/issues/2259#issuecomment-357282169 или отключить звук
нить
https://github.com/notifications/unsubscribe-auth/AHSjvgjb0BFbJhZ1VWM-pLGfa7tRBvDNks5tJ4VPgaJpZM4BGxv9
.

Используя что-то вроде https://bindfs.org/ — есть даже по крайней мере один плагин тома Docker, который уже реализует его (https://github.com/lebokus/docker-volume-bindfs — это первый результат, который я нашел через Google) .

я не могу изменить разрешение после установки тома, это кто-нибудь получил?

обходной путь:
Добавляем это в Dockerfile
RUN echo "if [ -e container_volume_path ]; then sudo chown user_name container_volume_path; fi" >> /home/user_name/.bashrc
Владелец container_volume_path изменяется после монтирования тома.

Возможность сопоставления uid и gid кажется таинственным недостающим элементом для обработки томов докеров. Путь наименьшего удивления состоял бы в том, чтобы включить его, а предлагаемые исправления неуклюжи и трудны для обнаружения, но при этом не дают преимуществ передового опыта:

Ре:
1) Не делитесь томами

  • Хорошо, но несущественно для обсуждения сопоставления uid/gid
    2) Синхронизируйте свои uid/gids
  • Это то, для чего предназначена функциональность, но без форсирования chown в Dockerfile.
    3) Убедитесь, что разрешения достаточны для всех, кто делится
  • Это снова зависит от поведения, определенного в Dockerfile, когда это может быть простое сопоставление.
    4) Используйте крепления предохранителей на хосте, чтобы связать разные uid/gid для каждого контейнера.
  • Хороший совет, это тоже похоже на стрижку яка.

@колбигк

когда это может быть простое сопоставление

В том-то и проблема, что невозможно сделать "простое сопоставление", так как оно не поддерживается на уровне vfs.
Некоторые файловые системы предоставляют возможность сопоставления владельцев (например, bindfs или nfs), но реализация этого в общем случае в настоящее время невозможна.

Мне нужны общие тома, например, в следующей ситуации:

Общие сертификаты

  • контейнер 1 — это обратный прокси-сервер, который обрабатывает let’s encrypt для всех размещенных доменов.
  • контейнер 2 — это сервер ldap, которому также необходимо предоставить сертификат своего домена.

решение: контейнер образа 2 наследуется от того же образа, что и контейнер 1, общий базовый образ создает общую группу, тогда оба контейнера имеют одинаковый групповой доступ

Dockerfile общего основания :

RUN groupadd -g 500 ssl-cert

letsencrypt-config.sh в зашифрованном изображении :

chgrp -R ssl-cert /etc/letsencrypt

Dockerfile mwaeckerlin/reverse-proxy :

RUN usermod -a -G ssl-cert www-data

Dockerfile из mwaeckerlin/openldap :

RUN usermod -a -G ssl-cert openldap

Вот и все.

Все это иллюстрирует, как изменить userperms во время точки входа или во время процесса сборки, чтобы весь докер работал под другим пользователем.

Но, возможно, я упустил важный момент после поиска в Интернете за последние 3 дня.
Ни одна из приведенных выше или иным образом связанных рекомендаций и (обходных путей) не будет работать никоим образом.

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

Я не могу отделаться от ощущения, что я глуп, пытаясь сделать что-то очень простое - с моей точки зрения.

  • Windows 10 Профессиональная 1803 (17134.112)
  • Докер для Windows 18.03.1-ce-win65 (17513)
  • Windows WSL с Hyper-V и Ubuntu

Попытка запустить простой контейнер apache2, в котором корень документа подключен к хосту, поэтому я могу разрабатывать исходный код php и сразу же тестировать его в контейнере докеров.

root<strong i="16">@win10</strong>:# docker run --rm -v /c/Users/<MyUser>/Development/www-data:/var/www/html -it httpd:2.4 /bin/bash

Внутри контейнера докера директория _/var/www/html_ всегда принадлежит _ root:root_ , поэтому мое php-приложение никогда не сможет открываться или записывать какие-либо данные внутри этой папки.
Пока ничего не получилось... :(

Для тех, кто ищет достаточно элегантное решение, ознакомьтесь с тем, что предложил @elquimista здесь . Я проверил это и работает хорошо

Мы успешно использовали https://github.com/boxboat/fixuid#specify -paths-and-behavior-across-devices. Кроме того, он настраивает пользователя внутри контейнера в соответствии с пользователем на хосте.

Вот пример конфигурации с изображения:

$ cat /etc/fixuid/config.yml
user: lion
group: lion
paths:
  - /home/lion
  - /home/lion/.composer/cache
  - /tmp

и запустить:

$ docker run --rm -it --init \
    -u 1000:1000 \
    -v `pwd`:/app \
    -v "$HOME/.composer/cache:/home/lion/.composer/cache" \
    --entrypoint='fixuid' \
    php:7.2-cli \
        /bin/bash

Обратите внимание, что это также раздражает при использовании систем хранения, которые не поддерживают разрешения и права собственности unix. В этом случае монтирование хранилища должно быть выполнено так, чтобы оно получило правильный uid для использования внутри контейнера, потому что любая попытка chown файлов просто терпит неудачу. Если бы был способ сообщить докеру, что файлы принадлежат определенному uid, независимо от владения за пределами контейнера, это упростило бы ситуацию.

@tlhonmey

Если бы был способ сообщить докеру, что файлы принадлежат определенному uid

Нет, не без пользовательской файловой системы (например, как bindfs).

@tlhonmey Да, мне удалось обойти проблему «систем хранения, не поддерживающих разрешения unix» с помощью некоторых символических ссылок.

По сути, при монтировании с дисков NTFS я помещал вещи в -v ./HostNtfsStuff:/data/ntfsMount , а затем делал символическую ссылку и chown, что ln -s -T /data/ntfsMount /var/lib/myApp && chown -Rh myApp:myApp /var/lib/myApp/

Вы тоже можете протестировать: su myApp -c 'echo foo > /var/lib/myApp/bar' && cat /data/ntfsMount/bar

Мое использование заключалось в том, чтобы разработчики Windows могли запускать контейнеры MySQL и сохраняться на подключенных томах, но это применимо ко многим приложениям.

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

Есть _один_ способ заставить это работать, но вам нужно заранее подготовиться в вашем Dockrfile.

RUN mkdir -p /var/lib/redis ; chown -R redis:redis /var/lib/redis
VOLUME ["/var/lib/redis"]
ENTRYPOINT ["usr/bin/redis-server"]
USER redis

(Я не тестировал этот пример, я работаю над контейнером хрома, который затем отображается в контейнере _separate_ X11, который ....)

Я использовал последний метод до сегодняшнего дня, когда я попытался связать том контейнера, и он сломался. По-видимому, вы не можете этого сделать. Том создается как root, а затем приложение внутри не может писать на него как пользователь. Автозаполнение, описанное в документации VOLUME , похоже, также не работает с монтированием привязки.

Я видел это, читая Dockerfile Best Practices , и вспомогательный скрипт - это то, что они рекомендуют:

#!/usr/bin/env bash
set -e

if [ "$1" = 'postgres' ]; then
    chown -R postgres "$PGDATA"

    if [ -z "$(ls -A "$PGDATA")" ]; then
        gosu postgres initdb
    fi

    exec gosu postgres "$@"
fi

exec "$@"

Итак, рекурсивный chown, чтобы убедиться, что у вас есть право собственности при каждом запуске, а затем запустите свое приложение от имени пользователя. exec также включает PID 1, поэтому сигналы работают. И если я хочу заполнить том чем-то вроде вспомогательного сценария для использования вне контейнера с результирующими данными, он, вероятно, также должен быть включен во вспомогательный сценарий. Интересно, однако, есть ли снижение производительности при запуске контейнера, если ваше приложение хранит тонны файлов на томе, особенно если хранилище не является локальным.

Кажется, что может быть лучшее решение. Может быть, что-то вроде сопоставления uid и gid контейнера с указанным именем пользователя и группой на хосте. Может ли докер заглянуть в /etc контейнера и понять это?

Вы не можете отображать uids/gid на уровне файловой системы, по крайней мере, без предохранителя.

Вы не можете отображать uids/gid на уровне файловой системы, по крайней мере, без предохранителя.

Вроде того, чего я опасался. Есть идеи, как может снизиться производительность, если докер использует такой предохранитель?

@mdegans

Итак, рекурсивный chown, чтобы убедиться, что у вас есть право собственности при каждом запуске,

Вам не нужно делать chown при каждом запуске. Вместо этого проверьте владельца каталога данных и выполните рекурсивную операцию chown только в том случае, если она неверна. Нравится:

 [ $(stat -c %U "$PG_DATA") == "postgres" ] || chown -R postgres "$PG_DATA"

Так что в идеале это произойдет только при первом запуске.

И будьте очень осторожны при запуске контейнера с таким сценарием точки входа; если вы смонтируете (например) свой домашний каталог в контейнер, все ваши файлы будут переданы в postgres

В хорошем дизайне образа Docker пользователь времени выполнения не является пользователем root и, следовательно, не может chown файлы …!

В хорошем дизайне образа Docker пользователь среды выполнения не является пользователем root и, следовательно, не может chown файлов…!

Правильно, но ничто не должно мешать переключению на root и обратно, что часто требуется... точно так же, как вы обычно не должны запускать что-либо как root , пока оно вам не понадобится, но когда вы это сделаете, вы можете сделать одно или несколько из следующих действий:

  • sudo
  • su
  • USER root

Согласно: https://f1.holisticinfosecforwebdevelopers.com/chap03.html#vps-countermeasures-docker-the-default-user-is-root

По моему скромному мнению, пользователь образа Docker должен убедиться, что он/она правильно установил разрешение на смонтированном томе.

Это очень похоже на то, что мы делали традиционно до появления контейнеров, например, когда я хотел запустить nginx и мне нужно было убедиться, что каталог статического HTML принадлежит нужному пользователю. Чтобы узнать, что мне нужно открыть файл nginx.conf, проверить пользователя рабочего и установить соответствующие разрешения. Собственно, это все было описано в документации nginx.

Это просто проблема с разрешениями Unix, ничего нового в Docker здесь нет. Так что, возможно, решение этой проблемы заключается в лучшей документации для каждого образа Docker о том, что должно принадлежать смонтированным томам. Я не помню, чтобы демон запуска nginx проверял правильность владения каталогом, он просто потерпел бы неудачу, если бы он не был правильно настроен.

Однако это правда, потому что теперь у нас есть пользователи, потенциально определенные внутри контейнера, а не снаружи, что заставляет вещи выглядеть по-другому (а это не так). Но UID внутри и снаружи эквивалентны, поэтому пользователь foobar с UID 2000 может существовать внутри контейнера, а не снаружи, но UID 2000 по-прежнему можно установить для файлов и каталогов снаружи. Мы должны изменить свое мышление в терминах UID/GID, а не в терминах понятных человеку имен, с которыми мы привыкли иметь дело.
Это также потенциально усложняет ситуацию, если вам нужно разделить том между двумя контейнерами, написанными двумя разными авторами. Возможно, установка разрешений с использованием традиционной системы Unix (пользователя, группы и т. д.) недостаточна для решения проблемы (отсутствие общего UID или GID). Я признаю, что, поскольку я использую Docker, я гораздо чаще использую POSIX ACL. Поэтому я могу назначить 3 разных разрешения для одного и того же файла. например, контейнерный писатель с разрешением rw, контейнерный читатель с разрешением r и хост-пользователь с разрешением r.

Еще один вариант: общий GID может быть применен с помощью флага setgid для общих каталогов. Маска файла может быть применена с помощью ACL.

Прежде чем что-либо делать в контейнере Docker, запустите:

```
umask 0000
````

https://en.wikipedia.org/wiki/Умаск

Опоздал в эту ветку, чтобы подтвердить, насколько полезной будет эта функция.

Честно говоря, я развертываю контейнеры уже около года и вижу, что это повсеместно становится настоящей проблемой. Предоставление решения на этом уровне здесь кажется единственным разумным выбором.

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

Настоящая проблема возникает, когда вы понимаете, что не каждый может прибегнуть к этой практике. Для некоторых популярных платформ, таких как Kubernetes или OpenShift, некоторые из этих сред могут быть настроены так, чтобы не разрешать привилегированные контейнеры... из-за... безопасности. У меня даже в голове не укладывается, как крупное финансовое учреждение может даже подумать о внедрении контейнерной платформы, обрабатывающей конфиденциальную информацию, без такого рода ограничений.

Проблемы безопасности, связанные с практикой _entrypoint-as-root_, привели к тому, что большое количество диаграмм управления Kubernetes предоставили initContainers , которые могут chown и chmod тома до запуска контейнера приложения. . Это может показаться хорошим решением, но поверьте мне: это не так .

В частности, диаграммы Helm замусорены жестко закодированными uids и gids , потому что их нужно тайно вырвать из среды выполнения приложения. Эта информация скрыта внутри контейнера и недоступна сразу во время развертывания.

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

Я надеюсь, что есть способ реализовать это как часть спецификации OCI, чтобы другие решения, зависящие от Docker, могли использовать его для элегантного полностью автоматизированного развертывания.

Итак, возникает вопрос: где еще в Интернете они разрабатывают общую спецификацию OCI, где следует провести это обсуждение? Предполагая, что это не лучший способ добавить эту функцию в докер (в конечном итоге, через требование соответствия будущему общепринятому принятию стандартов).

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

initContainers, которые могут chown и chmod тома до запуска контейнера приложения. Это может показаться хорошим способом, но поверьте мне, когда я говорю это: это не так.

ПВЖ; эта функция потребуется только в ситуациях, когда файлы совместно используются несколькими пространствами имен (либо файлы (предварительно) существующие на «хосте», либо общее расположение файлов, совместно используемое несколькими контейнерами, работающими от имени разных пользователей). В ситуациях, когда файлы предварительно создаются на хосте, это можно смягчить, убедившись, что у этих файлов есть правильные права собственности и разрешения, прежде чем делиться ими с контейнером. По сути, это ничем не отличается от (например) запуска nginx на хосте и проверки того, что файлы в корневом каталоге имеют правильные разрешения.

При совместном использовании между контейнерами, запущенными от имени другого пользователя, либо запустите оба контейнера с одним и тем же uid (или gid , и установите правильные групповые разрешения, аналогично тому, как это будет работать при запуске двух неконтейнерные процессы, которым необходим доступ к одним и тем же ресурсам).

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

Просто, чтобы предотвратить путаницу; контейнер, работающий как root , отличается от «привилегированного» контейнера ( --privileged или параметров, таких как набор --cap-add ). Привилегированные ( --privileged ) контейнеры очень небезопасны, в то время как контейнер, работающий как root , полностью изолирован и не сможет выйти из строя ; передача ему файлов/каталогов, смонтированных привязкой, пробивает в этом дыры, поэтому _будет_ предоставлять ему доступ к файлам/каталогам, которые вы передаете в качестве привязки.

В частности, Helm-чарты замусорены жестко запрограммированными идентификаторами uid и gid, потому что их необходимо тайно извлечь из среды выполнения приложения. Эта информация скрыта внутри контейнера и недоступна сразу во время развертывания.

Интересно: если эти uids/gids неизвестны; как будет выглядеть UX? (поскольку мне нужно будет предоставить сопоставление uid/gid для сопоставления uid/gid хоста с (неизвестным) container-uid/gid?

Итак, возникает вопрос: где еще в Интернете они разрабатывают общую спецификацию OCI, где следует провести это обсуждение?

Я не думаю (на первый взгляд), что необходимо изменение спецификации OCI; это может быть решено вне спецификации OCI; основная проблема заключается в том, что механизмы сопоставления uid/gid в настоящее время отсутствуют в ядре (или существуют (например, shiftfs ), но не являются общедоступными)

Это классический пятиугольник перехода ответственности / кто-то другой может или должен решить эту проблему. Либо это:

  • Пользователь
  • Конкретная реализация платформы Docker/контейнеризации
  • Спецификация OCI
  • ядро
  • Файловая система

Проблема уже была четко сформулирована: заставлять пользователя делать это неуклюже и менее безопасно. Однако эффект домино, когда пользователи взламывают изображения, также важен:

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

  • Ломает общий доступ к сообществу (довольно много). Поскольку разные пользователи определяют из одного и того же глобального пула пространств имен свои uid и gid для своих индивидуально разработанных образов.
  • Заставляет пользователей разрабатывать свой собственный специальный стандарт и надеяться, что другие будут следовать соглашению, которое они сами выбрали.
  • Заставляет пользователей использовать root для всего. Что наверняка менее безопасно. Потому что вы убираете дополнительный уровень привилегированной защиты от эскалации, который в противном случае был бы у вас. И значительно упрощает использование уязвимостей взлома контейнера, поскольку пользователь уже находится root внутри контейнера с самого начала. Не говоря уже о возможности запускать другие сервисы в том же контейнере, что также является еще одним способом уйти в сторону, прежде чем подниматься.

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

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

https://github.com/docker/compose/issues/3270#issuecomment-365644540

В котором есть несколько разных ссылок на эту же общую функцию (в другой проект / места), в том числе на распределенную файловую систему (известную как «Lustre») и другие проблемы, связанные с ZFS. Ну, так получилось, что я сам здесь использую ZFS.

Потом также нашел еще один экземпляр такого же бага на ubuntu/launchpad. Ссылаясь на ту же проблему ZOL # 4177,

https://bugs.launchpad.net/ubuntu/+source/zfs-linux/+bug/1567558

В котором говорится, что рассматриваемая ошибка была исправлена ​​​​в версии zfs 0.6.5.7+ SO. Означает ли это, что потенциально мы можем использовать zfs и ACL в качестве своего рода резервного хранилища для переназначения uid и gid? Ну, это не то, о чем я слышал раньше.

О, может быть, это решение работает только для контейнеров LXC. Потому что он также говорил в своих комментариях (руководитель проекта LXC), «мы используем помощники setuid (newuidmap и newgidmap)», которые затем могут «настроить карту uid и gid». Так что, по-видимому, в самом LXC также есть какой-то необходимый механизм, иначе часть zfs acls не может быть использована? Или, возможно, я ошибаюсь. Я не совсем уверен, что следую этому до конца.

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

Однако что произойдет, если функция переназначения будет реализована в overlayfs , но вместо этого я хочу использовать драйвер хранилища zfs для своей базовой файловой системы? Должен ли я быть лишен возможности переназначать uid/gid, если это реализуется для каждой файловой системы? Или мы можем реализовать оба по отдельности? Извините, мне немного неясно, должен ли демон Docker знать о таких переназначениях и предоставлять общий API и флаги (для передачи на уровень драйверов fs). Или если бы мы вместо этого сами выполняли такое переназначение вручную на стороне хоста (в файловой системе, вне докера). Этот аспект также остается для меня немного неясным.

[EDIT] ой, забыл добавить ссылку! Вот

https://lists.linuxfoundation.org/pipermail/containers/2018-June/039172.html

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

Мы бы использовали overly со смещением uid/gid для bindmount, если бы оверлей включал функции shiftfs, но нам пришлось бы откатиться на что-то другое (или ничего) в неподдерживаемых системах.

Podman — это замена Docker без рута https://www.youtube.com/watch?v=N0hSn5EwW8w https://podman.io/ . В podman root не используется, поэтому права пользователя обрабатываются правильно. Наша команда перешла на Podman из-за этой проблемы и работала очень хорошо.

Это не имеет никакого смысла.
Применяются те же проблемы.
Обратите внимание, что у докера также есть режим без рута.

Вы можете протестировать Podman с помощью следующих команд. У Podman нет отдельного демона в отличие от Docker, и все работает под пользователем, выполняющим команды podman . Таким образом, файлы, созданные внутри podman, принадлежат пользователю, выполнившему команду podman run ... .

kkimdev<strong i="8">@ubuntu</strong>:~$ mkdir podman_test
kkimdev<strong i="9">@ubuntu</strong>:~$ ls -agh podman_test
total 8.0K
drwxrwxr-x 2 kkimdev 4.0K Jun 27 04:23 .
drwxr-xr-x 8 kkimdev 4.0K Jun 27 04:23 ..

kkimdev<strong i="10">@ubuntu</strong>:~$ podman run --rm -it -v ~/podman_test:/podman_test alpine
/ # cd /podman_test/
/podman_test # touch test_file
/podman_test # ls -agh
total 8K
drwxrwxr-x    2 root        4.0K Jun 27 02:24 .
drwxr-xr-x   20 root        4.0K Jun 27 02:24 ..
-rw-r--r--    1 root           0 Jun 27 02:24 test_file

/podman_test #

kkimdev<strong i="11">@ubuntu</strong>:~$ ls -agh podman_test/
total 8.0K
drwxrwxr-x 2 kkimdev 4.0K Jun 27 04:24 .
drwxr-xr-x 8 kkimdev 4.0K Jun 27 04:23 ..
-rw-r--r-- 1 kkimdev    0 Jun 27 04:24 test_file

Это неподходящее место для рекламы podman — если есть конкретные технические подробности о том, как это работает, которые могут помочь решить эту проблему, они будут уместны для обсуждения, особенно в качестве потенциальных решений проблемы, которую вы хотите решить. в настоящее время комментирует. До сих пор это было не так, поэтому, пожалуйста, перенесите это обсуждение в другое место.

Тот факт, что podman имеет совершенно другую архитектуру, чем Docker, что делает эту проблему менее серьезной/болезненной, не позволяет волшебным образом Docker полностью изменить способ его работы только для решения этой единственной проблемы. Я могу заверить вас, что существует множество причин, по которым Docker устроен именно так, и игнорировать всю эту историю — откровенно недобросовестно.

@tianon Да, абсолютно, у обоих подходов есть свои плюсы и минусы. Я упомянул podman только потому, что запуск контейнера с podman с целевым пользователем специально решает эту техническую проблему, а именно «монтирование тома от имени пользователя, отличного от root».

Пожалуйста, взгляните на разрешение «test_file», созданное в моем комментарии выше. Сначала он монтирует каталог «~/podman_test» и записывает файл «test_file» внутри контейнера podman. Затем, как только пользователь выйдет за пределы контейнера, вы увидите, что файл принадлежит «kkimdev», а не root.

Проблема в том, что ваше предложение решить проблему с Docker состоит в том, что оно означает «не использовать Docker», что не очень конструктивно в системе отслеживания проблем для Docker.

Да, podman разработан по-другому, что делает этот вопрос спорным для этого инструмента — это хорошо и хорошо, но здесь совершенно не по теме. У Rootless есть разные компромиссы, некоторые из которых подходят для некоторых людей, а некоторые нет. Со временем это становится лучше (и в основном улучшения ядра), но это не универсальное решение для всех здесь.

Для этого требуются либо модификации ядра, либо прокладка для общего решения, как подробно обсуждалось выше (и поскольку @cpuguy83 и другие работали над тем, чтобы помочь решить эту проблему общим способом).

В Docker эта конкретная проблема была открыта с 2013 года, и почти шесть лет спустя легкого улучшения не предвидится. Podman был разработан для обеспечения совместимости с Docker, но также для устранения недостатков дизайна Docker (включая работу в качестве непривилегированного пользователя, для которого не требуется демон Docker с правами суперпользователя).

Если пользователи могут дать другим совет по проблеме GitHub, это совершенно нормально. Это сообщество. Не стесняйтесь рекомендовать все, что может быть полезно.

Я могу заверить вас, что есть много причин, по которым Docker устроен именно так.

Так и grep . Но если кому-то нужно искать быстрее, я бы все равно рекомендовал ripgrep . Даже на трекере grep . Неважно, чей это трекер проблем, если он решает проблемы пользователей и делает их счастливыми.

Если Podman не работает для вас: хорошо! Но если помогает другим, потому что им просто нужно заменить docker на podman в своей инфраструктуре: просто позвольте им это сделать.

Главный аргумент Podman заключается в том, что он не запускает демона, и это мой главный аргумент против него. Как восстановить контейнер после перезагрузки? Я не буду делать это вручную, а все остальное просто плохой дизайн. Также я не хочу, чтобы мой док-контейнер принадлежал пользователю, но принадлежал системе, а это означает root.
Podman имеет смысл, если вы единственный, кто его использует.

И чтобы решить вашу проблему: создайте контейнер с COPY --chown ...:... !

Также у Docker таких проблем нет и можно удаленно управлять docker серверами, что для меня тоже немаловажно.

Существуют инструменты для создания модулей из запущенных контейнеров, которые я не буду рекомендовать, потому что вы должны создавать их с нуля чистым способом.

Я думаю, мы должны вернуться к теме сейчас: ИМХО, первый совет был в порядке, но все остальное только раздувает эту проблему и ничего не решит.


@SuperSandro2000 , вы можете нажать здесь, чтобы получить ответ на ваши заявления.

Как восстановить контейнер после перезагрузки? Я не буду делать это вручную, а все остальное просто плохой дизайн.

Что ж, Podman имеет встроенную интеграцию с systemd (как почти все остальное почти во всех современных дистрибутивах GNU Linux). Таким образом, вам не нужно поддерживать «две» загрузочные системы (например, сначала иметь systemd для запуска демона Docker, который затем должен сделать еще один раунд запуска контейнеров в другой конфигурации). Таким образом, с Podman вы можете контролировать все с помощью systemd (имеется в виду: система, которую вы, скорее всего, уже установили и все равно используете).

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

Это совершенно нормально, если вы этого не хотите. Вы по-прежнему можете запускать Podman как суперпользователь, но вам больше не нужно это делать. В общем, это считается плохой идеей и увеличивает поверхность атаки, потому что, если кто-то сможет использовать ваш демон Docker, он получит контроль над _всем_ в системе.

Podman имеет смысл, если вы единственный, кто его использует.

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

И чтобы решить вашу проблему: создайте контейнер с COPY --chown ...:... !

ИМХО, проблема здесь заключается в _монтировании_ тома для контейнера в _runtime_. Что имеет мало общего с построением имиджа.

Также у Docker таких проблем нет и можно удаленно управлять docker серверами, что для меня тоже немаловажно.

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

Чтобы было ясно, вы должны быть в состоянии получить тот же эффект от докера без рута, что и от podman.
Это связано с тем, что dockerd работает как ваш пользователь, а корень в контейнере сопоставляется с вашим UID.

Это имеет недостатки и, конечно, не работает при совместном использовании демона несколькими пользователями.
https://get.docker.com/rootless

27 июня 2019 г., в 7:52, Александр Адам, [email protected] , написал:

Я думаю, мы должны вернуться к теме сейчас: ИМХО, первый совет был в порядке, но все остальное только раздувает эту проблему и ничего не решит.

@SuperSandro2000 https://github.com/SuperSandro2000 , вы можете щелкнуть здесь, чтобы получить ответ на ваши заявления.
https://podman.io/blogs/2018/09/13/systemd.html https://osric.com/chris/accidental-developer/2018/12/docker-versus-podman-and-iptables/ https:/ /osric.com/chris/accidental-developer/2018/12/используя-докер-для-получения-рут-доступа/

Вы получаете это, потому что вас упомянули.
Ответить на это сообщение непосредственно, просматривать его на GitHub https://github.com/moby/moby/issues/2259?email_source=notifications&email_token=AAGDCZXX2UQCG7LUVH57V6LP4TH2DA5CNFSM4AI3DP62YY3PNVWWK3TUL52HS4DFVREXG43VMVBW63LNMVXHJKTDN5WW2ZLOORPWSZGODYXL2XI#issuecomment-506379613 или приглушить нить https://github.com/notifications/ отписаться от подписки/AAGDCZX437HJP4M6XG3SEY3P4TH2DANCNFSM4AI3DP6Q .

@александрадам

ИМХО, проблема здесь заключается в установке тома для контейнера во время выполнения. Что имеет мало общего с построением имиджа.

Мое решение состояло в том, чтобы не монтировать каталог, а запечь его в контейнере, если это возможно.

Я имею в виду, что podman звучит хорошо, но я не буду менять его, потому что пока не вижу для себя никаких преимуществ. Спасибо за объяснение в любом случае.

podman страдает от той же проблемы, если Apache внутри контейнера запускается под пользователем www . https://github.com/containers/libpod/issues/3990

Решением может быть сопоставление пользователя www из контейнера с UID на хосте, если внутри контейнера нет пользователя root . Я не знаю, возможно ли это.

Если вы хотите работать с --read-only (чтобы сделать то же самое, что и с политикой readOnlyRootFilesystem Kubernetes), можно сделать следующее. Он основан на обходном пути, предложенном @jpetazzo :

  • Мой образ докера создает и использует пользователя с uid=1001 и gid=1001.
  • Отдельно создайте том докера
  • Указать uid:gid на 1001
  • Смонтируйте этот образ при запуске приложения.

Докерфайл:

FROM ubuntu

RUN groupadd -g 1001 appgroup && \
    useradd -u 1001 -g appgroup appuser

USER appuser

Потом:

$ docker build . -t test
$ docker volume create somedir
$ docker run -v somedir:/some_dir alpine chown -R 1001:1001 /some_dir

Теперь при запуске образа докера и монтировании тома /some_dir принадлежит нужному мне пользователю.

$ docker run -it --read-only -v somedir:/some_dir test ls -lrt

...
dr-xr-xr-x  13 root    root        0 Nov  4 15:22 sys
drwxr-xr-x   2 appuser appgroup 4096 Nov  5 09:45 some_dir
drwxr-xr-x   1 root    root     4096 Nov  5 09:45 etc
...

$ docker run -it --read-only -v somedir:/some_dir test touch /some_dir/hello
$ docker run -it --read-only -v somedir:/some_dir test ls -lrt /some_dir

-rw-r--r-- 1 appuser appgroup 0 Nov  5 09:52 hello

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

https://github.com/moby/moby/issues/2259#issuecomment-466094263

+1

Я думаю, что на данный момент это самая раздражающая проблема, с которой я сталкиваюсь с докером, и, видя, как долго он уже открыт, можно предположить, что это не относится ко многим другим?

Это не проблема, если вы знаете обходной путь. Мои кейсы:

  • Хост - Linux

    • uid в контейнере == желаемый uid на хосте — обходной путь не требуется
    • uid в контейнере != желаемый uid на хосте - просто запустите пару команд setfacl и предоставьте доступ rw как пользователю хоста, так и пользователю контейнера
  • Хост - MacOS - все работает из коробки для официального приложения Docker.

просто запустите пару команд setfacl и предоставьте rw доступ как для пользователя хоста, так и для пользователя контейнера

Это проблема. Я не хочу запускать пару команд setfacl для каждого образа докера и определять ОС.

На самом деле это также огромная проблема безопасности.

Пример сценария:

  • В host1 установлен докер
  • host1 имеет несколько служб, работающих в док-контейнерах, все из которых монтируют локальные пути под /docker/my-service-01|02|03|etc
  • каждый контейнер был создан разными поставщиками, и каждый из них следует своей собственной политике uid и guid , что требует от вас соответственно chown -R uid.gid /docker/my-service-01... .

Результат:

  • В какой-то момент обычные или служебные пользователи, созданные на host , получат полный доступ к /docker/my-service-01|02|03|etc , что нежелательно и нежелательно.
  • Если вы хотите смонтировать том как "только для чтения" на двух контейнерах от разных производителей - это не удастся, так как uid.gid не будут соответствовать требуемым, и вы не сможете chown потому что у каждого контейнера своя политика uid.gid и они разные :)

Да, мы подробно обсуждали эту проблему ранее, и ключевым фактом, о котором сообщалось (в то время), было то, что ядро ​​Linux не имело базового поддерживающего механизма для предоставления переназначаемых uid и gid. Таким образом, необходимо добавить в ядро, чтобы этот проект (moby/docker) реализовал эту очень желательную функциональность. В противном случае мы бы уже получили эту функцию некоторое время назад. Когда его впервые посмотрели.

Таким образом, наиболее продуктивным способом продолжить это обсуждение (сегодня) было бы следующее: Посмотреть, не изменилось ли что-либо в этой ситуации с тех пор. Поищите технический комментарий от основных разработчиков ядра Linux на vger.org. Ищите прошлые наборы исправлений / запросы на слияние в ядре для этой базовой отсутствующей функции. и Т. Д.

В надежде на лучшее понимание того, что происходит на этом более низком уровне. Что стало камнем преткновения? Это была проблема с производительностью? Было ли это возражением с точки зрения модели безопасности/ослабления? Это все еще на столе или в будущей дорожной карте, но имеет смысл только после того, как другие функции B и C могут быть реализованы? Вся эта разработка ядра продолжается в другом месте. В других каналах.

@DXist Тот факт, что это волшебным образом работает на OSX, а не на Linux, удивителен и сам по себе является проблемой.

Согласно последнему комментарию @dreamcat4 , кто-нибудь предпринял новую попытку узнать, каков этот статус? Есть ли в ядре поддержка переназначаемых uid и gid? Каково общее состояние здесь?

Я использовал пространства имен пользователей Linux, чтобы решить эту проблему. Работает точно так же (AFAICT), как и на других платформах (контейнер видит подключенный том как root, хост видит его как пользователя, который запускает докер).

Руководство находится здесь: https://www.jujens.eu/posts/en/2017/Jul/02/docker-userns-remap/

@патробинсон +1

Была ли эта страница полезной?
0 / 5 - 0 рейтинги