Docker: named volumes — правильная работа с томами

В терминологии Докера, тома (volumes) — это места для длительного хранения важных файлов (баз данных, логов и тд).

Принцип работы прост: определённые директории внутри контейнера (например, /var/lib/mysql или /var/log/nginx) монтируются извне. Можно уничтожить контейнер и создать на его месте новый — например, из обновленного Dockerfile или более свежего базового образа — и при этом драгоценные данные, размещенные на томах, останутся в целости и сохранности.

До версии Docker 1.10 было два способа работы с томами:

  • Bind-mounts — монтирование внешних папок параметром -v /host:/container (как в статье про MySQL внутри Докера).

  • Data-only containers — создание специального контейнера-спутника и использование его файловой системы для хранения данных (параметр --volumes-from).

Для томов существует проблема начальной инициализации (initial volume seeding). Когда том первый раз монтируется поверх существующей директории (например, /var/lib/mysql), то для продолжения нормальной работы необходимо сделать так, чтобы контейнер не заметил подмены. Иначе говоря, нужно сделать chown, chmod и скопировать в пустой том файлы из образа.

К сожалению, в этом месте bind-mounts и data-only containers ведут себя по-разному. В первом случае приходится делать это вручную (см. mysql_install_db в статье про MySQL), и получается, что при внешней простоте и привлекательности подхода, он становится неудобным в использовании.

На GitHub поднимался вопрос о нормализации поведения (#9092, #17152), но дальше обсуждений дело не зашло. Решили только (#17152, comment), что в версии 1.11 внешние папки надо будет создавать явно, чтобы подчеркнуть, что в этом случае Docker сам ничего не делает, но позже (#19953, comment) отказались от этой идеи, и всё осталось по-старому.

Data-only containers тоже не идеальны, а наоборот — больше похожи на костыль. Статья Data-only container madness (написанная одним из разработчиков Docker-а) не даром так озаглавлена.

Обновление. На DockerCon 2016 @cpuguy83, отвечая на вопрос из зала, сказал, что bind-mounts и вовсе не следует называть томами. Как говорится, «его пример другим наука». Если бы разработчики Докера заранее продумали архитектуру такой важной функциональности как хранение данных, всей этой глобальной путаницы могло бы и не быть!

Словом, ситуацию надо было как-то улучшать, и в результате в арсенал Докера были добавлены именованные тома. Давайте посмотрим на них в действии!

Именованный том создаётся командой:

docker volume create --name=mysql-data

И размещается в предсказуемом месте: /var/lib/docker/volumes/mysql-data

Теперь соберём небольшой тестовый образ с MySQL внутри:

FROM ubuntu:16.04

RUN export DEBIAN_FRONTEND=noninteractive \
    && apt-get update \
    && apt-get install -y mysql-server
docker build -t local/img1 .

И запустим контейнер, смонтировав созданный том в /var/lib/mysql:

docker run -v mysql-data:/var/lib/mysql local/img1 true

Как видите, делается это так же, как и в случае с монтированием внешних папок. Ключевое отличие: в значении параметра -v слева от двоеточия нет косых.

После первого использования том получает правильные права доступа и наполняется контентом из /var/lib/mysql:

ls /var/lib/docker/volumes/mysql-data/_data
debian-5.6.flag  ibdata1  ib_logfile0  ib_logfile1  mysql  performance_schema

Можно вывести список имеющихся томов:

docker volume ls

DRIVER              VOLUME NAME
local               mysql-data

И посмотреть информацию о конкретном томе:

docker volume inspect mysql-data

[
    {
        "Name": "mysql-data",
        "Driver": "local",
        "Mountpoint": "/var/lib/docker/volumes/mysql-data/_data"
    }
]

По-моему, прекрасно!


Все материалы по теме Docker:

Видео:

Статьи:

Устаревшее:

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

  1. Александр:

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

  2. Алексей:

    @Александр

    По поводу производительности не скажу.

    По поводу удобства. Для папок типа htdocs, содержимое которых вы полностью контролируете, старое монтирование и новые именованные тома примерно одинаково удобны: в обоих случаях файлы лежат в известных местах, и вам необходимо обеспечить правильные права доступа. Data-only containers — самый странный и неудобный способ из доступных сегодня, для любых файлов.

  3. Андрей:

    А можно ли задать расположение /var/lib/docker/volumes/mysql-data ?

  4. Денис:

    Спасибо, ценная статья!

  5. Vasili:

    Как теперь можно прочитать данные из хранилища в другом контейнере? Например, есть еще один контейнер nginx, и я хочу подключить named volume к нему и показывать картинки.

    Спасибо

  6. Приветствую! Христос воскрес! Слышал про docker и раньше, но все как-то не было времени на изучение. Начал знакомство с docker на твоих видео на youtube. Теперь читаю блог. Спасибо за ценную информацию в сжатом и доступном виде. Docker — это то, чего мне не хватало для решения некоторых задач. Желаю благополучия и успехов во всех начинаниях!

Ваш комментарий