1. Обзор
Контейнеры Docker используются для запуска приложений в изолированной среде. По умолчанию все изменения внутри контейнера теряются при остановке контейнера. Если мы хотим сохранить данные между запусками, могут помочь тома Docker и привязки.
В этом руководстве мы узнаем о томах Docker , а также о том, как управлять ими и подключать их к контейнерам.
2. Что такое объем?
2.1. Файловая система Docker
Контейнер Docker запускает программный стек, определенный в образе . Изображения состоят из набора слоев, доступных только для чтения, которые работают в файловой системе под названием Union File System. Когда мы запускаем новый контейнер, Docker добавляет слой чтения-записи поверх слоев образа, позволяя контейнеру работать так, как если бы он работал в стандартной файловой системе Linux .
Таким образом, любое изменение файла внутри контейнера создает рабочую копию на уровне чтения-записи. Однако когда контейнер останавливается или удаляется, этот уровень чтения-записи теряется .
Мы можем попробовать это, запустив команду, которая записывает, а затем читает файл:
$ docker run bash:latest \
bash -c "echo hello > file.txt && cat file.txt"
Результат:
hello
Но если мы запустим тот же образ только с командой для вывода содержимого файла:
$ docker run bash:latest bash -c "cat file.txt"
cat: can't open 'file.txt': No such file or directory
Второй запуск контейнера выполняется на чистой файловой системе, поэтому файл не найден.
2.2. Привязать маунтов
Привязка Docker — это высокопроизводительное подключение контейнера к каталогу на хост-компьютере . Это позволяет хосту совместно использовать собственную файловую систему с контейнером , который можно сделать доступным только для чтения или чтения-записи.
Это позволяет нам использовать контейнер для запуска инструментов, которые мы не хотим устанавливать на нашем хосте, и при этом работать с файлами нашего хоста. Например, если мы хотим использовать пользовательскую версию bash
для определенного сценария, мы можем выполнить этот сценарий в контейнере bash
, смонтированном в нашем текущем рабочем каталоге:
$ docker run -v $(pwd):/var/opt/project bash:latest \
bash -c "echo Hello > /var/opt/project/file.txt"
Параметр –v
может использоваться для всех форм монтирования и указывает, в данном случае, источник на хосте – рабочий каталог в выводе $(pwd)
– и целевую точку монтирования в контейнере – /var/opt /проект
.
После запуска этой команды мы найдем файл .txt
в рабочем каталоге нашего хост-компьютера. Это простой способ предоставления постоянных файлов между вызовами контейнера Docker, хотя он наиболее полезен, когда контейнер выполняет работу от имени хоста.
Хорошим вариантом использования для этого было бы выполнение различных версий инструментов сборки языка в Docker, чтобы избежать конфликтующих установок на компьютере разработчика.
Следует отметить, что $(pwd -W)
иногда требуется в оболочках Windows bash для предоставления рабочего каталога в форме, которую оболочка bash может передать в Docker.
2.3. Объемы докеров
При монтировании с привязкой используется файловая система хоста, но тома Docker являются родными для Docker . Данные хранятся где-то в хранилище, подключенном к хосту — часто в локальной файловой системе. Жизненный цикл самого тома длиннее, чем у контейнера, что позволяет ему сохраняться до тех пор, пока он не станет не нужен. Тома могут быть разделены между контейнерами.
В некоторых случаях том находится в форме, которую хост не может использовать напрямую.
3. Управление томами
Docker позволяет нам управлять томами с помощью набора команд docker volume .
Мы можем дать тому явное имя (именованные тома) или позволить Docker сгенерировать случайное имя (анонимные тома).
3.1. Создание томов
Мы можем создать том, используя подкоманду create
и передав имя в качестве аргумента:
$ docker volume create data_volume
data_volume
Если имя не указано, Docker генерирует случайное имя:
$ docker volume create
d7fb659f9b2f6c6fd7b2c796a47441fa77c8580a080e50fb0b1582c8f602ae2f
3.2. Список томов
Подкоманда ls
показывает все тома, известные Docker:
$ docker volume ls
DRIVER VOLUME NAME
local data_volume
local d7fb659f9b2f6c6fd7b2c796a47441fa77c8580a080e50fb0b1582c8f602ae2f
Мы можем фильтровать, используя флаг -f
или –filter
и передавая параметры ключ=значение
для большей точности:
$ docker volume ls -f name=data
DRIVER VOLUME NAME
local data_volume
3.3. Проверка томов
Чтобы отобразить подробную информацию об одном или нескольких томах, мы используем подкоманду inspect :
$ docker volume inspect ca808e6fd82590dd0858f8f2486d3fa5bdf7523ac61d525319742e892ef56f59
[
{
"CreatedAt": "2020-11-13T17:04:17Z",
"Driver": "local",
"Labels": null,
"Mountpoint": "/var/lib/docker/volumes/ca808e6fd82590dd0858f8f2486d3fa5bdf7523ac61d525319742e892ef56f59/_data",
"Name": "ca808e6fd82590dd0858f8f2486d3fa5bdf7523ac61d525319742e892ef56f59",
"Options": null,
"Scope": "local"
}
]
Следует отметить, что драйвер
тома описывает, как хост Docker находит том. Тома могут быть на удаленном хранилище через nfs, например. В этом примере том находится в локальном хранилище.
3.4. Удаление томов
Чтобы удалить один или несколько томов по отдельности, мы можем использовать подкоманду rm :
$ docker volume rm data_volume
data_volume
3.5. Обрезка томов
Мы можем удалить все неиспользуемые тома с помощью подкоманды prune :
$ docker volume prune
WARNING! This will remove all local volumes not used by at least one container.
Are you sure you want to continue? [y/N] y
Deleted Volumes:
data_volume
4. Запуск контейнера с томом
4.1. Использование -v
Как мы видели в предыдущем примере, мы можем запустить контейнер с монтированием привязки, используя параметр -v
:
$ docker run -v $(pwd):/var/opt/project bash:latest \
bash -c "ls /var/opt/project"
Этот синтаксис также поддерживает монтирование тома:
$ docker run -v data-volume:/var/opt/project bash:latest \
bash -c "ls /var/opt/project"
Поскольку наш том пуст, в нем ничего не отображается из точки монтирования. Однако, если бы мы записывали в том во время одного вызова контейнера:
$ docker run -v data-volume:/var/opt/project bash:latest \
bash -c "echo ForEach > /var/opt/project/ForEach.txt"
Тогда наше последующее использование контейнера с этим смонтированным томом сможет получить доступ к файлу:
$ docker run -v data-volume:/var/opt/project bash -c "ls /var/opt/project"
ForEach.txt
Параметр -v
содержит три компонента, разделенных двоеточием:
- Исходный каталог или имя тома
- Точка монтирования внутри контейнера
- (Необязательно)
ro
, если монтирование должно быть доступно только для чтения
4.2. Использование параметра –mount
Мы можем предпочесть использовать более понятную опцию –mount
, чтобы указать том, который мы хотим смонтировать:
$ docker run --mount \
'type=volume,src=data-volume,\
dst=/var/opt/project,volume-driver=local,\
readonly' \
bash -c "ls /var/opt/project"
Входными данными для –mount
является строка пар ключ-значение, разделенных запятыми. Здесь мы установили:
type
— кактом
, чтобы указать монтирование томаsrc
— к имени тома, хотя это мог быть и исходный каталог, если бы мы выполняли монтирование с привязкойdst
— как конечная точка монтирования в контейнереvolume-driver
— в данном случаелокальный драйвер
readonly
– сделать это монтирование доступным только для чтения; мы могли бы выбратьrw
для чтения/записи
Следует отметить, что приведенная выше команда также создаст том, если он еще не существует.
4.3. Использование –volumes-from
для совместного использования томов
Следует отметить, что присоединение тома к контейнеру создает долгосрочную связь между контейнером и томом. Даже когда контейнер вышел, связь все еще существует. Это позволяет нам использовать вышедший контейнер в качестве шаблона для монтирования того же набора томов в новый.
Допустим, мы запустили наш эхо
- скрипт в контейнере с монтированием тома данных .
Позже мы могли бы перечислить все контейнеры , которые мы использовали:
$ docker ps -a
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
4920602f8048 bash "docker-entrypoint.s…" 7 minutes ago Exited (0) 7 minutes ago exciting_payne
Мы могли бы запустить наш следующий контейнер, скопировав тома, используемые этим:
$ docker run --volumes-from 4920 \
bash:latest \
bash -c "ls /var/opt/project"
ForEach.txt
На практике –volumes-from
обычно используется для связывания томов между запущенными контейнерами . Jenkins использует его для обмена данными между агентами, работающими как контейнеры Docker.
5. Вывод
В этой статье мы увидели, как Docker обычно создает контейнер с новой файловой системой, но как связывание монтирования и тома позволяют долговременное хранение данных за пределами жизненного цикла контейнера.
Мы увидели, как составлять список томов Docker и управлять ими, а также как подключать тома к работающему контейнеру через командную строку.