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

К этому моменту, вы уже изучили некоторые основные концепции 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.


Комментарии:

Комментариев нет, желаете стать первым?

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