Volumes docker что это
Перейти к содержимому

Volumes docker что это

  • автор:

Хранение данных в Docker

Важная характеристика Docker-контейнеров — эфемерность. В любой момент контейнер может рестартовать: завершиться и вновь запуститься из образа. При этом все накопленные в нём данные будут потеряны. Но как в таком случае запускать в Docker приложения, которые должны сохранять информацию о своём состоянии? Для этого есть несколько инструментов.

В этой статье рассмотрим docker volumes, bind mount и tmpfs, дадим советы по их использованию, проведём небольшую практику.

Особенности работы контейнеров

Прежде чем перейти к способам хранения данных, вспомним устройство контейнеров. Это поможет лучше понять основную тему.

Контейнер создаётся из образа, в котором есть всё для начала его работы. Но там не хранится и тем более не изменяется ничего важного. В любой момент приложение в контейнере может быть завершено, а контейнер уничтожен, и это нормально. Контейнер отработал — выкидываем его и собираем новый. Если пользователь загрузил в приложение картинку, то при замене контейнера она удалится.

На схеме показано устройство контейнера, запущенного из образа Ubuntu 15.04. Контейнер состоит из пяти слоёв: четыре из них принадлежат образу, и лишь один — самому контейнеру. Слои образа доступны только для чтения, слой контейнера — для чтения и для записи. Если при работе приложения какие-то данные будут изменяться, они попадут в слой контейнера. Но при уничтожении контейнера слой будет безвозвратно потерян, и все данные вместе с ним.

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

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

В Docker есть несколько способов хранения данных. Наиболее распространенные:

  • тома хранения данных (docker volumes),
  • монтирование каталогов с хоста (bind mount).

Особые типы хранения:

  • именованные каналы (named pipes, только в Windows),
  • монтирование tmpfs (только в Linux).

На схеме показаны самые популярные типы хранения данных для Linux: в памяти (tmpfs), в файловой системе хоста (bind mount), в томе Docker (docker volumes). Разберём каждый вариант.

Тома (docker volumes)

Тома — рекомендуемый разработчиками Docker способ хранения данных. В Linux тома находятся по умолчанию в /var/lib/docker/volumes/. Другие программы не должны получать к ним доступ напрямую, только через контейнер.

Тома создаются и управляются средствами Docker: командой docker volume create, через указание тома при создании контейнера в Dockerfile или docker-compose.yml.

В контейнере том видно как обычный каталог, который мы определяем в Dockerfile. Тома могут быть с именами или без — безымянным томам Docker сам присвоит имя.

Один том может быть примонтирован одновременно в несколько контейнеров. Когда никто не использует том, он не удаляется, а продолжает существовать. Команда для удаления томов: docker volume prune.

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

Для чего стоит использовать тома в Docker:

  • шаринг данных между несколькими запущенными контейнерами,
  • решение проблемы привязки к ОС хоста,
  • удалённое хранение данных,
  • бэкап или миграция данных на другой хост с Docker (для этого надо остановить все контейнеры и скопировать содержимое из каталога тома в нужное место).

Монтирование каталога с хоста (bind mount)

Это более простая концепция: файл или каталог с хоста просто монтируется в контейнер.

Используется, когда нужно пробросить в контейнер конфигурационные файлы с хоста. Например, именно так в контейнерах реализуется DNS: с хоста монтируется файл /etc/resolv.conf.

Другое очевидное применение — в разработке. Код находится на хосте (вашем ноутбуке), но исполняется в контейнере. Вы меняете код и сразу видите результат. Это возможно, так как процессы хоста и контейнера одновременно имеют доступ к одним и тем же данным.

Особенности bind mount:

  1. Запись в примонтированный каталог могут вести программы как в контейнере, так и на хосте. Это значит, есть риск случайно затереть данные, не понимая, что с ними работает контейнер.
  2. Лучше не использовать в продакшене. Для продакшена убедитесь, что код копируется в контейнер, а не монтируется с хоста.
  3. Для успешного монтирования указывайте полный путь к файлу или каталогу на хосте.
  4. Если приложение в контейнере запущено от root, а совместно используется каталог с ограниченными правами, то в какой-то момент может возникнуть проблема с правами на файлы и невозможность что-то удалить без использования sudo.

Когда использовать тома, а когда монтирование с хоста

Volume Bind mount
Просто расшарить данные между контейнерами. Пробросить конфигурацию с хоста в контейнер.
У хоста нет нужной структуры каталогов. Расшарить исходники и/или уже собранные приложения.
Данные лучше хранить не локально (а в облаке, например). Есть стабильная структура каталогов и файлов, которую нужно расшарить между контейнерами.

Монтирование tmpfs

Tmpfs — временное файловое хранилище. Это некая специально отведённая область в оперативной памяти компьютера. Из определения выходит, что tmpfs — не лучшее хранилище для важных данных. Так оно и есть: при остановке или перезапуске контейнера сохранённые в tmpfs данные будут навсегда потеряны.

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

Например, приложение в контейнере тормозит из-за того, что в ходе работы активно идут операции чтения-записи, а диски на хосте не очень быстрые. Если вы не уверены, в какой каталог идёт эта нагрузка, можно применить к запущенному контейнеру команду docker diff . И вот этот каталог смонтировать как tmpfs, таким образом перенеся ввод-вывод с диска в оперативную память.

