Reputation: 2287
I am using docker-compose to create a mysql container, and create a database in it. If I delete the database manually, no matter what I do, I can't re-create the container and force it to re-create the database too.
Here's my 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: {}
The init.sql script simply creates a database:
CREATE DATABASE IF NOT EXISTS my_database;
GRANT ALL PRIVILEGES ON my_database.* TO my_user@'%' IDENTIFIED BY 'mypass';
FLUSH PRIVILEGES;
The first time I run docker-compose up
, everything works fine. I can log into the mysql with docker container exec -it mysqltest-db bash
, then log into mysql with mysql -u root -proot
, and run show databases
. Sure enough, my_database
is there:
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| my_database |
| mysql |
| performance_schema |
+--------------------+
4 rows in set (0.01 sec)
Next I manually delete the database by running drop database my_database
.
Then I ctrl+c to kill the container, and run docker-compose down -v
. As I understand it, the -v
should destroy the volume that contained the mysql data. I check that it's really gone by running docker volume ls
, and confirm that the dockertest_my_volume
volume is no longer present.
Then I run docker-compose pull && docker-compose up -V --force-recreate
to re-create the container. This is where I'm stuck. When I login to the container, and then to mysql, and run show databases
again, the my_database is still gone:
mysql> show databases;
+--------------------+
| Database |
+--------------------+
| information_schema |
| mysql |
| performance_schema |
+--------------------+
3 rows in set (0.01 sec)
What am I missing to force Docker to completely rebuild from scratch, so that the mysql database gets created the second time?
There is clearly a big difference in the amount of log output between the first and second runs. However in both cases, it seems to create a volume:
$-> 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
Upvotes: 3
Views: 2111
Reputation: 158714
Docker has two kinds of built-in storage, named volumes and bind mounts. The syntax of these is very similar, but a named volume attaches Docker-managed storage to a container, and a bind mount directly attaches some host directory instead.
Your docker-compose.yml
file says:
volumes:
- ./my_volume:/var/lib/mysql
This is the bind-mount syntax; it names a path directly on your host system. (If you look you can see the my_volume
directory and the MySQL data files within it.)
The MySQL image startup sequence knows to look in the /var/lib/mysql
directory, and if that directory is empty it does the first-time initialization sequence. If there's a MySQL installation there, it will not re-run the initialization scripts, even if you've deleted the content there. This is the same behavior if it's a named volume or a bind mount.
In your case, even though you've deleted the database, the MySQL system files are still there. You can force it to start from scratch:
docker-compose rm --stop mysql
rm -rf my_volume
docker-compose up -d
Upvotes: 3
Reputation: 16100
Wow, an easy one at last. Docker volumes are names, not paths. You have:
volumes:
- ./my_volume:/var/lib/mysql
Which mounts a path on your local filesystem relative to the context (the folder where you started the container), ./my_volume
, into the container at path /var/lib/mysql
. What you really want is this:
volumes:
- my_volume:/var/lib/mysql
Which contains a volume reference (a named volume). This creates/mounts the volume my_volume
into /var/lib/mysql
within the container.
You can diagnose the problem because you'll have a directory called my_volume
next to the docker-compose.yaml
file. Another way to check this is to execute docker volume ls
while the container is running and you'll notice that there is no my_volume
volume (when running your code, not mine -- when you run mine it'll work ;).
Easily fixed though :)
Upvotes: 2