Какова практическая цель 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 на Docker: как сохранить пользовательские данные между развертываниями?
Что касается вопроса GitLab, кто-то хочет расширить образ GitLab предварительно сконфигурированными данными для целей тестирования, но невозможно зафиксировать эти данные в последующем изображении из-за VOLUME в /var/opt/gitlab в родительском изображении.
ТЛ; др: VOLUME
был разработан для мира до Docker 1.9. Лучше просто оставить это.