Короче: нет, ваша VOLUME
инструкция не верна.
Dockerfile VOLUME
указывает один или несколько томов с указанием путей на стороне контейнера. Но это не позволяет автору изображения указывать путь к хосту. На стороне хоста тома создаются с очень длинным ID-именем внутри корня Docker. На моей машине это есть /var/lib/docker/volumes
.
Примечание. Поскольку автоматически сгенерированное имя очень длинное и не имеет смысла с точки зрения человека, эти тома часто называют «безымянным» или «анонимным».
Ваш пример, в котором используется '.' персонаж даже не будет работать на моей машине, независимо от того, сделаю ли я точку первым или вторым аргументом. Я получаю это сообщение об ошибке:
docker: ответ об ошибке от демона: ошибка времени выполнения oci: container_linux.go: 265: запуск процесса контейнера вызвал "process_linux.go: 368: инициализация контейнера вызвала \" open / dev / ptmx: нет такого файла или каталога \ "".
Я знаю, что то, что было сказано по этому поводу, вероятно, не очень ценно для того, кто пытается понять, VOLUME
и, -v
конечно же, не дает решения для того, чего вы пытаетесь достичь. Так что, надеюсь, следующие примеры прольют больше света на эти проблемы.
Минутучебник: Определение объемов
Учитывая этот Dockerfile:
FROM openjdk:8u131-jdk-alpine
VOLUME vol1 vol2
(Что касается результата этого мини-руководства, не имеет значения, укажем мы vol1 vol2
или /vol1 /vol2
- не спрашивайте меня, почему)
Построить это:
docker build -t my-openjdk
Бегать:
docker run --rm -it my-openjdk
Внутри контейнера запустите ls
командную строку, и вы заметите, что существуют два каталога; /vol1
и /vol2
.
Запуск контейнера также создает два каталога или «тома» на стороне хоста.
Когда контейнер запущен, выполните его docker volume ls
на хост-машине, и вы увидите что-то вроде этого (я заменил среднюю часть имени тремя точками для краткости):
DRIVER VOLUME NAME
local c984...e4fc
local f670...49f0
Вернувшись в контейнер , выполните touch /vol1/weird-ass-file
(создает пустой файл в указанном месте).
Этот файл теперь доступен на хост-машине в одном из безымянных томов, лол. Мне потребовалось две попытки, потому что я сначала попробовал первый указанный том, но в конце концов я нашел свой файл во втором указанном томе, используя эту команду на хост-машине:
sudo ls /var/lib/docker/volumes/f670...49f0/_data
Точно так же вы можете попытаться удалить этот файл на хосте, и он также будет удален в контейнере.
Примечание. _data
Папка также называется «точкой монтирования».
Выйдите из контейнера и перечислите тома на хосте. Они ушли. Мы использовали --rm
флаг при запуске контейнера, и этот параметр эффективно стирает не только контейнер при выходе, но и тома.
Запустите новый контейнер, но укажите том, используя -v
:
docker run --rm -it -v /vol3 my-openjdk
Это добавляет третий том, и вся система в конечном итоге имеет три безымянных тома. Команда бы вылетела, если бы мы указали только -v vol3
. Аргумент должен быть абсолютным путем внутри контейнера. На стороне хоста новый третий том анонимен и находится вместе с двумя другими томами в /var/lib/docker/volumes/
.
Ранее было сказано, что Dockerfile
невозможно сопоставить путь к хосту, что создает для нас проблему при попытке перенести файлы с хоста в контейнер во время выполнения. -v
Эту проблему решает другой синтаксис.
Представьте, что у меня есть подпапка в каталоге моего проекта, ./src
которую я хочу синхронизировать /src
внутри контейнера. Эта команда делает свое дело:
docker run -it -v $(pwd)/src:/src my-openjdk
Обе стороны :
персонажа ожидают абсолютного пути. Левая сторона - это абсолютный путь на главной машине, правая сторона - это абсолютный путь внутри контейнера. pwd
это команда, которая «печатает текущий / рабочий каталог». Ввод команды $()
принимает команду в скобках, запускает ее в подоболочке и возвращает абсолютный путь к нашему каталогу проекта.
Собирая все вместе, предположим, что у нас есть ./src/Hello.java
папка нашего проекта на хост-машине со следующим содержимым:
public class Hello {
public static void main(String... ignored) {
System.out.println("Hello, World!");
}
}
Мы создаем этот Dockerfile:
FROM openjdk:8u131-jdk-alpine
WORKDIR /src
ENTRYPOINT javac Hello.java && java Hello
Запускаем эту команду:
docker run -v $(pwd)/src:/src my-openjdk
Это напечатает «Hello, World!».
Самое приятное то, что мы полностью свободны изменять файл .java с новым сообщением для другого вывода при втором запуске - без необходимости перестраивать изображение =)
Заключительные замечания
Я новичок в Docker, и вышеупомянутый «учебник» отражает информацию, которую я собрал на трехдневном хакатоне по командной строке. Мне почти стыдно, что я не смог предоставить ссылки на понятную англоязычную документацию, подтверждающую мои утверждения, но я честно думаю, что это связано с отсутствием документации, а не с личными усилиями. Я знаю, что примеры работают так, как рекламируется, используя мою текущую настройку: «Windows 10 -> Vagrant 2.0.0 -> Docker 17.09.0-ce».
Учебник не решает проблему «как указать путь к контейнеру в Dockerfile и позволить команде run указывать только путь к хосту». Может быть, способ есть, просто я его не нашел.
Наконец, у меня VOLUME
интуитивное предчувствие, что указание в файле Dockerfile не просто необычно, но, вероятно, лучше никогда не использовать VOLUME
. По двум причинам. Первую причину, которую мы уже определили: мы не можем указать путь к хосту - это хорошо, потому что файлы Dockerfiles должны быть очень независимы от специфики хост-машины. Но вторая причина заключается в том, что люди могут забыть использовать эту --rm
опцию при запуске контейнера. Можно не забыть снять контейнер, но забыть удалить объем. Кроме того, даже при наличии лучшей человеческой памяти может оказаться непростой задачей выяснить, какие из всех анонимных томов можно безопасно удалить.
docker volume prune
может использоваться для очистки оставшихся томов, которые не прикреплены к работающим контейнерам. Не сказать, что можно будет легко отличить потенциально важные по id .../
,vol1
относительно/
, который разрешается в/vol1
. Если вы используете,WORKDIR
чтобы указать рабочий каталог, отличный от/
,vol1
и/vol1
больше не будет указывать на тот же каталог.Указание
VOLUME
строки в Dockerfile настраивает немного метаданных в вашем образе, но важно то, как эти метаданные используются.Во-первых, что сделали эти две строки:
WORKDIR
Линия есть создает каталог , если он не существует, и обновляет некоторые метаданные изображения , чтобы определить все относительные пути, а с текущим каталогом для команд , какRUN
будет в этом месте.VOLUME
Линия есть определяет два тома , один относительный путь.
, а другой/usr/src/app
, как только случается быть тот же каталог. Чаще всегоVOLUME
строка содержит только один каталог, но может содержать несколько, как вы это сделали, или это может быть массив в формате json.Вы не можете указать источник тома в Dockerfile : распространенный источник путаницы при указании томов в Dockerfile - это попытка сопоставить синтаксис времени выполнения источника и назначения во время сборки образа, это не сработает . Dockerfile может указывать только место назначения тома. Было бы тривиальной уязвимостью безопасности, если бы кто-то мог определить источник тома, поскольку он мог бы обновить общий образ в концентраторе докеров, чтобы смонтировать корневой каталог в контейнер, а затем запустить фоновый процесс внутри контейнера как часть точки входа, которая добавляет логины в / etc / passwd, настраивает systemd для запуска майнера биткойнов при следующей перезагрузке или ищет в файловой системе кредитные карты, SSN и закрытые ключи для отправки на удаленный сайт.
Что делает строка VOLUME? Как уже упоминалось, он устанавливает некоторые метаданные изображения, чтобы сказать, что каталог внутри изображения является томом. Как используются эти метаданные? Каждый раз, когда вы создаете контейнер из этого образа, докер заставляет этот каталог быть томом. Если вы не указываете том в своей команде запуска или не создаете файл, единственный вариант для docker - создать анонимный том. Это локальный именованный том с длинным уникальным идентификатором для имени и без каких-либо других указаний на то, почему он был создан или какие данные он содержит (анонимные тома - это данные, которые теряются). Если вы переопределите том, указав на именованный том или том хоста, ваши данные будут отправлены туда.
VOLUME ломает вещи: вы не можете отключить том, однажды определенный в Dockerfile. И что еще более важно,
RUN
команда в докере реализована с помощью временных контейнеров. Эти временные контейнеры получат временный анонимный том. Этот анонимный том будет инициализирован содержимым вашего изображения. Любая запись внутри контейнера от вашейRUN
команды будет сделана на этот том. КогдаRUN
команда завершается, изменения изображения сохраняются, а изменения анонимного тома отменяются. Из-за этого я настоятельно не рекомендую определятьVOLUME
внутри Dockerfile. Это приводит к неожиданному поведению нижестоящих пользователей вашего изображения, которые хотят расширить изображение исходными данными в расположении тома.Как указать объем? Чтобы указать, куда вы хотите включить тома с изображением, предоставьте файл
docker-compose.yml
. Пользователи могут изменить это, чтобы настроить расположение тома в соответствии с их локальной средой, и он фиксирует другие параметры времени выполнения, такие как порты публикации и сеть.Кто-то должен это задокументировать! У них есть. Docker включает предупреждения об использовании VOLUME в свою документацию по Dockerfile вместе с советом указать источник во время выполнения:
источник
Команда
VOLUME
в aDockerfile
вполне законна, совершенно обычна, абсолютно удобна в использовании и в любом случае не является устаревшей. Просто нужно это понять.Мы используем его, чтобы указывать на любые каталоги, в которые приложение в контейнере будет много писать. Мы не используем его
VOLUME
только потому, что хотим поделиться между хостом и контейнером, как файл конфигурации.Команде просто нужен один параметр; путь к папке относительно
WORKDIR
установленного внутри контейнера. Затем docker создаст том на своем графике (/ var / lib / docker) и подключит его к папке в контейнере. Теперь контейнеру будет куда писать с высокой производительностью. БезVOLUME
команды скорость записи в указанную папку будет очень низкой, потому что теперь контейнер использует своюcopy on write
стратегию в самом контейнере.copy on write
Стратегия является основной причиной , почему существует тома.Если вы монтируете через папку, указанную
VOLUME
командой, команда никогда не запускается, потому чтоVOLUME
выполняется только при запуске контейнера, вроде какENV
.В основном с
VOLUME
командой вы получаете производительность без внешнего монтирования каких-либо томов. Данные будут сохраняться при запуске контейнеров без каких-либо внешних подключений. Затем, когда все будет готово, просто установите что-нибудь поверх него.Несколько хороших примеров использования:
- журналы
- временные папки
Некоторые плохие варианты использования:
- статические файлы
- конфигурации
- код
источник
VOLUME
директории для конфигов. Однако после того, как вы действительно смонтируете конфигурацию, вам придется монтировать ее поверх этого каталога, и поэтомуVOLUME
команда не запускается. Поэтому бессмысленно использоватьVOLUME
команду в каталоге, указанном для конфигурации. Кроме того, инициализация графика объема одним статическим файлом, доступным только для чтения, является серьезным излишеством. Так что я придерживаюсь того, что сказал, не нужноVOLUME
командовать конфигами.Чтобы лучше понять
volume
инструкцию в файле dockerfile, давайте изучим типичное использование тома в официальной реализации файла докеров mysql.Ссылка: https://github.com/docker-library/mysql/blob/3362baccb4352bcf0022014f67c1ec7e6808b8c5/8.0/Dockerfile
Это
/var/lib/mysql
местоположение MySQL по умолчанию, в котором хранятся файлы данных.Когда вы запускаете тестовый контейнер только для тестовых целей, вы не можете указывать его точку установки, например
тогда экземпляр контейнера mysql будет использовать путь монтирования по умолчанию, указанный в
volume
инструкции в файле dockerfile. тома создаются с очень длинным ID-подобным именем внутри корня Docker, это называется «безымянный» или «анонимный» том. В папке базовой хост-системы / var / lib / docker / volume.Это очень удобно для целей быстрого тестирования без необходимости указывать точку подключения, но все же можно добиться максимальной производительности, используя Volume для хранилища данных, а не уровень контейнера.
Для формального использования вам нужно будет указать путь монтирования с помощью именованного тома или привязки монтирования, например
Команда монтирует каталог / my / own / datadir из базовой хост-системы как / var / lib / mysql внутри контейнера. Каталог данных / my / own / datadir не будет автоматически удален, даже если контейнер будет удален.
Использование официального образа mysql (пожалуйста, проверьте раздел «Где хранить данные»):
Ссылка: https://hub.docker.com/_/mysql/
источник
-v
используя его, не устанавливая громкость в DockerfileЯ не считаю использование VOLUME хорошим в любом случае, за исключением случаев, когда вы создаете изображение для себя, и никто другой не собирается его использовать.
На меня негативно повлияло то, что VOLUME был показан в базовых изображениях, которые я расширил, и узнал о проблеме только после того, как изображение уже было запущено, например wordpress, который объявляет
/var/www/html
папку как VOLUME , и это означало, что любые файлы, добавленные или измененные во время этап сборки не учитывается, и текущие изменения сохраняются, даже если вы не знаете. Существует уродливый обходной путь для определения веб-каталога в другом месте, но это просто плохое решение для более простого: просто удалите директиву VOLUME.Вы можете легко достичь цели объема, используя эту
-v
опцию, это не только проясняет, какими будут тома контейнера (без необходимости смотреть на Dockerfile и родительские Dockerfiles), но также дает потребителю возможность использовать громкость или нет.Как сказано в этом ответе, использовать VOLUMES в основном плохо по следующим причинам :
Возможность отмены объявления тома может помочь, но только если вы знаете тома, определенные в файле докеров, который сгенерировал образ (и в родительских файлах докеров!). Кроме того, VOLUME может быть добавлен в более новые версии файла Dockerfile, что может неожиданно нарушить работу потребителей изображения.
Еще одно хорошее объяснение ( об образе оракула с VOLUME , который был удален ): https://github.com/oracle/docker-images/issues/640#issuecomment-412647328
Еще больше случаев, когда VOLUME сломал что-то для людей:
Запрос тянуть , чтобы добавить опции для сброса Свойства родительского образа (включая объем), был закрыт , и в настоящее время обсуждается здесь (и вы можете увидеть несколько случаев из людей , пострадавших отрицательно из - за объемы , определенных в dockerfiles), который имеет комментарий с хорошим объяснение против VOLUME:
Я тоже считаю EXPOSE плохим, но у него меньше побочных эффектов. Единственное хорошее, что я вижу в VOLUME и EXPOSE, - это документация, и я бы счел их хорошими, если бы они служили только для этого (без каких-либо побочных эффектов).
TL; DR
Я считаю, что лучше всего отказаться от VOLUME.
источник