Пустой Docker volume получил файлы из образа: разбираем nocopy
В образе есть каталог /data с примером конфигурации. К нему подключили новый именованный том, ожидая пустое хранилище. После запуска в томе уже лежат файлы. У Docker есть полезное поведение первоначального заполнения: содержимое каталога образа может копироваться в пустой volume при его подключении. Но это поведение нужно учитывать как часть инициализации данных.
Оно отличается от обычного bind mount. Когда каталог хоста монтируют поверх каталога контейнера, его содержимое скрывает прежние файлы. Именованный volume имеет собственный жизненный цикл, и первоначальная загрузка из образа создаёт отдельную копию. После этого обновление образа не следует воспринимать как синхронизацию файлов уже существующего тома.
Явно выбрать первичное содержимое
Если том должен начинаться пустым, у mount есть параметр volume-nocopy. Для Compose соответствующая настройка находится в длинной форме volumes:
services:
app:
build: .
volumes:
- type: volume
source: appdata
target: /data
volume:
nocopy: true
volumes:
appdata: {}
Теперь приложение должно само понимать, как работать с пустым /data. Если оно требует стартовый файл, инициализацию нужно сделать отдельным понятным действием: создать файл при отсутствии, применить миграцию или подготовить содержимое перед запуском. Нельзя одновременно запретить копирование и ожидать, что пример из образа появится в томе прежним способом.
Настройка nocopy не очищает существующий том. Она управляет копированием при подключении, а не удалением старых данных. Если в appdata уже что-то лежит, смена YAML не вернёт его к исходному состоянию. Для опыта создайте отдельный проект или новый тестовый том; удалять рабочий volume ради проверки этого свойства не требуется.
Проверить два независимых жизненных цикла
Сначала запустите один и тот же тестовый образ с новым томом без nocopy и посмотрите начальные файлы. Затем используйте другой новый том с nocopy и сравните результат. Так в опыте нет влияния ранее существовавшего содержимого. После этого измените файл в образе и пересоздайте контейнер с прежним томом: это покажет, почему обновление образа не равно обновлению данных.
Для приложения заранее определите владельца конфигурации. Если файл должен поставляться с релизом и меняться при обновлении, хранить его копию в постоянном томе может быть неудобно. Если пользователь редактирует файл и должен сохранить изменения между релизами, постоянное хранилище оправдано, но потребуется миграция формата.
В инструкции полезно разделить пустой первый запуск, повторный запуск и обновление версии. Каждый из них работает с разным состоянием данных. Когда это описано явно, появление файлов в новом томе перестаёт выглядеть случайностью, а смена образа не становится неожиданной попыткой перезаписать пользовательские настройки.
Продолжить практику
Эту настройку проще понимать в составе приложения, у которого есть сеть, данные и понятная процедура обновления. На курсе «Docker и Docker Compose: контейнеризация приложений» вы упакуете HTTP-сервис с PostgreSQL, разберёте конфигурацию, хранение данных и диагностику сбоев. В программе есть локальные лабораторные, работа с registry и версиями образов; итоговый проект включает передачу окружения другому разработчику и проверку восстановления базы.
Источник: официальная документация.
Другие задачи по теме: Процессы, сеть, тома и сборка контейнера.
Продолжить на практике
- Docker и Docker Compose: контейнеризация приложений ↗
Упакуйте приложение в Docker и запустите его с PostgreSQL через Compose. Образы, сети, тома, диагностика поломок, обновление версий и восстановление данных — с практикой и итоговым проектом.