Такое хранилище может одновременно работать только с одним контейнером и доступно только в Linux.

Общие советы по использованию томов

Монтирование в непустые директории

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

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

Монтирование служебных файлов

С хоста можно монтировать любые файлы, в том числе служебные. Например, сокет docker. В результате получится docker-in-docker: один контейнер запустится внутри другого. UPD: (*это не совсем так. mwizard в комментариях пояснил, что в таком случае родительский docker запустит sibling-контейнер). Выглядит как бред, но в некоторых случаях бывает оправдано. Например, при настройке CI/CD.

Монтирование /var/lib/docker

Разработчики Docker говорят, что не стоит монтировать с хоста каталог /var/lib/docker, так как могут возникнуть проблемы. Однако есть некоторые программы, для запуска которых это необходимо.

Практика: создадим тестовый том

Ключ командной строки для Docker при работе с томами.

Для volume или bind mount:

--volume | -v
--tmpfs

Команды для управления томами в интерфейсе CLI Docker:

$ docker volume Commands: create Create a volume (Создать том) inspect Display detailed information on one or more volumes (Отобразить детальную информацию) ls List volumes (Вывести список томов) prune Remove all unused volumes (Удалить все неиспользуемые тома) rm Remove one or more volumes (Удалить один или несколько томов)

Создадим тестовый том:

$ docker volume create slurm-storage slurm-storage

Вот он появился в списке:

$ docker volume ls DRIVER VOLUME NAME local slurm-storage

Команда inspect выдаст примерно такой список информации в json:

$ docker inspect slurm-storage [ < "CreatedAt": "2020-12-14T15:00:37Z", "Driver": "local", "Labels": <>, "Mountpoint": "/var/lib/docker/volumes/slurm-storage/_data", "Name": "slurm-storage", "Options": <>, "Scope": "local" > ]

Попробуем использовать созданный том, запустим с ним контейнер:

$ docker run --rm -v slurm-storage:/data -it ubuntu:20.10 /bin/bash # echo $RANDOM > /data/file # cat /data/file 13279 # exit

После самоуничтожения контейнера запустим другой и подключим к нему тот же том. Проверяем, что в нашем файле:

$ docker run --rm -v slurm-storage:/data -it centos:8 /bin/bash -c "cat /data/file" 13279

То же самое, отлично.

Теперь примонтируем каталог с хоста:

$ docker run -v /srv:/host/srv --name slurm --rm -it ubuntu:20.10 /bin/bash

Docker не любит относительные пути, лучше указывайте абсолютные!

Теперь попробуем совместить оба типа томов сразу:

$ docker run -v /srv:/host/srv -v slurm-storage:/data --name slurm --rm -it ubuntu:20.10 /bin/bash

Отлично! А если нам нужно передать ровно те же тома другому контейнеру?

$ docker run --volumes-from slurm --name backup --rm -it centos:8 /bin/bash

Вы можете заметить некий лаг в обновлении данных между контейнерами, это зависит от используемого Docker драйвера файловой системы.

Создавать том заранее необязательно, всё сработает в момент запуска docker run:

$ docker run -v newslurm:/newdata -v /srv:/host/srv -v slurm-storage:/data --name slurm --rm -it ubuntu:20.10 /bin/bash

Посмотрим теперь на список томов:

$ docker volume ls DRIVER VOLUME NAME local slurm-storage local newslurm

Ещё немного усложним команду запуска, создадим анонимный том:

$ docker run -v /anonymous -v newslurm:/newdata -v /srv:/host/srv -v slurm-storage:/data --name slurm --rm -it ubuntu:20.10 /bin/bash

Такой том самоуничтожится после выхода из контейнера, так как мы указали ключ –rm.

Если этого не сделать, давайте проверим что будет:

$ docker run -v /anonymous -v newslurm:/newdata -v /srv:/host/srv -v slurm-storage:/data --name slurm -it ubuntu:20.10 /bin/bash $ docker volume ls DRIVER VOLUME NAME local 04c490b16184bf71015f7714b423a517ce9599e9360af07421ceb54ab96bd333 local newslurm local slurm-storage

Хозяйке на заметку: тома (как образы и контейнеры) ограничены значением настройки dm.basesize, которая устанавливается на уровне настроек демона Docker. Как правило, что-то около 10Gb. Это значение можно изменить вручную, но потребуется перезапуск демона Docker.

При запуске демона с ключом это выглядит так:

$ sudo dockerd --storage-opt dm.basesize=40G

Однажды увеличив значение, его уже нельзя просто так уменьшить. При запуске Docker выдаст ошибку.

Если вам нужно вручную очистить содержимое всех томов, придётся удалять каталог, предварительно остановив демон:

$ sudo service docker stop $ sudo rm -rf /var/lib/docker

Если вам интересно узнать подробнее о работе с данными в Docker и других возможностях технологии, приглашаем на двухдневный онлайн-интенсив в феврале. Будет много практики.

Автор статьи: Александр Швалов, практикующий инженер Southbridge, Certified Kubernetes Administrator, автор и разработчик курсов Слёрм.

  • Блог компании Слёрм
  • Системное администрирование
  • Виртуализация
  • Серверное администрирование
  • DevOps

