Короткий ответ
Данные приложения должны находиться в named volume (или, при необходимости, bind mount), а не в writable-слое контейнера; при пересоздании контейнера с новым образом нужно подключить тот же volume по имени — тогда данные автоматически доступны новому контейнеру.
Как это работает подробнее
writable-слой уничтожается вместе с контейнером при docker rm, независимо от того, по какой причине он пересоздаётся (обновление версии образа, смена конфигурации). Если каталог с данными приложения внутри контейнера подключён как volume, сам volume существует отдельно от жизненного цикла контейнера и переживает его удаление.
Пример кода
Пример конфигурации
$ docker volume create pgdata
$ docker run -d --name pg15 -v pgdata:/var/lib/postgresql/data postgres:15
$ docker stop pg15 && docker rm pg15
$ docker run -d --name pg15 -v pgdata:/var/lib/postgresql/data postgres:15.5Что использовать на практике
- Практика. типичный безопасный процесс обновления версии stateful-сервиса —
docker stop old,docker rm old, затемdocker run --name new -v same_volume:/data new_image; важно убедиться, что новая версия образа совместима по формату данных с тем, что лежит в volume (например, при мажорном обновлении БД иногда требуется отдельная миграция формата перед переключением).
Подводные камни
- Риск. при обновлении меняют путь монтирования volume внутри контейнера между версиями образа без переноса данных на новый путь, из-за чего приложение в новой версии "не видит" старые данные, хотя volume физически не потерян; не делают backup volume перед обновлением версии stateful-сервиса, рискуя потерять данные при несовместимом обновлении.