Обмен данными между контейнерами Docker
Ubuntu | Комментировать запись
Docker – это популярный инструмент для контейнеризации. Контейнеры Docker обеспечивают идентичное поведение программ в разных средах.
Docker-контейнеры непостоянны, они существуют только в течение выполнения задачи или команды, для запуска которой они предназначены.
Однако в некоторых ситуациях приложения должны совместно использовать данные или сохранять данные после остановки контейнера. Базы данных, пользовательский контент веб-сайтов, логи – лишь несколько примеров данных, которые нецелесообразно или невозможно включить в контейнер Docker ; но приложениям такие данные крайне необходимы. Постоянный доступ к данным могут обеспечить тома Docker.
Требования
- Сервер Ubuntu 16.04 (начальная настройка описана здесь).
- Пользователь с доступом к команде sudo.
- Docker (инструкции по установке можно найти здесь).
Примечание: данное руководство предназначено для сервера Ubuntu 16.04, однако команды docker одинаково работают в разных операционных системах (если пользователь с доступом к sudo добавлен в группу docker).
Тома Docker можно создать и присоединить во время создания контейнера. Также том можно создать отдельно от контейнера и присоединить его позже. Данное руководство описывает несколько способов настройки совместного использования данных контейнерами.
1: Независимый том
В Docker’s 1.9 была добавлена команда docker volume create, которая позволяет создавать тома отдельно от контейнеров. К примеру, чтобы добавить том DataVolume1, нужно ввести:
docker volume create --name DataVolume1
Если команда выполнена успешно, на экране появится имя контейнера:
DataVolume1
Чтобы использовать этот том, создайте новый контейнер с помощью образа Ubuntu, используя –rm флаг, чтобы автоматически удалить его при выходе.
Чтобы смонтировать новый том, нужно использовать опцию -v. Эта опция требует имя тома; после имени нужно поставить двоеточие и указать абсолютный путь к тому внутри контейнера. Если в контейнере/образе нет такого каталога, команда создаст его. Если каталог существует, смонтированный том удалит всё его содержимое.
docker run -ti --rm -v DataVolume1:/datavolume1 ubuntu
Добавьте в том данные:
echo "Example1" > /datavolume1/Example1.txt
Поскольку при запуске был использован флаг –rm, контейнер будет автоматически удалён, если его закрыть. Однако к тому это не относится – он останется в системе.
exit
Убедитесь, что том существует в системе:
docker volume inspect DataVolume1
[
{
"Name": "DataVolume1",
"Driver": "local",
"Mountpoint": "/var/lib/docker/volumes/datavolume1/_data",
"Labels": null,
"Scope": "local"
}
]
Примечание: Просмотреть эти данные можно даже на хосте, для этого нужно перейти в точку монтирования. Однако при этом нельзя изменять данные – это приведёт к ошибкам и нарушению целостности данных в приложении или контейнере.
Попробуйте запустить новый контейнер и прикрепить к нему том DataVolume1:
docker run --rm -ti -v DataVolume1:/datavolume1 ubuntu
cat /datavolume1/Example1.txt
Example1
Закройте контейнер:
exit
2: Как сохранить том после удаления контейнера
Теперь попробуйте создать новый том вместе с контейнером, а затем удалите контейнер и прикрепите том к новому контейнеру.
Создайте новый контейнер с помощью команды docker run на основе образа ubuntu. Флаг –t предоставит терминал, -i позволит с ним взаимодействовать. Чтобы указать имя, используйте –name.
Добавьте флаг –v, чтобы создать том. Он будет называться DataVolume2. После имени через двоеточие нужно указать путь к точке монтирования. В конце команды нужно указать базовый образ Ubuntu. Встроенная в образ команда bash развернёт оболочку контейнера.
docker run -ti --name=Container2 -v DataVolume2:/datavolume2 ubuntu
Примечание: Флаг –v очень гибкий. Он также используется для выбора имени тома. Если первый аргумент начинается с / или ~/, флаг выполнит монтирование. В противном случае он присвоит тому имя.
-v /path:/path/in/container смонтирует каталоги /path и /path/in/container
-v path:/path/in/container создаст том по имени path, не имеющий никакого отношения к хосту.
Читайте также: Обмен данными между контейнером Docker и хостом
Теперь вы в контейнере. Добавьте данные в том.
echo "Example2" > /datavolume2/Example2.txt
cat /datavolume2/Example2.txt
Example2
Закройте контейнер:
exit
Перезапустите его, и том будет смонтирован автоматически:
docker start -ai Container2
Убедитесь, что том успешно смонтирован и все данные на месте:
cat /datavolume2/Example2.txt
Example2
Закройте контейнер:
exit
Docker не позволит удалить том, если на него ссылается какой-либо контейнер. Попробуйте удалить том:
docker volume rm DataVolume2
Эта команда выдаст ошибку, поскольку том используется контейнером, ID которого указан в конце сообщения.
Error response from daemon: Unable to remove volume,
volume still in use: remove DataVolume2: volume is in use -
[719f98391ecf1d6f0f053ffea1bbd84cd2dc9cf6d31d5a4f348c60d98392804c]
Чтобы удалить контейнер, укажите его ID:
docker rm 719f98391ecf1d6f0f053ffea1bbd84cd2dc9cf6d31d5a4f348c60d98392804c
719f98391ecf1d6f0f053ffea1bbd84cd2dc9cf6d31d5a4f348c60d98392804c
Удаление контейнера никак не повлияет на том. Убедитесь, что том присутствует в системе:
docker volume ls
DRIVER VOLUME NAME
local DataVolume2
Чтобы удалить том, введите:
docker volume rm DataVolume2
Теперь вы знаете, как создать пустой том данных вместе с контейнером.
3: Создание тома на основе существующих данных
В целом том, созданный отдельно от контейнера, почти ничем не отличается от тома, созданного вместе с контейнером. Но одно отличие всё же есть: если, создавая том вместе с контейнером, вы укажете путь к каталогу, в котором хранятся данные, эти данные будут скопированы в том.
Для примера попробуйте создать контейнер и добавить том в /var (в базовом образе этот каталог содержит некоторые данные).
docker run -ti --rm -v DataVolume3:/var ubuntu
Содержимое каталога /var из исходного образа будет скопировано в том. Этот том можно смонтировать в новый контейнер. В этот раз используйте команду ls, которая выведет на экран содержимое каталога:
docker run --rm -v DataVolume3:/datavolume3 ubuntu ls DataVolume3
Том DataVolume3 является копией каталога /var.
backups
cache
lib
local
lock
log
mail
opt
run
spool
tmp
Эта функция будет полезна при необходимости сохранить данные собственного образа.
4: Совместное использование тома
Теперь попробуйте присоединить несколько контейнеров к одному тому данных.
Это относительно просто сделать, но есть один важный нюанс: при этом Docker не блокирует файлы. Если подключенные контейнеры должны записывать данные в том, приложения, запущенные в этих контейнерах, должны быть разработаны для записи в общие хранилища данных (с целью предотвращения повреждения данных).
Создайте новый контейнер и том (Container4 и DataVolume4).
docker run -ti --name=Container4 -v DataVolume4:/datavolume4 ubuntu
Создайте файл и добавьте в него какой-нибудь текст:
echo "This file is shared between containers" > /datavolume4/Example4.txt
Закройте контейнер:
exit
Эта команда вернёт вас в командную строку хоста, с помощью которой вы сможете создать новый контейнер и смонтировать его с томом данных DataVolume4.
Создайте Container5 и смонтируйте том Container4:
docker run -ti --name=Container5 --volumes-from Container4 ubuntu
cat /datavolume4/Example4.txt
This file is shared between containers
Добавьте в файл текст, находясь в Container5:
echo "Both containers can write to DataVolume4" >> /datavolume4/Example4.txt
Закройте контейнер:
exit
Теперь убедитесь, что данные остались в контейнере Container4.
Просмотрите изменения, внесённые в контейнере Container5. Перезапустите Container4:
docker start -ai Container4
cat /datavolume4/Example4.txt
cat /DataVolume4/Example4.txt
This file is shared between containers
Both containers can write to DataVolume4
Как видите, оба контейнера имеют право на чтение и запись в томе данных.
Закройте контейнер Container4:
exit
Как уже говорилось, Docker не блокирует файлы. Потому приложения, запущенные в контейнерах, должны делать это самостоятельно. Добавив :ro, том можно смонтировать в режиме только для чтения, чтобы не допустить случайного повреждения данных. попробуйте сделать это.
Смонтируйте том только для чтения в контейнере Container6. При этом нужно создать новый контейнер, подключить его к тому, а затем удалить старый контейнер. Демонтировать том не придётся.
Чтобы смонтировать том только для чтения, используйте опцию :ro после имени контейнера:
docker run -ti --name=Container6 --volumes-from Container4:ro ubuntu
Чтобы убедиться, что контейнер ограничен правом на чтение тома, попробуйте удалить тестовый файл:
rm /datavolume4/Example4.txt
rm: cannot remove '/datavolume4/Example4.txt': Read-only file system
Закройте контейнер:
exit
Теперь можно удалить контейнеры и том.
docker rm Container4 Container5 Container6
docker volume rm DataVolume4
Заключение
Теперь вы умеете настраивать совместное использование данных между несколькими контейнерами.
Читайте также: Обмен данными между контейнером Docker и хостом
Tags: Docker, Ubuntu 16.04