Работа с томами (Volumes) в Docker

Volumes — являются механизмом для сохранения данных, создаваемых и используемых Docker контейнерами (с хостевой машины на контейнер).

Надеюсь что у вас уже имеется докер на хостевой машине, если нет, вот полезные статьи:

И так, приступим.

Работа с томами (Volumes) в Docker

Сейчас буду приводить наглядные примеры того, каким образом можно работать с волюмами, стореджами.

Создание Volumes в Docker

Чтобы создать Volume, выполните:

$ docker volume create --name http-custom-data http-custom-data

Проверим что имеется в докере:

$ docker volume ls

Или вывести только необходимый:

$ docker volume ls | grep http-custom-data local http-custom-data

Получим подробную инфу:

$ docker volume inspect http-custom-data

Создадим index.html файл:

my custom page from Volume

Скопируем созданный файл в волюму:

$ cp index.html /var/lib/docker/volumes/http-custom-data/_data/

Смотрим, есть ли файл:

$ ls -l /var/lib/docker/volumes/http-custom-data/_data/ total 4 -rw-r--r-- 1 root root 28 Oct 11 20:40 index.html

И запустим контейнер nginx:

$ docker run -d -P -v http-custom-data:/usr/share/nginx/html nginx b94feb29c143eea7900965706447151e96df86539312bdcea79b42952bae701a

Посмотрим какой порт юзает созданный контейнер:

$ docker port $(docker ps -lq) 80/tcp -> 0.0.0.0:32769

Дерним курл чтобы убедится что скопированные данные имеются в докере:

# curl 127.0.0.1:32769 my custom page from Volume

Собственно, что и требовалось доказать — все есть и работает должным образом.

Создание TMPFS Volumes в Docker

Рассмотрим пример создания TMPFS Volume (данные хранятся в RAM) следующим образом:

$ docker volume create --driver local \ --opt type=tmpfs \ --opt device=tmpfs \ --opt o=size=100m,uid=1000 \ foo

Создание BTRFS Volumes в Docker

Рассмотрим пример создания BTRFS Volume (данные хранятся на /dev/sda2 разделе) следующим образом:

$ docker volume create \ --driver local \ --opt type=btrfs \ --opt device=/dev/sda2 \ foo

Создание NFS Volumes в Docker

Рассмотрим пример создания NFS Volume (в удаленной части NFS) следующим образом:

$ docker volume create \ --driver local \ --opt type=nfs \ --opt o=addr=192.168.1.1,rw \ --opt device=:/path/to/dir \ foo

Монтирование Volumes с хостевой машины в контейнер.

Добавление Volum-ов в контейнер(ы) являются хорошим решением т.к при завершении жизни контейнера все ваши данные будут утеряны. Если ваш контейнер генерирует непостоянные данные, рассмотрите возможность использования монтирования tmpfs, чтобы избежать постоянного хранения данных в любом месте и увеличить производительность контейнера, избегая записи на перезаписываемый слой контейнера.

$ docker run -d -p 127.0.0.1:8080:80 -v $(pwd):/var/www/html:ro httpd

Или вот еще примеры:

$ docker run --rm -v $(pwd):$(pwd) -w $(pwd) maven:3.3-jdk-8 clean package $ docker run -d -v /var/log/httpd:/var/log/httpd httpd $ docker run -d -v /var/log/tomcat:/usr/local/tomcat/logs tomcat $ docker run -d -v /data:/etc/mongo mongo

Монтирование tmpfs в Docker

Монтирование tmpfs является временным и сохраняется только в памяти хоста. Когда контейнер остановится, монтирование tmpfs будет удалено, и файлы, написанные там, не будут сохранены.

Ограничения монтирования tmpfs:

  • Вы не можете шарить данные монтированием tmpfs между контейнерами.
  • Эта функция доступна только в том случае, если вы используете Docker в Linux.
$ docker run -d -ti -p127.0.0.1:8282:8200 --name=vault_test --mount type=tmpfs,destination=/tmp vault:0.11.4

Выглядит это так:

Работа с томами/хранилищами (Volumes/Storages) в Docker

Case #1. VOLUME в Dockerfile

Создадим докерфайл выглядит:

FROM nginx RUN echo "default page" > /usr/share/nginx/html/index.html VOLUME /usr/share/nginx/html/
$ docker build -t nginx_v:1 . . Successfully built efdfe29e01fd Successfully tagged nginx_v:1

Проверим PRE-BUILT данные:

$ docker run -d -p80:80 nginx_v:1 $ curl localhost default page
$ docker exec $(docker ps -lq) \ sh -c 'echo changed page > /usr/share/nginx/html/index.html' $ curl localhost changed page
$ docker stop $(docker ps -lq)
$ docker inspect $(docker ps -lqa) | jq '.[]|.Mounts' [ < "Type": "volume", "Name": "395c2b4639c0a577ff25b379adc201e77a1cedbc5d50e91150149e1f51191182", "Destination": "/usr/share/nginx/html", "Driver": "local", "Mode": "", "RW": true, "Source": "/ var/lib/docker/volumes/395c2b4639c0. f51191182/_data", "Propagation": "" >]
$ cat /var/lib/docker/volumes/395c2b4639c0a577ff25b379adc201e77a1cedbc5d50e91150149e1f51191182/_data/index.html changed page

