我正在使用 docker-compose 创建一个 mysql 容器,并在其中创建一个数据库。如果我手动删除数据库,无论我做什么,都无法重新创建容器并强制它也重新创建数据库。
这是我的 docker-compose.yml:
version: '3'
services:
mysql:
container_name: mysqltest-db
image: mysql:5.6.51
volumes:
- ./my_volume:/var/lib/mysql
- ./data/init.sql:/docker-entrypoint-initdb.d/1.init.sql
command: --default-authentication-plugin=mysql_native_password
ports:
- 3306:3306
environment:
MYSQL_ROOT_PASSWORD: root
MYSQL_DATABASE: my_database
MYSQL_USER: my_user
MYSQL_PASSWORD: mypass
volumes:
my_volume: {}
init.sql 脚本只是创建一个数据库:
CREATE DATABASE IF NOT EXISTS my_database;
GRANT ALL PRIVILEGES ON my_database.* TO my_user@'%' IDENTIFIED BY 'mypass';
FLUSH PRIVILEGES;
第一次我运行 docker-compose up
,一切正常。我可以用docker container exec -it mysqltest-db bash
登录mysql,然后用mysql -u root -proot
登录mysql,然后运行show databases
。果然,有my_database
:
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| my_database |
| mysql |
| performance_schema |
+--------------------+
4 rows in set (0.01 sec)
接下来我通过运行 drop database my_database
来手动删除数据库。
然后我 ctrl+c 杀死容器,然后运行 docker-compose down -v
。据我了解,-v
应该销毁包含 mysql 数据的卷。我通过运行 docker volume ls
检查它是否真的消失了,并确认 dockertest_my_volume
卷不再存在。
然后我运行 docker-compose pull && docker-compose up -V --force-recreate
来重新创建容器。这就是我被困的地方。当我登录容器,然后登录 mysql,再次运行 show databases
时,my_database 仍然不见了:
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+
3 rows in set (0.01 sec)
强制 Docker 从头开始完全重建,以便第二次创建 mysql 数据库,我缺少什么?
第一次和第二次运行之间的日志输出量显然存在很大差异。但是在这两种情况下,似乎都在创建一个卷:
$-> docker-compose up -V --force-recreate
Docker Compose is now in the Docker CLI, try `docker compose up`
Creating network "dockertest_default" with the default driver
Creating volume "dockertest_my_volume" with default driver
Creating mysqltest-db ... done
Attaching to mysqltest-db
答案 0 :(得分:1)
哇,终于轻松了。 Docker 卷是名称,而不是路径。你有:
volumes:
- ./my_volume:/var/lib/mysql
将本地文件系统上相对于上下文(您启动容器的文件夹)的路径 ./my_volume
装入路径 /var/lib/mysql
处的容器中。你真正想要的是:
volumes:
- my_volume:/var/lib/mysql
其中包含卷引用(命名卷)。这会在容器内创建/安装卷 my_volume
到 /var/lib/mysql
。
您可以诊断问题,因为您将在 my_volume
文件旁边有一个名为 docker-compose.yaml
的目录。检查这一点的另一种方法是在容器运行时执行 docker volume ls
,您会注意到没有 my_volume
卷(运行您的代码时,不是我的 - 当您运行我的代码时,它会工作;).
虽然很容易修复:)
答案 1 :(得分:1)
Docker 有两种内置存储,named volumes 和 bind mounts。它们的语法非常相似,但命名卷将 Docker 管理的存储附加到容器,而绑定挂载则直接附加一些主机目录。
您的 docker-compose.yml
文件说:
volumes:
- ./my_volume:/var/lib/mysql
这是绑定挂载语法;它直接在您的主机系统上命名路径。 (如果您仔细观察,您可以看到 my_volume
目录和其中的 MySQL 数据文件。)
MySQL 映像启动序列知道在 /var/lib/mysql
目录中查找,并且如果该目录为空,它将执行首次初始化序列。如果那里有 MySQL 安装,它不会重新运行初始化脚本,即使您删除了那里的内容。如果它是命名卷或绑定安装,则这是相同的行为。
就您而言,即使您删除了数据库,MySQL 系统文件仍然存在。您可以强制它从头开始:
docker-compose rm --stop mysql
rm -rf my_volume
docker-compose up -d