Как часто вы слышали байку о том, что при удалении контейнера все данные удаляются? На самом деле это конечно так, но не совсем. Некоторые считают это самым главным минусом так как боятся потерять важные данные и даже отказываются из-за этого от контейнеризации. Но этого можно легко избежать.
Контейнеры в докере вещи эфемерные, получается, что по сути это временная среда. Т.е. всё что находится внутри контейнера исчезнет при его удалении. При выполнении команды docker rm myapp Docker удаляет верхний слой, в котором происходят операции записи и чтения, подробнее про слои.
Запомните контейнер — это не виртуальный сервер, а временная изолированная среда. Главная цель контейнера быстро запуститься и быстро исчезнуть без следов. Так происходит потому что девиз контейнеризации — это не менять конфигурацию контейнера, а каждый раз всё пересоздавать.
Перезапуск или остановка контейнера не приводит к потере данных, только удаление контейнера.
Так что с важными данными?
Понятное дело, что веб сервера или сервера приложений зачастую можно пересоздавать, удаляя данные без проблем. Но бывают ситуации, когда необходимо использовать контейнеры с важными данными, это могут быть лог файлы приложения или то еще важнее база данных. Конечно про хранение базы данных в контейнере много холивара, но тут каждый решает сам использовать контейнеризацию для этого или нет.
Для того чтобы сохранить важные данные от удаления Docker предоставляет две возможности:
- использовать тома (Docker Volume)
- монтирование локальной папки (Bind mount)
Docker Volume
Docker Volume - это постоянное хранилище, которым управляет сам Docker. Т.е. созданием этих томов занимается сам Docker. Эти тома хранятся по умолчанию в директории /var/lib/docker/volumes/.
При использовании Docker Volume правами на тома управляет сам Docker, он задаёт владельцев, права и монтирует их только при запуске контейнера.
Docker Volume в Dockerfile
При использовании контейнеров для некоторых типов требуется создавать Docker Volume прямо в образе, например, образ приложений баз данных (mariadb).
VOLUME /var/lib/mysql
Теперь при запуске контейнера автоматически будет создан том для контейнера и при его удалении база данных не удалится. Т.е. создатель образа уже заранее об этом позаботился.
Для примера я создам контейнер с образа mariadb:latest:
docker run --detach --name some-mariadb -e MARIADB_ROOT_PASSWORD=my-secret-pw mariadb:latest
docker ps
e568132fbaf9 mariadb:latest "docker-entrypoint.s…" 45 seconds ago Up 44 seconds 3306/tcp some-mariadb
Теперь при просмотре конфигурации контейнера у него будет как минимум один существующий тов.
docker inspect -f '{{json .Mounts}}' some-mariadb | jq
{
"Type": "volume",
"Name": "ec0302b40bf39f5c983464ebb95c0a3fa8e70f6ecdd5ec28bbeb9d8a271151e7",
"Source": "/var/lib/docker/volumes/64165e246eab56a2c5bbd047c07eb2ba68d419a83c51cff1e7a4c8cafa505b70/_data",
"Destination": "/var/lib/mysql",
"Driver": "local",
"Mode": "",
"RW": true,
"Propagation": ""
}
Из вывода команды можно догадаться что файлы хранятся в локальной директории /var/lib/docker/volumes/64165e246eab56a2c5bbd047c07eb2ba68d419a83c51cff1e7a4c8cafa505b70/_data. Скажу сразу удалить эту директорию на хосте и потерять данные можно, Docker не защищает директорию /var/lib/docker/volumes/ от удаления файлов.
Список Docker Volume
Выше я проверил какой том используется контейнером используя команду docker inspect. Но для управления томами в Docker есть отдельная команда docker volume.
- Просмотр всех томов в Docker
docker volume lslocal 64165e246eab56a2c5bbd047c07eb2ba68d419a83c51cff1e7a4c8cafa505b70 - Проверить конфигурацию тома
docker volume inspect 64165e246eab56a2c5bbd047c07eb2ba68d419a83c51cff1e7a4c8cafa505b70{ "CreatedAt": "2025-11-03T13:14:44+06:00", "Driver": "local", "Labels": { "com.docker.volume.anonymous": "" }, "Mountpoint": "/var/lib/docker/volumes/64165e246eab56a2c5bbd047c07eb2ba68d419a83c51cff1e7a4c8cafa505b70/_data", "Name": "64165e246eab56a2c5bbd047c07eb2ba68d419a83c51cff1e7a4c8cafa505b70", "Options": null, "Scope": "local" }
Docker Volume в Docker run
Я показал, как можно создать том еще на этапе сборки образа, но можно добавить том при создании контейнера. Этот вариант кстати добавит еще и удобочитаемости при выводе результат выполнения команды docker volume ls.
Для того чтобы добавить том в контейнер при его создании используется опция -v.
docker run --detach --name some-mariadb -v some-mariadb-vol1:/var/lib/mysql -e MARIADB_ROOT_PASSWORD=my-secret-pw
mariadb:latest
Теперь, когда я выполню команду docker volume ls я увижу нормальное имя тома а не эти бесконечные буквы и цифры. Да и путь к директории тома в самой ОС будет выглядеть лучше.
docker volume ls
local some-mariadb-vol1
Для создания Docker Volume можно также использовать команду docker volume create. Но обычно эта команда используется только если нужно указать специфические параметры для тома, которые нельзя указать при выполнении команды docker run.
Общий доступ к Docker Volume
Как нетрудно догадаться если контейнер удалён, а том еще остался то можно добавить этот том в другой контейнер со всеми данными внутри него.
Также сразу несколько контейнеров могут использовать один и тот же том, но никакой синхронизации операций записи нет. Т.е. один контейнер может с лёгкостью перезаписать изменения другого контейнера или вообще повредить данные, так что будьте осторожны, особенно с базами данных.
Docker Volume для уже созданного и работающего контейнера
К сожалению, тут сделать этого нельзя, только если вы не используете docker-compose.
Для добавления тома к уже существующему контейнеру придётся его удалить и создать заново. Но если вы всё делаете правильно, то такая операция не должна на что-то повлиять. Если же что-то внутри контейнере лежит важное не в Docker Volume или Bind mount сохраните эти файлы.
Удаление Docker Volume
Теперь, когда у меня есть том для контейнера some-mariadb при удалении самого контейнера данные и сам том должны остаться не тронутыми.
docker volume ls
sudo ls /var/lib/docker/volumes/64165e246eab56a2c5bbd047c07eb2ba68d419a83c51cff1e7a4c8cafa505b70/_data
aria_log.00000001 ddl_recovery.log ibdata1 ibtmp1
Если после удаления контейнера данные с тома этого контейнера уже не нужны можно удалить сам том, просто удалить директорию в самой ОС недостаточно.
docker volume rm 64165e246eab56a2c5bbd047c07eb2ba68d419a83c51cff1e7a4c8cafa505b70
sudo ls /var/lib/docker/volumes/64165e246eab56a2c5bbd047c07eb2ba68d419a83c51cff1e7a4c8cafa505b70/_data
ls: cannot access
Bind mount
Благодаря Bind mount можно прокинуть локальную папку с хостовой ОС в контейнер. Соответственно даже при удалении контейнера данные остаются внутри директории хоста с Docker.
docker run -d -v $(pwd)/data:/usr/src/app/data myapp:1.0
При выполнении этой команды Docker не создаёт отдельный volume, а просто связывает локальную директорию с директорией внутри контейнера, по сути этакий линк на директорию.
Но при выборе между Bind mount и Docker Volume рекомендуется использовать именно Docker Volume. Потому что одна из идей Docker это изоляция контейнера от файловой системы хоста, но при Bind mount это идея рушится и управляет правами на доступ к файлам уде сама ОС, а не Docker. Также есть некоторые ограничения при использовании Docker в Docker Swarm и Kubernetes.
Основное преимущество тут в том, что можно править файлы, используемые контейнером, не залезая в сам контейнер.
Bind mount невозможно использовать при создании образа, т.е. в Dockerfile. Добавить Bind mount к контейнеру можно только при создании контейнера или при использовании Docker Compose.
Для проброса локальной директории в контейнер при создании самого контейнера используется опция -v.
docker run --detach --name some-mariadb -v /var/lib/mysql:/var/lib/mysql -e
sudo ls /var/lib/mysql


Комментарии