Transfer a database between Docker MySQL images

I was feeling pretty pleased with myself having just figured out how to set up a private Docker registry, when I discovered an interesting thing about Docker’s official MySQL image: commits don’t persist database data! This is my fault for not understanding the documentation and how to work with data volumes.

In any case, my wife set up a Dockerized website in WordPress. We wanted to transfer it to a new domain. I set up a private registry to which to commit images of her data. I deployed everything only to discover that the data, both database and WordPress, are not stored in ther respective images. This was no good for my purposes, so I set out to persist the database and WordPress data by creating and mounting two data volume containers.

Here’s how I transfered everything between my Docker MySQL/WordPress images and their respective data volume containers…

Configure Docker Compose

Supposing we are transfering the website from originaldomain.com to somenewdomain.com, this is how to configure Compose:

1
2
3
4
cd ~
mkdir somenewdomain.com
cd somenewdomain.com
vim docker-compose.yml

Copy and save the following:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
wordpress:
image: wordpress
links:
- mysql
environment:
- WORDPRESS_DB_PASSWORD=secretp@ssword
- VIRTUAL_HOST=somenewdomain.com
expose:
- 80
volumes_from:
- somenewdomaincom_wordpress_data
mysql:
image: mysql
environment:
- MYSQL_ROOT_PASSWORD=secretp@ssword
- MYSQL_DATABASE=wordpress
volumes_from:
- somenewdomaincom_database_data

The volumes_from settings point to containers which point to volumes on the host system…

Create the database volume container

1
docker create -v /data --name somenewdomaincom_database_data mysql /bin/true

Create the WordPress volume container

1
docker create -v /data --name somenewdomaincom_wordpress_data wordpress /bin/true

Fire it up!

1
docker-compose up -d

The two data volume containers don’t contain any data yet. That comes next.

The MySQL database

An aside: some investigating

It was important that I be able to verify for myself that the data wasn’t being persisted, so I needed to examine the databases in each image…

First, I needed to find out what IP my MySQL container was listening on.

1
docker inspect originaldomaincom_mysql | grep IPAddr

Then I used my local mysql installation to connect to the database on the container.

1
mysql -u root -h 172.17.1.163 -p

From the mysql> prompt, I looked at the databases:

1
show databases;

The database was simply called wordpress, so I took a look in there:

1
2
use wordpress;
show tables;

I found a bunch of woocommerce tables, which I knew to be my wife’s WordPress data. I repeated the process for the existing (but broken) somenewdomain_mysql container and discovered that the WordPress database didn’t even exist. My investigation confirmed what I had suspected: the data wasn’t being committed to the image.

Export the database

I needed to get the data out of the MySQL container so that I could write it to a new container pointing to a data volume container. What? To do this, I first needed to know the IP that the original (originaldomain.com) database is listening on:

1
docker inspect originaldomaincom_mysql | grep IPAddr

Then, setting that IP with the -h option, this exports all of the tables:

1
mysqldump -u root -h 172.17.1.163 -p wordpress > originaldomaincom_mysql.sql

Import the database

Find the IP of the new MySQL image:

1
docker inspect somenewdomaincom_mysql | grep IPAddr

Create a wordpress database (if necessary):

1
mysql -u root -h 172.17.1.174 -p

From mysql> prompt, check to see if the wordpress database already exists:

1
show databases;

Create it, if it doesn’t:

1
create database wordpress;

Logout of the the MySQL command line and execute from the host machine:

1
mysql -u root -h 172.17.1.174 -p wordpress < originaldomaincom_mysql.sql

The data has now been imported and is stored in a volume guarded by the _somenewdomaincom_wordpressdata container.

WordPress

Copy the WordPress data

All the WordPress template and customizations are currently stored in volume directly accessed by _originaldomaincomwordpress container. I needed to find that directory on my host machine:

1
docker inspect originaldomaincom_wordpress

I looked under Mounts for Source. The paths looked something like this:

1
/var/lib/docker/volumes/2623fb3bc681407027c1ebdaca118d04b6e851448459d4e577b86105d694af6c/_data

I copied that data to my current working directory for safe keeping:

1
sudo cp -R /var/lib/docker/volumes/2623fb3bc681407027c1ebdaca118d04b6e851448459d4e577b86105d694af6c/_data .

Then I needed the Source path for the _somenewdomaincom_wordpressdata container:

1
docker inspect somenewdomaincom_wordpress_data

It looked like this:

1
/var/lib/docker/volumes/c93e95c490dc2cc5e9dc226d16412f05ccd8f335d437237045632a8f46fda45c/_data

I was careful to note the configuration whose Destination was /var/lib/mysql. There will be two mount points. The other destination (the wrong one) looks like this: /data.

Knowing the destination path, I removed the entire _data directory, because I don’t want any weird stuff hanging around:

1
sudo rm -rf /var/lib/docker/volumes/c93e95c490dc2cc5e9dc226d16412f05ccd8f335d437237045632a8f46fda45c/_data

I copied the contents of the data directory to the _somenewdomaincom_wordpressdata volume container’s source:

1
sudo cp -R data /var/lib/docker/volumes/c93e95c490dc2cc5e9dc226d16412f05ccd8f335d437237045632a8f46fda45c/

With all the data transfered, I restarted Docker Compose:

1
docker-compose restart

Everything looked good, except for one thing. All the links on the homepage were still pointing to the old originaldomain.com domain.

To fix this, I simply edited the wp-config.php file contained in the _data/ directory I had just copied

1
sudo vim /var/lib/docker/volumes/c93e95c490dc2cc5e9dc226d16412f05ccd8f335d437237045632a8f46fda45c/_data/wp-config.php

Then I appended and saved these two lines:

1
2
define('WP_HOME','https://somenewdomain.com');
define('WP_SITEURL','https://somenewdomain.com');

Restart again,

1
docker-compose restart

The site worked as it did before on its new domain.

Conclusion

I have a better understanding of how to work with Docker volumes, which renders my previous application of the Docker technology mostly inadequate.

As well, I suspect the whole import/export MySQL stuff may be unnecessary. It may be sufficient to simply copy the directory as with the WordPress data, but that has not yet been confirmed.