Удалим контейнер и поглядим что выйдет с данными:

$ docker rm $(docker ps -lqa) $ cat /var/lib/docker/volumes/395c2b4639c0a577ff25b379adc201e77a1cedbc5d50e91150149e1f51191182/_data/index.html changed page

Case #2. Создание Volume для контейнера

Запускаем контейнер вот так:

$docker run -d -p 80:80 -v /usr/share/nginx/html nginx $ curl localhost . Welcome to nginx! .

Находим куда смонтируется Volume:

$ docker inspect $(docker ps -lqa) | jq -r '.[]|.Mounts[] | .Source' /var/lib/docker/volumes/b6400a50ad0a0e8f11fa962cb99e7d2e425ac1654c4e4ea1376ae61a05e5dbc8/_data
$ echo changed > $(docker inspect $(docker ps -lqa) | jq -r '.[]|.Mounts[] | .Source')/index.html $ curl localhost changed

Case #3. Шара данных между контейнерами

На 1-м контейнере, ранаем:

$ docker run -d -v /usr/share/nginx/html --name c1 nginx $ echo changed > $(docker inspect c1 | jq -r '.[]|.Mounts[] | .Source')/index.html

На 2-м контейнере, ранаем:

$ docker run --volumes-from c1 busybox cat /usr/share/nginx/html/index.html changed

Что делает инструкция VOLUME в Dockerfile?

Никак не могу понять что делает инструкция VOLUME [«/data»] в Dockerfile, сначала я думал, что это аналог опции -v и что можно написать так: VOLUME [«С:/test:/data»] , но оказался не прав. Так что за директорию создает иснтрукция VOLUME и где она хранится на хост-машине (windows)? И как лучше и правильно подключать директорию с данными, например, БД к контейнеру? Через опцию -v ?

Отслеживать
13.7k 12 12 золотых знаков 43 43 серебряных знака 75 75 бронзовых знаков
задан 15 янв 2018 в 14:28
user281215 user281215
31 1 1 золотой знак 1 1 серебряный знак 2 2 бронзовых знака
15 янв 2018 в 14:38
@VladyslavTereshyn, не помогло, можно как то своими словами?
15 янв 2018 в 14:38

3 ответа 3

Сортировка: Сброс на вариант по умолчанию

VOLUME говорит о том, что при запуске контейнера необходимо создать директорию на хосте, заполненную данными из образа, и смонтировать в указанной точке внутри контейнера (/data):

  • Контейнер стартует
  • Перед стартом в дебрях инсталяции докера создается пустая директория
  • В директорию копируется содержимое /data из образа
  • Директория монтируется в контейнер по пути /data

Хранится она где-то внутри установки Docker (где именно это на Windows — не знаю). Не побоюсь собственного оценочного суждения — это абсолютно бесполезная директива, которая несет больше вреда, нежели пользы (потому что, например, она остается жить после смерти контейнера, потребляя ненужное место, и обнаружить в какой-то момент тысячи ненужных volume — это обычное дело). Если вам необходимо вынести данные из контейнера для сохранения (например, чтобы сохранить БД между запусками контейнера), то действительно лучше использовать -v . Основная разница между -v и VOLUME в Dockerfile состоит в том, что в -v вы указываете конечную директорию, которую нужно пробросить внутрь контейнера и сами управляете ей, а VOLUME проделывает почти то же самое, только эта директория находится непонятно где, управляется самим докером (обычно наоборот, вовсе не управляется), и управление всем этим добром стоит порядочного количества нервов.

Управление данными в Docker

К докер контейнерам можно подключать внешние папки. Рассматриваем основные способы.

Время чтения: больше 15 мин

