Вопрос или проблема
Я запускаю Docker внутри контейнера, используя команду ниже:
docker run --rm -ti --privileged -v /var/run/docker.sock:/var/run/docker.sock docker:1.12 sh
В оболочке этого контейнера я вижу каталог с множеством файлов. Допустим, это /project
с файлом build.gradle
. Я хотел бы запустить новый контейнер и смонтировать этот каталог, используя команду ниже
docker run -ti --rm -v /project:/project openjdk:8-jdk bash -c "ls /project"
.
Однако, похоже, что каталог проекта пуст, команда ls /project
не показывает никаких файлов..
Теперь пытаюсь смонтировать файл:
docker run -ti --rm -v /project/build.gradle:/project/build.gradle openjdk:8-jdk bash -c "ls /project/"
На этот раз папка показывает файл.
Кто-нибудь знает, почему монтирование тома не работает так, как ожидалось. Это проблема с правами доступа?
Нет. Внутри контейнера “docker” у вас есть только клиент Docker, а не все остальное. Когда вы монтируете сокет Docker внутри своего контейнера “docker”, команда Docker, которую вы выполняете, отправляется непосредственно на сервер Docker, работающий на вашем реальном хосте Docker. Поэтому этот каталог ожидаемо существует на вашем хосте Docker.
Пример, как смонтировать том с помощью Docker в Docker:
host$ pwd
/var/my-project
host$ docker run -v /var/run/docker.sock:/var/run/docker.sock -v $PWD:/app docker -it sh
/ # ls -l /app ### внутри первого docker
<СПИСОК ФАЙЛОВ ПРОЕКТА>
/ # docker run -v /var/my-project:/inception docker sh ### вам нужно передать каталог ХОСТА, а не текущий каталог контейнера (/app)
/ # ls -l /inception ### внутри второго docker
<СПИСОК ФАЙЛОВ ПРОЕКТА>
Я разрабатываю внутри контейнера. Чтобы запустить приложение с помощью Docker из Docker и смонтировать том, вы можете просто смонтировать том с путем с хоста.
docker-compose.yaml
:
version: '3.8'
services:
web:
build:
context: ./baseimage
dockerfile: Dockerfile
ports:
- '8000:8000'
volumes:
# - ./<appsrc>:/app # <= Это не работает
# Вместо этого используйте расположение тома на хост-системе
# (где монтируется сокет Docker)
- /c/Users/<user>/<container_folder>/<appsrc>:/app # <= это работает
Теперь вы можете запустить docker-compose up
Конечно, это работает только тогда, когда <container_folder>
смонтирован внутри контейнера Docker, где вы выполняете эту команду.
Я использую исполнитель Kubernet и монтирую /var/run/docker.sock, чтобы выполнить команду Docker в pod исполнителя, но нам нужно выполнить команду ‘docker run -v’ в pod, и теперь я знаю коренную причину, почему я не могу смонтировать каталог в pod, чтобы Docker. Но как я могу смонтировать код моего проекта в Docker? Потому что код проекта находится в pod исполнителя, а не на хосте. Как изменить мой конвейер, чтобы это поддержать?
Ответ или решение
Монтирование тома в Docker внутри Docker: Подробное руководство
Вопрос, который вы подняли, касается специфики работы Docker в контексте контейнеров, запущенных внутри других контейнеров (часто называемого "Docker в Docker" или DinD). Эта конфигурация может вызвать путаницу, особенно когда вы пытаетесь монтировать тома. В этом ответе мы детально разберем ваши наблюдения и предложим подходы для правильного монтирования.
Проблема с монтированием директории
В вашем случае, когда вы запускаете команду:
docker run -ti --rm -v /project:/project openjdk:8-jdk bash -c "ls /project"
и не видите ожидаемые файлы, это происходит потому, что вы пытаетесь смонтировать директорию, которая существует не в хост-системе, а в контейнере Docker, запущенном внутри вашего первого контейнера.
Важный момент здесь заключается в том, что после монтирования сокета Docker (/var/run/docker.sock
), команды Docker, которые вы исполняете внутри "второго" контейнера, обращаются к Docker-серверу, работающему на хосте, а не к Docker-серверу, работающему внутри вашего первого контейнера.
Решение проблемы
Для успешного монтирования директории, вам нужно использовать путь, который соответствует реальной файловой системе вашего хост-хоста. Например, если ваша директория проекта находится на хосте по пути /var/my-project
, вы должны указать именно этот путь при монтировании.
Вот пример рабочего процесса:
-
Убедитесь, что ваш проект доступен на хост-машине:
host$ pwd /var/my-project
-
Запустите первый Docker-контейнер с монтированием сокета Docker и вашего проекта:
host$ docker run --rm -ti --privileged -v /var/run/docker.sock:/var/run/docker.sock -v /var/my-project:/app docker:1.12 sh
-
Теперь, внутри контейнера, запустите второй контейнер с монтированием директории проекта:
/ # docker run -ti --rm -v /app:/inception openjdk:8-jdk bash -c "ls /inception"
Это должно отобразить файлы вашего проекта, так как вы монтируете директорию, которая существует на хост-системе.
Использование Docker Compose
Если вы серьезно занимаетесь разработкой и хотели бы автоматизировать процесс настройки, соглашение о компоновке (Docker Compose) будет уместным. Пример docker-compose.yaml
файла:
version: '3.8'
services:
web:
build:
context: ./baseimage
dockerfile: Dockerfile
ports:
- '8000:8000'
volumes:
- /c/Users/<user>/<container_folder>/<appsrc>:/app # Указываем реальный путь на хосте
Дополнительные рекомендации:
- Убедитесь, что
<container_folder>
смонтировано в контейнере, где вы запускаете командуdocker-compose up
. - Путь должен ссылаться на директорию на хосте, а не на внутреннюю файловую систему вашего контейнера.
Запуск в Kubernetes
Если вы работаете в Kubernetes и используете GitLab Runner или подобный, вам нужно будет учесть, что ваш проект находится в поде, а не на хосте. Здесь важный момент заключается в том, что Kubernetes использует другие механизмы для управления томами.
Вы можете использовать emptyDir
, чтобы создать временное хранилище, которое будет доступно контейнерам в поде, например:
apiVersion: v1
kind: Pod
metadata:
name: mypod
spec:
containers:
- name: mycontainer
image: docker:1.12
volumeMounts:
- mountPath: /app
name: app-storage
volumes:
- name: app-storage
emptyDir: {}
После этого вам нужно будет указать правильные пути внутри вашего контейнера для монтирования, помня о том, что все взаимодействие будет происходить в пределах Kubernetes кластера.
Заключение
Монтирование томов в Docker внутри Docker требует внимательного подхода, особенно когда речь идет о контекстах и путях. Используйте реальный путь на хосте для монтирования, а также учитывайте специфику Kubernetes, чтобы организовать работу с файлами эффективно. Выбор правильного подхода обеспечит плавную работу вашего проекта и минимизирует проблемы, связанные с доступом к файлам.