Как добавить том в существующий контейнер Docker?

297

У меня есть контейнер Docker, который я создал, просто установив Docker в Ubuntu и выполнив:

sudo docker run -i -t ubuntu /bin/bash

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

exit

Затем я хотел добавить том и понял, что это не так просто, как я думал, что будет. Если я использую его, sudo docker -v /somedir run ...то получаю новый новый контейнер, поэтому мне нужно установить Java и сделать то, что я уже сделал раньше, чтобы получить контейнер с подключенным томом.

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

Действительно ли это единственный способ добавить том в существующий контейнер?

mahonya
источник
1
После Контейнеров они стали неотъемлемой частью Программистов и, следовательно, такие вопросы чаще всего публикуются здесь. Вопросы, размещенные здесь с использованием dockerтега, составляют 34k + , что намного больше, чем у этих двух сайтов stackoverflow.com/questions/tagged/docker
MA Hossain Tonu

Ответы:

394

Вы можете зафиксировать свой существующий контейнер (то есть создать новое изображение из изменений контейнера), а затем запустить его с вашими новыми монтируемыми устройствами.

Пример:

$ docker ps  -a
CONTAINER ID        IMAGE                 COMMAND                  CREATED              STATUS                          PORTS               NAMES
    5a8f89adeead        ubuntu:14.04          "/bin/bash"              About a minute ago   Exited (0) About a minute ago                       agitated_newton

$ docker commit 5a8f89adeead newimagename

$ docker run -ti -v "$PWD/dir1":/dir1 -v "$PWD/dir2":/dir2 newimagename /bin/bash

Если все в порядке, остановите свой старый контейнер и используйте этот новый.

Это оно :)

Леонардо Кукеджо
источник
22
И если вам нужен новый контейнер, чтобы по какой-то причине взять старое имя, используйте docker rename после удаления старого.
Дирк
10
Я просто хотел указать, что выше, где вы упоминаете, newnameofcontainerчто это, вероятно, должно быть названо new_image_name- потому что docker commitсоздает новый образ в вашей системе. Затем в следующем, когда вы делаете a, docker runвы фактически используете имя изображения , из которого вы хотите запустить новый контейнер. Вышеприведенное работает, но просто хотел уточнить для других, что указанная выше метка-заполнитель newnameofcontainer фактически является именем для нового изображения. Спасибо! отличный ответ. о, вы можете увидеть вновь созданный образ из первой команды фиксации docker image ls
Docker,
3
На самом деле, вам не нужно фиксировать новый контейнер, если вы хотите начать с изображения. Просто docker run -v /srv/a:/tmp ubuntu:14.04хорошо.
ЮнХао Ху
У меня уже есть контейнер, работающий со всеми файлами. Если вышеуказанный метод создает новый контейнер, я не могу собрать все заново. Есть ли способ, которым я могу избежать этого и смонтировать, не создавая новый контейнер или образ?
Динар
Сохранит ли это старые сопоставления томов из старого контейнера или я должен повторно объявить их также с новым контейнером?
thebeancounter
79

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

Скопируйте файлы / папки между контейнером и локальной файловой системой: -

docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH|-

docker cp [OPTIONS] SRC_PATH|- CONTAINER:DEST_PATH

Для справки смотрите:

https://docs.docker.com/engine/reference/commandline/cp/

user128364
источник
47
Существует огромная разница между монтированием тома и копированием файлов в контейнер и из него ...
Жюль
31
В любом случае это помогло мне. Я не знал команду 'docker cp' и пытался добиться именно этого - копировать файлы из запущенного контейнера на хост.
Иван
3
это не монтирование, но удобно переносить файлы обратно и обратно между контейнером и локальным хостом.
linehrr
Хотя это и решает проблему локальной репликации содержимого контейнера, это не является эквивалентом монтирования тома и не должно рассматриваться как альтернатива. А именно, репликация должна управляться пользователем, и данные теперь существуют в двух местах.
Себастьян Гаведа
1
Я не понимаю, почему так много голосов, это очень неправильный ответ на заданный вопрос.
Жоао Матос
33

Я успешно смонтировал /home/<user-name>папку своего хоста в /mntпапку существующего (не запущенного) контейнера. Вы можете сделать это следующим образом:

  1. Откройте файл конфигурации, соответствующий остановленному контейнеру, который можно найти по адресу /var/lib/docker/containers/99d...1fb/config.v2.json(может быть config.jsonдля более старых версий докера).

  2. Найти MountPointsраздел, который был пуст в моем случае: "MountPoints":{}. Затем замените содержимое на что-то вроде этого (вы можете скопировать правильное содержимое из другого контейнера с правильными настройками):

"MountPoints":{"/mnt":{"Source":"/home/<user-name>","Destination":"/mnt","RW":true,"Name":"","Driver":"","Type":"bind","Propagation":"rprivate","Spec":{"Type":"bind","Source":"/home/<user-name>","Target":"/mnt"},"SkipMountpointCreation":false}}

