Какова практическая цель VOLUME в Dockerfile?

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

Я понимаю что когда VOLUME указывается в Dockerfile, это дает указание Docker создавать безымянный том на время работы контейнера, который сопоставлен с указанным каталогом внутри него. Например:

# Dockerfile
VOLUME ["/foo"]

Это создаст том для хранения любых данных, хранящихся в /foo внутри контейнера. Объем (при просмотре через docker volume ls) будет отображаться как случайный набор чисел.

Каждый раз, когда вы делаете docker runэтот том не используется повторно. Это ключевой момент, вызывающий путаницу здесь. Для меня цель тома состоит в том, чтобы содержать постоянное состояние во всех экземплярах изображения (все контейнеры, запущенные с него). Так что, в основном, если я сделаю это, без явного отображения тома:

#!/usr/bin/env bash
# Run container for the first time
docker run -t foo

# Kill the container and re-run it again. Note that the previous 
# volume would now contain data because services running in `foo`
# would have written data to that volume.
docker container stop foo
docker container rm foo

# Run container a second time
docker run -t foo

Я ожидаю, что безымянный том будет повторно использован между 2 run команды. Однако, это не так. Потому что я явно не отображал том через -v опция, новый объем создается для каждого run,

Вот важная часть номер 2: так как я должен явно указать -v делить постоянное состояние между run команды, зачем мне указывать VOLUME в моем Dockerfile? Без VOLUMEЯ могу сделать это (используя предыдущий пример):

#!/usr/bin/env bash
# Create a volume for state persistence
docker volume create foo_data

# Run container for the first time
docker run -t -v foo_data:/foo foo

# Kill the container and re-run it again. Note that the previous 
# volume would now contain data because services running in `foo`
# would have written data to that volume.
docker container stop foo
docker container rm foo

# Run container a second time
docker run -t -v foo_data:/foo foo

Теперь, действительно, второй контейнер будет иметь данные, смонтированные в /foo это было там из предыдущего экземпляра. Я могу сделать это без VOLUME в моем Dockerfile. Из командной строки я могу превратить любой каталог внутри контейнера в монтирование в привязанный каталог на хосте или томе в Docker.

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

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

1 ответ

Инструкции как VOLUME а также EXPOSE немного анахронизм. Именованные тома в том виде, в каком мы их знаем сегодня, были введены в Docker 1.9 почти три года назад.

До Docker 1.9 запускался контейнер, в образе которого был один или несколько VOLUME инструкции (или с помощью --volume вариант) был единственным способом создания томов для обмена данными или сохранения. На самом деле, это была лучшая практика - создавать контейнеры только для данных, единственной целью которых было удержание одного или нескольких томов, а затем делиться этими томами с контейнерами приложения, используя --volumes-from вариант. Вот несколько статей, которые описывают этот устаревший шаблон.

Кроме того, проверьте moby/moby#17798 (контейнеры только для данных, устаревшие с докером 1.9.0?), Где обсуждалось изменение от контейнеров только для данных к именованным томам.

Сегодня я считаю VOLUME Инструкция как продвинутый инструмент, который следует использовать только для специализированных случаев и после тщательного обдумывания. Например, официальное изображение postgres объявляет VOLUME в /var/lib/postgresql/data, Это может улучшить производительность контейнеров postgres из коробки, не допуская данных базы данных из многоуровневой файловой системы. Docker не должен искать во всех слоях изображения контейнера для запросов файлов в /var/lib/postgresql/data,

Тем не менее VOLUME Инструкция действительно стоит денег.

  • Пользователи могут не знать о том, что создаются безымянные тома, и продолжают занимать место на своем хосте Docker после удаления контейнеров.
  • Нет способа удалить том, объявленный в Dockerfile. Нисходящие изображения не могут добавлять данные в пути, где существуют тома.

Последняя проблема приводит к таким проблемам.

Что касается вопроса GitLab, кто-то хочет расширить образ GitLab предварительно сконфигурированными данными для целей тестирования, но невозможно зафиксировать эти данные в последующем изображении из-за VOLUME в /var/opt/gitlab в родительском изображении.

ТЛ; др: VOLUME был разработан для мира до Docker 1.9. Лучше просто оставить это.

Другие вопросы по тегам