Открыть/закрыть навигацию по статье

  1. Связанные папки (bind mounts)
    1. Как пользоваться
    1. Как пользоваться
    2. Использование драйверов
    3. Резервные копии
    1. Как пользоваться
    1. Игорь Коровченко советует
    1. Опишите жизненный цикл контейнера Docker

    Обновлено 17 мая 2022

    В этой статье мы поговорим про управление данными приложений в Docker. Узнать, что такое Docker, вы сможете из статьи «Что такое Docker». Также вы можете почитать о мультиконтейнерных приложениях и Docker Compose и о том, как устроен Dockerfile.

    Итак, по умолчанию все данные приложения хранятся в контейнере Docker и после остановки контейнера теряются. Но это не единственный способ работать с данными. Можно использовать оперативную память и файловую систему компьютера, на котором установлен Docker Engine. Существует несколько типов хранилищ данных:

    • связанные папки, примонтированные к контейнеру как внешние диски (bind mounts);
    • тома (volumes);
    • часть оперативной памяти для работы с данными (tmpfs mounts или npipe mounts).

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

    Наглядная схема типов управления данными в Docker:

    Наглядная схема типов управления данными в Docker.

    Рассмотрим каждый тип по отдельности.

    Связанные папки (bind mounts)

    Скопировать ссылку «Связанные папки (bind mounts)» Скопировано

    Связанные папки появились в Docker с самых первых релизов. Это удобный инструмент, но у него есть ограничения. Этот тип управления данными позволяет связать папку на компьютере пользователя (то есть хосте, на котором установлен Docker Engine) и папку в контейнере. Работать в контейнере и на хосте с такой папкой можно одновременно, все изменения будут отображаться и там, и там. Механизм bind mounts подразумевает, что данные могут быть изменены в любое время как из подключённого контейнера, так и непосредственно на хосте.

    При создании связанной папки указывается полный путь к ней на хосте и путь внутри контейнера. Если папка не существует на хосте, Docker может создать её сам.

    Связанные папки используются:

    Когда конфигурационные файлы на хосте и в контейнере одни и те же. Именно этот тип использует сам Docker для автоматического монтирования конфигурации DNS хоста.

    Когда работаем с исходным кодом и артефактами сборок. Можно использовать системы сборки для исходного кода внутри контейнера. Вы меняете код, бандлер, который находится внутри контейнера, это видит, и код попадает в новую сборку. Другой вариант использования — работа с уже собранными бандлами, например, для тестирования или отладки приложений.

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

    Как пользоваться

    Скопировать ссылку «Как пользоваться» Скопировано

    Чтобы связать папку на хосте с папкой внутри контейнера, можно воспользоваться флагами -v или — — mount . $ ( pwd ) в командах ниже означает, что примонтируется текущая папка на хосте.

    Пример с флагом -v :

     docker run -d \ -it \ --name devtest \ -v "$(pwd)"/target:/app \ node:lts docker run -d \ -it \ --name devtest \ -v "$(pwd)"/target:/app \ node:lts     

    Можно задать следующие опции: rprivate , private , rshared , shared , rslave , slave , ro , z и Z .

    Первые шесть параметров позволяют управлять тем, как будут влиять изменения в одной точке монтирования тома на другие точки монтирования. По умолчанию используется rprivate , что означает — никак.

    Последние три параметра могут быть указаны только для флага -v . Значение ro определяет режим только для чтения. Папка на хосте не может быть изменена внутри контейнера. Значение z обозначает, что папка на хосте может быть использована несколькими контейнерами. Значение Z обозначает, что папка используется только одним контейнером. Не указывайте значение Z для системных папок, например, /usr или /home. Это приведёт к тому, что работа операционной системы на хосте будет парализована. Будьте аккуратны!

    Пример с флагом — — mount :

     docker run -d \ -it \ --name devtest \ --mount type=bind,source="$(pwd)"/target,target=/app \ node:lts docker run -d \ -it \ --name devtest \ --mount type=bind,source="$(pwd)"/target,target=/app \ node:lts     

    Ключ bind-propagation

    Для флага — — mount есть ключ bind — propagation , который работает только на Linux (операционные системы контейнера и хоста должны поддерживать этот режим работы).

    Представьте, есть две точки монтирования /mnt1 и /mnt2 , к которым привязана одна и та же папка на хосте. Значения ключа bind — propagation определяют, что произойдёт, если в связанной папке появятся подпапки. Что произойдёт с /mnt2 / sub при монтировании /mnt1 / sub ? Возможны следующие варианты:

    — shared указывает на то, что изменения для точки монтирования /mnt1 / sub будут в точности отражаться в /mnt2 / sub и наоборот;
    — slave указывает на то же, что shared , но только в одном направлении (изменения в первой точке монтирования будут распространяться на вторую, но не наоборот);
    — private указывает, что изменения в первой точке монтирования не будут отображаться во второй, и наоборот;
    — rshared — то же, что shared , распространяет подобное поведение на все реплики точек монтирования;
    — rslave — то же, что slave , распространяет подобное поведение на все реплики точек монтирования;
    — rprivate (значение по умолчанию) — то же, что private , распространяет подобное поведение на все реплики точек монтирования.

     docker run -d \ -it \ --name devtest \ --mount type=bind,source="$(pwd)"/app/src,target=/app \ --mount type=bind,source="$(pwd)"/app/src,target=/app2,readonly,bind-propagation=rslave \ node:lts docker run -d \ -it \ --name devtest \ --mount type=bind,source="$(pwd)"/app/src,target=/app \ --mount type=bind,source="$(pwd)"/app/src,target=/app2,readonly,bind-propagation=rslave \ node:lts     

    Папка /app/src на хосте дважды монтируется к разным папкам в контейнере. Вторая точка монтирования имеет дополнительные настройки:

    — приложение app2 может только читать данные из папки на хосте;
    — изменения в первой точке монтирования сразу происходят и во второй, но не наоборот.

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

    Флаг — — mount не поддерживает опции для управления метками selinux ( z и Z ).

    Проверьте корректность работы хранилища с помощью команды:

     docker inspect devtest docker inspect devtest     

    В соответствующей секции Mounts вы сможете найти исчерпывающую информацию. Например, если вы находились в папке /tmp/source/target при запуске контейнера, то в этой секции будет указана примерно следующая информация:

     "Mounts": [  "Type": "bind", "Source": "/tmp/source/target", "Destination": "/app", "Mode": "", "RW": true, "Propagation": "rprivate" >], "Mounts": [  "Type": "bind", "Source": "/tmp/source/target", "Destination": "/app", "Mode": "", "RW": true, "Propagation": "rprivate" > ],      

    Для разрыва связи между папками на хосте и в контейнере выполните команды остановки и удаления контейнера:

     docker container stop devtestdocker container rm devtest docker container stop devtest docker container rm devtest     
    1. Связанными папками нельзя управлять из Docker CLI.
    2. Абсолютные пути на разных компьютерах могут быть разными.
    3. Если в контейнере в примонтированной папке есть содержимое, то оно «перекроет» содержимое связанной папки на все время работы контейнера.
    4. Использовать связанные папки для работы с конфигурационными файлами небезопасно.
    5. Файловая система и структура папок могут сильно отличаться на разных компьютерах.
    6. Правила описания путей к файлам могут отличаться при переходе от одной платформы к другой.
    7. Вы можете столкнуться с ситуацией, когда приложение в контейнере получит доступ к системным папкам или удалит критически важные файлы.

    Тома (volumes)

    Скопировать ссылку «Тома (volumes)» Скопировано

    Тома — это лучший тип управления данных в Docker. Только объекты или службы Docker должны иметь права на изменение данных, расположенных в томах. На хосте данные хранятся в специальных папках, но без доступа администратора к ним не подобраться. В идеологии Docker тома — что-то вроде образа флэш-накопителя или CD/DVD.

    Тома можно размещать не только на хосте. Можно, например, пользоваться облачными платформами для совместной работы с данными или для тестирования приложений. А ещё тома будут работать как с Linux-контейнерами, так и с Windows-контейнерами, поскольку файловая система томов одна и та же.

    Когда том примонтирован к контейнеру, операционная система хоста не имеет к нему доступа. Docker управляет томами отдельно, позволяя подключаться одному или нескольким контейнерам одновременно. Плюсом является и то, что том существует самостоятельно и не зависит от жизненного цикла контейнеров.

    Тома могут быть созданы при сборке контейнера (с помощью Dockerfile или Docker Compose) или вручную с помощью Docker Engine. Тома могут иметь имя, назначенное пользователем (именованные тома, named volumes), а могут быть анонимными с именем, которое Docker устанавливает автоматически (анонимные тома, anonymous volumes).

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

    Итак, возможности томов:

    — миграция данных и создание резервных копий;
    — управление с помощью Docker CLI или Docker API;
    — тома работают и с Linux-, и с Windows-контейнерами;
    — данные легко и безопасно можно использовать в нескольких контейнерах;
    — существует механизм драйверов, который позволяет хранить данные не только на хосте, но и на сервере или в облаке, шифровать данные в томе или добавлять дополнительную функциональность;
    — новые тома могут создаваться с уже загруженными с помощью контейнера данными;
    — если на хосте установлены Mac или Windows, тома будут быстрее работать с Docker Desktop, чем связанные папки;
    — тома не увеличивают размер контейнера;
    — тома находятся вне жизненного цикла контейнера.

    Когда нам нужно получить доступ к данным из разных контейнеров. Том создаётся в первый раз либо вручную, либо при сборке контейнера. Уничтожается том всегда только с помощью Docker вручную. После остановки контейнера том будет продолжать работать, пока не будет удалён пользователем.

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

    Когда вы хотите хранить данные не только у себя на локальном компьютере, но и на сервере или в облаке.

    Когда нужно создать резервную копию или перенести тома с одного компьютера на другой. Тома хранятся в определённой папке на компьютере. Вы можете просто скопировать её, заархивировать и перенести на другой хост. Примерно так же создаётся и резервная копия.

    Если ваше приложение требует высокой скорости обмена данными на Mac и Windows. Тома сохраняются на виртуальной машине Linux VM, на которой работают и контейнеры, поэтому скорость чтения и записи высокая. Нет лишних накладных расходов на доступ к файловой системе хоста.

    Когда важно, чтобы файловая система имела нативное поведение. Например, база данных должна контролировать кэширование на диске для гарантии выполнения транзакций. Файловые системы на Mac и Windows работают не так, как на Linux. Это может привести к ошибкам работы некоторых приложений.

    Как пользоваться

    Скопировать ссылку «Как пользоваться» Скопировано

    Создать том можно с помощью флагов -v или — — mount при запуске контейнера. Для флага -v можно указать параметр ro , который будет означать использование режима только для чтения. Для флага — — mount есть ключ volume — opt , который устанавливает набор опций, разделённых запятыми. Не забывайте, что значения для этого ключа должны быть экранированы кавычками. Работа с томами такова, что изменения в одной точке монтирования в контейнере не будут отображаться в другой точке монтирования (параметр bind — propagation всегда выставлен в значение rprivate ).

    Подключить том с именем my — vol можно следующим образом.

    С флагом — — mount :

     docker run -d \ --name devtest \ --mount source=my-vol,target=/app \ node:lts docker run -d \ --name devtest \ --mount source=my-vol,target=/app \ node:lts     
     docker run -d \ --name devtest \ -v my-vol:/app \ node:lts docker run -d \ --name devtest \ -v my-vol:/app \ node:lts     

    Проверьте корректность результата выполнения команды:

     docker inspect devtest docker inspect devtest     

    Чтобы удалить том, необходимо отключить связанный с ним контейнер и удалить сам контейнер:

     docker container stop devtestdocker container rm devtestdocker volume rm my-vol docker container stop devtest docker container rm devtest docker volume rm my-vol     

    Управлять томами можно через Docker API с помощью Docker CLI и Docker Compose.

    Чтобы создать новый том с помощью Docker CLI, используйте команду:

     docker volume create my-vol docker volume create my-vol     

    Получите список томов на хосте:

     docker volume ls docker volume ls      

    Посмотрите информацию о томе:

     docker volume inspect my-vol docker volume inspect my-vol     

    Удалите том командой:

     docker volume rm my-vol docker volume rm my-vol     

    Если том был анонимным, то можно удалить его сразу после завершения работы контейнера. Для этого при запуске контейнера вы можете прописать флаг — — rm . Вместе с удалением контейнера в этом случае удалится и том:

     docker run --rm -v /foo -v awesome:/bar container app docker run --rm -v /foo -v awesome:/bar container app     

    После завершения работы и последующего удаления контейнера анонимный том удалится, а именованный awesome продолжит работать.

    Чтобы удалить все неиспользуемые тома, используйте команду:

     docker volume prune docker volume prune     

    Для того, чтобы подключить том с помощью Dockerfile, необходимо использовать инструкцию VOLUME :

     FROM node:ltsRUN useradd userRUN mkdir /data && touch /data/xRUN chown -R user:user /dataVOLUME /data FROM node:lts RUN useradd user RUN mkdir /data && touch /data/x RUN chown -R user:user /data VOLUME /data      

    Интересно, что вы не сможете внести какие-либо изменения в данные на этапе сборки образа. Следующий Dockerfile правильно работать не будет:

     FROM node:ltsRUN useradd userVOLUME /dataRUN touch /data/xRUN chown -R user:user /data FROM node:lts RUN useradd user VOLUME /data RUN touch /data/x RUN chown -R user:user /data      

    Том будет подключён только после создания образа на этапе запуска контейнера. Возможно, придётся использовать инструкции CMD или ENTRYPOINT . Подробнее описано в статье «Как устроен Dockerfile».

    Запустить том для отдельного контейнера с Docker Compose можно с помощью следующей конфигурации:

     services: frontend: image: node:lts volumes: - myapp:/home/node/appvolumes: myapp: services: frontend: image: node:lts volumes: - myapp:/home/node/app volumes: myapp:      

    Команда docker — compose up поднимет не только сам контейнер frontend , но и создаст том myapp . Если он уже был создан, Docker Compose подключит его к контейнеру, но надо указать это явно с помощью элемента external так:

     services: frontend: image: node:lts volumes: - myapp:/home/node/appvolumes: myapp: external: true services: frontend: image: node:lts volumes: - myapp:/home/node/app volumes: myapp: external: true      

    Подробнее о формате конфигурации Docker Compose можно прочитать в статье о Docker Compose.

    Использование драйверов

    Скопировать ссылку «Использование драйверов» Скопировано

    Когда приходит время масштабировать приложение, несколько сервисов должны работать с одним хранилищем данных. Для этого существует масса решений, и у Docker есть своё — драйверы для томов. Это лишь один пример использования драйверов. Можно организовать, например, пересылку данных между контейнерами с поддержкой шифрования или автоматическое шифрование и дешифровку всех данных в томе. Можно реализовать любой механизм обработки данных. Драйверы повышают уровень абстракции, позволяя отделить логику работы приложения от системы хранения данных.

    Например, есть два компьютера — хост, на котором установлен Docker и запускаются контейнеры, и файловый сервер, который поставляет данные для них. Контейнеры ничего не знают про эту архитектуру: все запускалось изначально на локальном хосте. Драйвер vieux / sshfs позволяет использовать SSH-соединение для связи с файловым сервером, при этом данные будут представлены в виде тома Docker.

    Для начала необходимо установить соответствующий плагин для Docker Engine:

     docker plugin install --grant-all-permissions vieux/sshfs docker plugin install --grant-all-permissions vieux/sshfs     

    Затем нужно создать том и прописать учётные данные:

     docker volume create --driver vieux/sshfs \ -o sshcmd=test@node2:/home/test \ -o password=testpassword \ sshvolume docker volume create --driver vieux/sshfs \ -o sshcmd=test@node2:/home/test \ -o password=testpassword \ sshvolume     

    Если для связи по SSH между клиентом и сервером уже работают ключи доступа, то пароль можно опустить. Флаг -o указывает на опции, которые могут быть переданы драйверу. Набор доступных опций у каждого драйвера свой.

    Можно создать том и другим способом, при запуске контейнера:

     docker run -d \ --name sshfs-container \ --volume-driver vieux/sshfs \ --mount src=sshvolume,target=/app,volume-opt=sshcmd=test@node2:/home/test,volume-opt=password=testpassword \ nginx:latest docker run -d \ --name sshfs-container \ --volume-driver vieux/sshfs \ --mount src=sshvolume,target=/app,volume-opt=sshcmd=test@node2:/home/test,volume-opt=password=testpassword \ nginx:latest     

    Если драйвер требует передачи опций, приходится использовать флаг — — mount .

    Резервные копии

    Скопировать ссылку «Резервные копии» Скопировано

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

     docker run -v /dbdata --name dbstore node:lts /bin/bash docker run -v /dbdata --name dbstore node:lts /bin/bash     

    Как создать резервную копию данных в томе? Нужно:

    — запустить новый контейнер и примонтировать том, который используется в контейнере dbstore ;
    — примонтировать папку на хосте, чтобы потом в неё положить резервную копию;
    — зайти внутри контейнера в том, заархивировать данные и положить их в связанную папку.

     docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata     

    После завершения архивации контейнер выключится и удалится, а резервная копия останется у вас в папке, из которой вы запускали команду.

    Допустим, у вас возникла необходимость развернуть данные из сохранённой резервной копии внутри контейнера dbstore2 . Нужно запустить его:

     docker run -v /dbdata --name dbstore2 node:lts /bin/bash docker run -v /dbdata --name dbstore2 node:lts /bin/bash     

    Затем разархивировать данные в том:

     docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1" docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1"      

    Хранение в оперативной памяти

    Скопировать ссылку «Хранение в оперативной памяти» Скопировано

    Хранение в оперативной памяти бывает двух типов: tmpfs mounts и npipe mounts.

    Механизм tmpfs mount в операционной системе Linux позволяет выделить часть оперативной памяти хоста для хранения данных. Данные не сохраняются в файловой системе, и получается быстрое хранилище. Примонтированная папка tmpfs работает, пока запущен контейнер, поэтому не стоит использовать этот способ для хранения настроек и результатов работы приложения.

    Для пользователей операционной системы Windows существует ещё один тип управления данными — npipe mount. Этот тип позволяет получить доступ к хосту Docker из контейнера и в основном используется для управления данными с Docker Engine API.

    Используем оперативную память:

    Если вы не хотите оставлять данные после завершения работы приложения.

    Как пользоваться

    Скопировать ссылку «Как пользоваться» Скопировано

    Этот раздел посвящён использованию только на Linux.

    С помощью томов и связанных папок вы можете делиться файлами между хостом и контейнером. После остановки контейнера данные сохраняются. Но если на хосте используется операционная система Linux, то существует и третий тип работы с данными — tmpfs. Это временное файловое хранилище, которое располагается в оперативной памяти, присутствует во многих Unix-подобных системах. Когда вы создаёте контейнер, Docker может создать отдельный слой в оперативной памяти снаружи контейнера для хранения и обработки данных.

    При использовании этого типа работы с данными в Docker есть два ограничения:

    — операционной системой хоста может быть только Linux;
    — данные в tmpfs доступны лишь из одного контейнера.

    tmpfs хорошо работает в случае хранения чувствительной информации: ключей шифрования, паролей, сертификатов доступа и тому подобного.

    Чтобы запустить контейнер с tmpfs, используют команду:

     docker run -d \ -it \ --name tmptest \ --mount type=tmpfs,destination=/app \ node:lts docker run -d \ -it \ --name tmptest \ --mount type=tmpfs,destination=/app \ node:lts     

    С помощью ключа tmpfs — size можно определить максимальный размер хранилища в байтах. По умолчанию он не ограничен. Ключ tmpfs — mode служит для определения уровня доступа в восьмеричном формате. Например, значение по умолчанию 1777 обозначает, что любой пользователь или программа в контейнере имеют неограниченный доступ к данным, которые будут доступны и вне контейнера. Этот параметр работает также, как и для tmpfs в Unix-подобных операционных системах.

    Также есть альтернативная более короткая команда для управления tmpfs mounts:

     docker run -d \ -it \ --name tmptest \ --tmpfs /app \ node:lts docker run -d \ -it \ --name tmptest \ --tmpfs /app \ node:lts     

    Проверьте состояние контейнера, чтобы убедиться, что файловое хранилище создано корректно:

     docker container inspect tmptest docker container inspect tmptest     

    В соответствующей секции будет доступна информация о примонтированной папке:

     "Tmpfs":  "/app": "">, "Tmpfs":  "/app": "" >,      

    Для удаления слоя с данными выполните команды остановки и удаления контейнера:

     docker container stop tmptestdocker container rm tmptest docker container stop tmptest docker container rm tmptest     

    На практике

    Скопировать ссылку «На практике» Скопировано

    Игорь Коровченко советует

    Скопировать ссылку «Игорь Коровченко советует» Скопировано

    ✨ Вы можете получить данные из определённой папки контейнера, если примонтируете к ней пустую папку или пустой том на хосте. После монтирования данные автоматически окажутся доступны с хоста и останутся там после работы контейнера. Это удобный способ сделать бэкап или получить результаты работы приложения.

    Если папка или том окажутся не пустыми, то при монтировании к контейнеру содержимое будет на время скрыто. Контейнер будет воспринимать эту папку как пустую, данные будут в неё сохраняться и будут доступны с хоста во время работы контейнера. После окончания работы контейнера или после того, как том или папка будут отмонтированы, данные из контейнера будут потеряны, поскольку снова будут доступны те файлы и подпапки, которые были скрыты при монтировании. Это тот же механизм, который Linux будет использовать, когда вы, например, примонтируете USB-накопитель к уже заполненной чем-то папке.

    На собеседовании

    Скопировать ссылку «На собеседовании» Скопировано

Добавить комментарий

Ваш адрес email не будет опубликован. Обязательные поля помечены *