Есть несколько способов сделать это, но центральная проблема заключается в том, что привязываемые монтирования не включают в себя возможность сопоставления 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