или такой же (отформатированный):

  "MountPoints": {
    "/mnt": {
      "Source": "/home/<user-name>",
      "Destination": "/mnt",
      "RW": true,
      "Name": "",
      "Driver": "",
      "Type": "bind",
      "Propagation": "rprivate",
      "Spec": {
        "Type": "bind",
        "Source": "/home/<user-name>",
        "Target": "/mnt"
      },
      "SkipMountpointCreation": false
    }
  }
  1. Перезапустите сервис докера: service docker restart

Это работает для меня с Ubuntu 18.04.1 и Docker 18.09.0

Игорь Бендруп
источник
3
Спасибо за ответ. Шаг 3 имеет решающее значение. Я также добавил бы, что лучше сначала остановить контейнер докера перед выполнением записи.
buzypi
7
Это лучший ответ, поскольку он полностью сохраняет существующий контейнер. Вот что я сделал: 1. Остановите механизм докера: systemctl stop docker.service2. Отредактируйте config.v2.json: vim <(jq . /var/lib/docker/containers/<container-ID>/config.v2.json)3. Сохраните обновления в файл: :w config.v2.json4. Выйдите из vim: :q!5. Обновите существующий файл: jq -c . config.v2.json > /var/lib/docker/containers/<container-ID>/config.v2.json6. Запустите механизм докера: systemctl start docker.service7. Запустите контейнер при необходимости. : docker start <container-name/ID>8. Наслаждайтесь :-)
Android Control
2
Ключевым шагом является service docker restart. Я попытался docker restart <container>тогда, новый конфиг не поднят, и это перезаписывается старым конфигом.
KFL
1
Также jqпоможет довольно распечатать JSON, чтобы он мог редактироваться человеком:cat config.v2.json | jq . > config.json
KFL
14

У Жерома Петаццони есть довольно интересное сообщение в блоге о том, как присоединить том к контейнеру во время его работы . Это не то, что встроено в Docker из коробки, но возможно сделать.

Как он также указывает

Это не будет работать на файловых системах, которые не основаны на блочных устройствах.

Это будет работать только в том случае, если / proc / mounts правильно перечисляет узел блочного устройства (что, как мы видели выше, не обязательно верно).

Кроме того, я проверил это только в моей локальной среде; Я даже не примерял облачный экземпляр или что-то подобное

YMMV

R0MANARMY
источник
8

К сожалению, опция переключения для монтирования тома есть только в runкоманде.

docker run --help

-v, --volume list Bind mount a volume (default [])

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

  1. Экспортируйте свой контейнер docker container export -o ./myimage.docker mycontainer
  2. Импортировать как изображение docker import ./myimage.docker myimage
  3. затем docker run -i -t -v /somedir --name mycontainer myimage /bin/bash
Адель Хелал
источник
1
К вашему сведению - docker containerнедопустимая команда в 1.11.2 (последняя версия, которая поддерживается Synology на момент написания статьи). Я не могу найти никаких документов, говорящих, когда это было добавлено, хотя. В этом случае первая команда docker export -o ./myimage.docker mycontainer.
Крис Р. Доннелли
2

Замечание по использованию контейнеров Docker Windows после того, как мне пришлось долго искать эту проблему!

Condiditions:

  • Windows 10
  • Docker Desktop (последняя версия)
  • использование Docker Windows Container для образа microsoft / mssql-server-windows-developer

Проблема:

  • Я хотел смонтировать словарь хоста в мой контейнер Windows.

Решение как частично различаемое здесь:

  • создать докер контейнер

docker run -d -p 1433:1433 -e sa_password=<STRONG_PASSWORD> -e ACCEPT_EULA=Y microsoft/mssql-server-windows-developer

  • перейти к командной оболочке в контейнере

docker exec -it <CONTAINERID> cmd.exe

  • создать DIR

mkdir DirForMount

  • остановка контейнера

docker container stop <CONTAINERID>

  • передать контейнер

docker commit <CONTAINERID> <NEWIMAGENAME>

  • удалить старый контейнер

docker container rm <CONTAINERID>

  • создать новый контейнер с новым изображением и объемным монтажом

docker run -d -p 1433:1433 -e sa_password=<STRONG_PASSWORD> -e ACCEPT_EULA=Y -v C:\DirToMount:C:\DirForMount <NEWIMAGENAME>

После этого я решил эту проблему на контейнерах Docker Windows.

droebi
источник
-3

Лучший способ - скопировать все файлы и папки в каталог в вашей локальной файловой системе: docker cp [OPTIONS] CONTAINER:SRC_PATH DEST_PATH

SRC_PATHнаходится на контейнере DEST_PATHна локальном хосте

Затем docker-compose downприсоедините том к тому же DEST_PATHи запустите контейнеры Docker, используяdocker-compose up -d

Добавьте объем, следуя в docker-compose.yml

volumes:
 - DEST_PATH:SRC_PATH
Ватсал Мишра
источник
Есть и другие, лучшие варианты выше.
MrR
На самом деле, есть лучшие варианты выше, и копирование файлов не монтирует их. Кроме того, определение «тома», заданное для опции docker-compose, выполняется наоборот: volume: - HOST_PATH: CONTAINER_PATH
Guillaume S.