Управление данными в контейнерах

Kate

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

Тома данных​


Том данных специально отведенная директория для одного или более контейнера, которая не использует Union File System. Тома данных обеспечивают несколько полезных функций для совместного использования данных:
  • Тома инициализируются при создании контейнера. Если базовый образ контейнера содержит данные в точке монтирования, эти данные копируются в новый том при инициализации. (Обратите внимание что это не применяется при монтирование каталога хоста.)
  • Тома данных могут быть использованы между контейнерами.
  • Изменения в томах данных производятся напрямую .
  • Изменения в томах данных не включаются когда вы обновляете образ.
  • Тома данных сохраняются даже при удалении контейнера.
Тома данных разработаны для сохранения данных, не зависимо от жизненного цикла контейнера. По этому Docker никогда не удаляет тома при удалении контейнера и не убирает их в мусор если ни один контейнер больше не ссылается на них .

Добавление тома данных​

Вы можете добавить том данных к контейнеру используя флаг -v с командой docker create или docker run. Вы можете использовать -v несколько раз для подключения нескольких томов. Теперь подключим одиночный том к вашему контейнеру.
$ docker run -d -P --name web -v /webapp training/webapp python app.py

Эта команда создаст новый том в контейнере /webapp.
Примечание: Вы можете использовать инструкцию VOLUME внутри Dockerfile для добавления одного или нескольких томов в любой контейнер создаваемый из этого образа.

Поиск томов​

Вы можете посмотреть томы на хосте с помощью команды docker inspect.
$ docker inspect web

