Вопрос или проблема
Я запускаю MySQL в контейнере Docker:
sudo docker run --rm --name mysql5 --net legacy_net --net-alias mysql5 --ip 172.20.0.2 -e MYSQL_ROOT_PASSWORD=$MROOTPASS -d mysql:5.7
mysql -u root -h 172.20.0.2 -p$MROOTPASS
и создал экспериментальную базу данных с помощью следующей команды:
CREATE DATABASE testdb;
и зафиксировал контейнер:
sudo docker commit mysql5 mysql:5.7-test
Когда я запустил зафиксированный контейнер:
sudo docker stop mysql5;
sudo docker run --rm --name mysql5 --net legacy_net --net-alias mysql5 --ip 172.20.0.2 -e MYSQL_ROOT_PASSWORD=$MROOTPASS -d mysql:5.7-test
моя тестовая база данных исчезла.
Это нормальное поведение или я сделал что-то не так?
Я думал, что Docker хранит свои данные где-то во внутреннем хранилище, которое копируется в новый образ, когда я выполняю docker commit
. Что я неправильно понимаю?
ИЗМЕНЕНИЕ1
sudo docker inspect mysql5 | grep -i volume
"VolumeDriver": "",
"VolumesFrom": null,
"Type": "volume",
"Source": "/var/lib/docker/volumes/1f04f07e91a16e6e9aeb393af2954dd7e32e2a2b93615fb4b6924de3568951af/_data",
"Volumes": {
sudo docker inspect mysql:5.7
"Volumes": {
"/var/lib/mysql": {}
},
ИЗМЕНЕНИЕ2
Docker создает том с пользователем mysql
, у которого id=999:
sudo docker run --rm --name mysql5 -v /home/dmitriano/work/mysql:/var/lib/mysql --net legacy_net --net-alias mysql5 --ip 172.20.0.2 -e MYSQL_ROOT_PASSWORD=$MROOTPASS -d mysql:5.7
ll
drwxr-xr-x 5 999 root 4096 Jan 20 19:31 mysql/
sudo docker exec -it mysql5 bash -c "id 999"
uid=999(mysql) gid=999(mysql) groups=999(mysql)
Что я должен сделать с этим 999 на хост-машине?
Ответ или решение
Пропажа тестовой базы данных после коммита контейнера MySQL в Docker может вызвать некоторое удивление, особенно если вы ожидали, что все данные сохранятся в новом имидже. Чтобы понять, что именно произошло, и избежать подобных проблем в будущем, разберёмся более подробно.
Теория
Docker предоставляет возможность управлять изолированными окружениями через контейнеры. Каждый контейнер основывается на образе, который можно представить как "шаблон" для создания новых контейнеров. Когда вы запускаете контейнер, Docker использует слой образа и добавляет поверх него слои для всех изменений, которые вносятся в этом контейнере. Когда вы выполняете docker commit
, Docker фиксирует текущие слои изменений и создает новый образ.
Однако, важно понимать, что файлы в контейнере, расположенные в определенных директориях, могут сохраняться вне зависимости от самих слоев. Это достигается через механизм "волюмов" (volumes), которые физически располагаются на хост-машине. В случае с MySQL, по умолчанию, база данных сохраняется в /var/lib/mysql
, и этот путь может быть подключён как volume. Это значит, что директории, подключенные как volume, не копируются при коммите контейнера, так как они считаются внешними по отношению к слоям контейнера.
Пример
В вашей конкретной ситуации:
- Вы создали контейнер MySQL и добавили базу данных.
- Вы выполнили команду
docker commit
, сделав новый образ. - При запуске контейнера из нового образа в директории, связанной с volume
/var/lib/mysql
, данных не оказалось.
Ваше предположение о том, что все данные будут автоматически сохранены в новом образе после выполнения docker commit
, неверно. Данные, находящиеся в volumes, остаются вне контекста слоев контейнера и, соответственно, вне образа.
Применение
Чтобы избежать потери данных и корректно управлять ими, учтите следующие рекомендации:
-
Использование
docker volume
: Создайте и используйте именованные volumes при запуске ваших контейнеров. Это позволит сохранять и управлять данными независимо от состояния контейнера:docker volume create --name my_mysql_data
Затем запускайте контейнер MySQL с подключенным volume:
sudo docker run --rm --name mysql5 \ --net legacy_net --net-alias mysql5 --ip 172.20.0.2 \ -e MYSQL_ROOT_PASSWORD=$MROOTPASS \ -v my_mysql_data:/var/lib/mysql \ -d mysql:5.7
-
Понимание прав и доступа: Если вы монтируете volume на хост-машине, убедитесь, что у пользователей контейнера есть права доступа к этому каталогу. В вашем случае, MySQL запускается от имени пользователя с UID 999. Убедитесь, что соответствующий каталог на хосте предоставляет необходимый доступ.
-
Резервное копирование: Регулярно создавайте резервные копии важной информации. Для баз данных это может быть экспорт через
mysqldump
:mysqldump -u root -p $MROOTPASS --all-databases > backup.sql
Или использование инструментов для резервного копирования, если требуется восстановление на уровне данных.
-
Документация и понимание слоев Docker: Понимание того, как Docker работает с файлами и данными, позволяет избегать таких проблем. Рекомендуется использовать volumes для данных, которые должны сохраняться за пределами жизненного цикла контейнера.
Следуя этим рекомендациям, вы сможете надёжно управлять базами данных в Docker и избежать неожиданной потери информации при изменении контейнеров. Эти меры помогут организовать эффективное и стабильное окружение для развития и тестирования в Docker.