Как заставить хост и контейнер читать / записывать одни и те же файлы с помощью Docker? - PullRequest
0 голосов
/ 09 мая 2019

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

Однако я получаю отказ в разрешении в контейнере, потому что UID в контейнере и хосте не совпадают. Разве первоначальная цель Docker - ускорение и упрощение разработки?

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

Контейнер Alpine, рабочая станция Fedora 29 и редактор Atom.

Вопрос

Может кто-нибудь сказать мне, есть ли другой способ, чтобы и моя рабочая станция, и контейнер могли читать / записывать одни и те же файлы?

Ответы [ 2 ]

2 голосов
/ 09 мая 2019

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


Вариант 1: получить Mac или развернуть докер внутри VirtualBox.Обе эти среды имеют интеграцию с файловой системой, которая динамически обновляет UID.Для Mac это реализовано с OSXFS .Имейте в виду, что это удобство сопровождается снижением производительности.


Вариант 2. Смена хоста.Если UID на хосте совпадает с UID внутри контейнера, проблем не возникнет.Вы просто запустите usermod на своем пользователе на хосте, чтобы изменить там свой UID, и все будет работать, по крайней мере, пока вы не запустите другой образ с другим UID внутри контейнера.


Вариант 3: изменить свое изображение.Некоторые изменят изображение на статический UID, соответствующий их среде, часто в соответствии с UID в производственной среде.Другие передадут arg сборки с чем-то вроде --build-arg UID=$(id -u) как часть команды build, а затем Dockerfile с чем-то вроде:

FROM alpine
ARG UID=1000
RUN adduser -u ${UID} app

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


Вариант 4: Измените UID контейнера.Это можно сделать в файле compose или в одном контейнере с чем-то вроде docker run -u $(id -u) your_image.Теперь контейнер будет работать с новым UID, и файлы на томе будут доступны.Однако имя пользователя внутри контейнера не обязательно будет соответствовать вашему UID, что может показаться странным для любых команд, которые вы запускаете внутри контейнера.Что еще более важно, любые файлы, принадлежащие пользователю внутри контейнера, которые вы не скрыли с вашим томом, будут иметь исходный UID и могут быть недоступны.


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


Опция 6: Установите точку входа, которая динамически обновляет ваш контейнер.Несмотря на нежелание менять свой имидж, это мое предпочтительное решение для полноты.Ваш контейнер должен запускаться от имени пользователя root, но только в процессе разработки, и приложение все равно будет запускаться от имени пользователя, соответствующего производственной среде.Однако первым шагом этой точки входа будет изменение UID / GID пользователя в контейнере в соответствии с UID / GID вашего тома.Это похоже на вариант 4, но теперь файлы внутри изображения, которые не были заменены томом, имеют правильные UID, и пользователь внутри контейнера теперь будет отображаться с измененным UID, поэтому такие команды, как ls, показывают имя пользователя внутри контейнера., а не UID для сопоставления с другим пользователем или ни с кем вообще.Хотя это изменение в вашем образе, код выполняется только в процессе разработки и только в качестве краткой точки входа для настройки контейнера для этого разработчика, после чего процесс внутри контейнера будет выглядеть так же, как в производственной среде.

Чтобы реализовать это, я делаю следующие изменения.Сначала Dockerfile теперь включает скрипт fix-perms и gosu из базового образа, который я отправил в концентратор (это пример Java, но изменения переносимы в другие среды):

FROM openjdk:jdk as build
# add this copy to include fix-perms and gosu or install them directly
COPY --from=sudobmitch/base:scratch / /
RUN  apt-get update \
 &&  apt-get install -y maven \
 &&  useradd -m app
COPY code /code
RUN  mvn build
# add an entrypoint to call fix-perms
COPY entrypoint.sh /usr/bin/
ENTRYPOINT ["/usr/bin/entrypoint.sh"]
CMD ["java", "-jar", "/code/app.jar"]
USER app

Сценарий entrypoint.sh вызывает fix-perms, а затем exec и gosu для перехода от пользователя root к приложению:

#!/bin/sh
if [ "$(id -u)" = "0" ]; then
  # running on a developer laptop as root
  fix-perms -r -u app -g app /code
  exec gosu app "$@"
else
  # running in production as a user
  exec "$@"
fi

Файл разработчика, монтирующий том и запускающийся с правами root:

version: '3.7'
volumes:
  m2:
services:
  app:
    build:
      context: .
      target: build
    image: registry:5000/app/app:dev
    command: "/bin/sh -c 'mvn build && java -jar /code/app.jar'"
    user: "0:0"
    volumes:
    - m2:/home/app/.m2
    - ./code:/code

Этот пример взят из моей презентации, доступной здесь: https://sudo -bmitch.github.io / Presentations / dc2019 / tips-and-tricks-of-the-captains.html # fix-perms

Код для исправлений и другие примеры доступны в моем репозитории для базового образа: https://github.com/sudo-bmitch/docker-base

0 голосов
/ 09 мая 2019

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

Кроме того, вы можете рассмотреть возможность редактирования этих файлов как root.

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...