В результате будет отображена подробная информация о конфигурации контейнеров включая тома. Вывод будет примерно таким:
...
"Mounts": [
{
"Name": "fac362...80535",
"Source": "/var/lib/docker/volumes/fac362...80535/_data",
"Destination": "/webapp",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
]
...

В приведенном выше примере Source отображает местоположение на хосте и Destination расположение тома внутри контейнера. RW отображает доступность для чтения/записи.

Монтируем каталог хоста как том данных​

В дополнение к созданию тома с помощью флага -v вы также можете монтировать каталог из Docker engine хоста внутри контейнера.
$ docker run -d -P --name web -v /src/webapp:/opt/webapp training/webapp python app.py

Эта команда монтирует каталог хоста, /src/webapp, внутрь контейнера /opt/webapp. Если путь /opt/webapp уже существует внутри родительского образа контейнера, то /src/webapp монтируется наложением и не удаляет уже существующий контент. После удаления монтирования, контент будет вновь доступен. Это согласуется с ожидаемым поведением команды mount.
Каталог в контейнере должен всегда указываться через абсолютный путь, например так /src/docs. Каталог на хосте может быть указан как в виде абсолютного пути так и в виде имени. Если вы укажете абсолютный путь для хост-каталога, Docker монтируется на путь, который вы укажете. Если вы укажете имя, Docker создает названный том с таким именем.
Имя тома должно начинаться с буквы или цифры и состоять из символов a-z0-9, _ (нижнее подчеркивание), . или - (дефис). Абсолютный путь начинается с / (косой черты).
к примеру, вы можете указать либо /foo либо foo для каталога хоста. Если вы указываете /foo, Docker Engine создает точку монтирования. Если указать foo, Докер создаст именованный том.
Если вы используете Docker Machine на Mac или Windows, ваш Docker Engine демон будет иметь ограниченный доступ к файловой системе OS X или Windows. Docker Machine пытается автоматически расшарить каталоги /Users (OS X) или C:\Users (Windows). В OS X вы можете монтировать файлы и директории используя команду:
docker run -v /Users/<path>:/<container path> ...

В Windows, можно монтировать директории так:
docker run -v c:\<path>:/c:\<container path>

Все остальные пути происходят из файловой системы вашей аиртуальной машины, так что если вы хотите расшарить другие каталоги хоста, вам нужно выполнить дополнительные действия. В случае с VirtualBox вам необходимо сделать каталог хоста доступным для шернига в VirtualBox. После чего, вы можете монтировать каталог с помощью флага -v.
Монтаж каталога хоста может быть полезным для тестирования. К примеру, вы можете монтировать исходный код внутрь контейнера. Затем изменить исходный код и посмотреть на результат выполнения приложения в реальном времени. Каталог на хосте должен быть указан через абсолютный путь и если каталог не существует, демон Docker Engine автоматически создаст его для вас.
Тома Docker по умолчанию монтируются в режиме чтения-записи, но вы также можете установить режим только для чтения.
$ docker run -d -P --name web -v /src/webapp:/opt/webapp:ro training/webapp python app.py

Здесь вы смонтировали ту же директорию /src/webapp но добавили опцию ro для того что бы директория была доступна только для чтения.
Из-за ограничений функции mount, перемещение подкаталогов внутри каталога исходного хоста может открыть доступ из контейнера к файловой системе хоста. Для этого злоумышленнику потребуется доступ к хосту и смонтированному каталогу .
Примечание: Каталог хоста, по своей природе, хост-зависим. По этой причине, вы не можете смонтировать каталог хоста из Dockerfile поскольку сборка образов должна быть портативной. Каталог хоста не будет доступен для всех потенциальных хозяев.

Монтирование разделяемого хранилища в качестве тома данных​

В дополнение к монтированию каталога хоста в вашем контейнере, есть плагины для Docker позволяющие монтировать хранилища данных разных типов: iSCSI, NFS или FC.
Преимущество использования общих томов заключается в том что они не зависят от хоста. Это означает что том может быть доступен на любом хосте на котором запущен контейнер, до тех пор пока есть доступ к общему хранилищу данных и установлен плагин.
Один из способов использовать драйвера томов это команда docker run. Драйвера создают тома по имени, а не по пути как в других примерах.
Следующая команда создает именованный том, с названием my-named-volume, используя драйвер тома flocker, и делает его доступным из контейнера /opt/webapp:
$ docker run -d -P \
--volume-driver=flocker \
-v my-named-volume:/opt/webapp \
--name web training/webapp python app.py

Также вы можете использовать команду docker volume create, для создания тома перед тем как использовать его в контейнере.
Приведенный пример также создает том my-named-volume, на этот раз с помощью команды docker volume create.
$ docker volume create -d flocker -o size=20GB my-named-volume

$ docker run -d -P \
-v my-named-volume:/opt/webapp \
--name web training/webapp python app.py

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

Ярлыки томов​

Системы использующие метки, такие как SELinux требуют что бы соответствующие метки были размещены в содержимом томов смонтированных в контейнер. Без метки, система безопасности может блокировать процессы запущенные внутри контейнера и пытающиеся получить доступ к данным из тома. По умолчанию Docker не меняет метки установленные ОС.
Что бы изменить метку в контексте контейнера, вы можете добавить любой из двух суффиксов :z или :Z к тому при монтировании. Эти суффиксы указывают Docker переразметить файловые объекты на общих томах. Опция z говорит Docker что два контейнера разделяют содержимое тома. В результате, Docker размечает контент как общий. Метки общих томов позволяют всем контейнерам читать и записывать контент. Опция Z указывает Docker пометить контент как приватный. Только текущий контейнер может может использовать приватный том.

Монтирование файла хоста как тома данных​

Флаг -v также может быть использован для монтирования одиночного файла, а не только директории из хост машины.
$ docker run --rm -it -v ~/.bash_history:/root/.bash_history ubuntu /bin/bash

Вы попадете в bash shell нового контейнера, при этом вы будете видеть историю команд терминала хоста и когда вы выйдите из контейнера, хост будет отображать историю команд контейнера.
Примечание: Многие инструменты используемые для редактирования файлов, включая vi и sed --in-place могут привести к изменению индексного дескриптора. Начиная с версии Docker v1.1.0, «sed: cannot rename ./sedKdJ9Dy: Device or resource busy». В случае когда вы хотите отредактировать смонтированный файл, часто проще смонтировать родительский каталог.

Создание и монтирование контейнера тома данных​

Если у вас есть какие-то постоянные данные которые вы хотите сделать доступными для контейнеров, или использовать из временных контейнеров, то лучше всего создать контейнер с именованным томом данных, а затем монтировать данные из него.
Давайте создадим новый именованный контейнер с общим томом. Поскольку этот контейнер не запускает приложения мы возьмем образ training/postgres таким образом все контейнеры будут использовать общие слои, экономя дисковое пространство..
$ docker create -v /dbdata --name dbstore training/postgres /bin/true

Вы можете использовать флаг --volumes-from для монтирования тома /dbdata к другому контейнеру.
$ docker run -d --volumes-from dbstore --name db1 training/postgres

И еще одному:
$ docker run -d --volumes-from dbstore --name db2 training/postgres

В этом случае, если образ postgres содержит каталог с названием /dbdata после монтирования тома dbstore контейнер скроет файлы в /dbdata из образа postgres. В результате будут доступны только файлы из контейнера dbstore.
Вы можете использовать несколько параметров --volumes-from для комбинирования томов данных из нескольких контейнеров. Что бы найти подробную информацию о --volumes-from читайте Монтирование томов из контейнера в руководстве по команде run.
Вы можете также расширить цепочку смонтировав том из контейнера dbstoreв другой контейнер через контейнеры db1 или db2.
$ docker run -d --name db3 --volumes-from db1 training/postgres

При удалении контейнеров в которых смонтированы тома, в том числе контейнер dbstore или последующие контейнеры db1 или db2, тома не удаляются. Для удаления тома с диска, вам нужно применить к контейнеру команду docker rm -v со ссылкой на том. Это позволяет обновлять или эффективно переносить тома данных между контейнерами.
Примечание: Docker не будет предупреждать вас при удалении контейнера без использования флага -v для удаления томов. Если вы удаляете контейнеры без использования флага -v, вы оставляете оборванные тома, которые больше не связаны с контейнером. Вы можете использовать команду docker volume ls -f dangling=true для поиска оборванных томов, и используйте команду docker volume rm <volume name> для удаления томов которые больше не нужны.

Резервное копирование, восстановление и миграция томов данных​

Еще одна полезная функция для томов это резервное копирование, восстановление и миграции. Вы можете использовать флаг --volumes-from для создания нового контейнера который монтирует необходимый том, например так:
$ docker run --rm --volumes-from dbstore -v $(pwd):/backup ubuntu tar cvf /backup/backup.tar /dbdata

Здесь мы запустили новый контейнер и смонтировали том из контейнера dbstore. Затем была смонтирован каталог локального хоста /backup. В конце, передается команда использующая tar для резервного копирования содержимого тома dbdata в файл backup.tar лежащий в директории /backup. Когда команда выполнена и контейнер остановлен у нас остается резервная копия тома dbdata.
Вы можете восстановить резервную копию в том же контейнере, или в любом другом.
$ docker run -v /dbdata --name dbstore2 ubuntu /bin/bash

Затем распакуйте архив резервной копии новом томе контейнера.
$ docker run --rm --volumes-from dbstore2 -v $(pwd):/backup ubuntu bash -c "cd /dbdata && tar xvf /backup/backup.tar --strip 1"

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

Удаление томов​

Том данных сохраняется после того как контейнер удаляется. Вы можете создавать именованные или анонимные тома. Именованные тома имеют заданную форму источника вне контейнера, к примеру awesome:/bar. Анонимные тома не имеют конкретного источника. Когда контейнер удаляется Docker Engine демон очищает анонимные тома. Для этого используйте опцию --rm, к примеру:
$ docker run --rm -v /foo -v awesome:/bar busybox top

Эта команда создает анонимный том /foo. Когда контейнер удален, Docker Engine удаляет том /foo, но не awesome.

Важные советы по использованию общих томов​

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

Следующие шаги​

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


Источник статьи: https://dker.ru/docs/docker-engine/learn-by-example/manage-data-in-containers/
 
Сверху