WordPress Storage Container – Setting up the database in Docker
Written by Bunkers on February 25, 2017
This is a follow on post to yesterday's introduction covering my motivations and approach for setting up a development WordPress Docker environment. If you're following along, make sure you have a working Docker tool set installed, so you can run docker
and docker-compose
on the command line. If you haven't then look back at yesterday's post for some options.
I've simplified (at least for me) the approach taken in my main reference article by not using Ansible. This has pros and cons, but it's another technology to understand, and another moving part to go wrong!
I am using docker-compose
. It's technology that may go out of favour soon for more production level tools for orchestrating multiple containers, but for this project it's perfect.
Four containers make up the environment. These are:
- Percona - The database container, running Percona. If you've not come across it before it's a MySQL compatible database server. It has some advantages, most notably that it isn't MySQL and I believe performance is better too.
- Data - Probably badly named, but this is the file system volume. It's where most of the work happens for me, as I 'install' WordPress if it's not found, and setup the
wp-config
file etc. - Web - An Nginx container that serves as a front end to...
- PHP - A straightforward PHP container running FPM (FastCGI Process Manager) so it is a bit like running an Nginx proxy to a PHP server
Let's start with the database. We're going to use the main image, but add in a couple of scripts to make backing up and restoring the database more straight forward.
Create a project directory (I've called mine wp-docker
) and a sub-directory called percona
. In there create a file called load_db.sh
with the following contents:
#!/bin/bash echo "use $MYSQL_DATABASE;" | cat - /tmp/wp_backup.sql > temp && mv temp /tmp/wp_backup.sql mysql -uroot -p$MYSQL_ROOT_PASSWORD < /tmp/wp_backup.sql && rm /tmp/wp_backup.sql |
If you're familiar with using the MySQL client this should be straightforward. It's taking a SQL backup file from /tmp/wp_backup.sql
and adding a command to switch to the correct database at the top. Then it logs in as root
, runs the SQL script and deletes it. This is so you don't accidentally stamp over your database at a later date. You'll notice we're using a couple of environment variables here. I'll cover that shortly.
As you might be able to work out from this, if you've got a database backup you'd like to use put that in a further sub-directory called tmp
and name it wp_backup.sql
Next create another script file called backup.sh
that just contains:
#!/bin/bash MYSQL_PWD=$MYSQL_ROOT_PASSWORD mysqldump -hlocalhost -uroot $MYSQL_DATABASE |
This script is a single command. It runs mysqldump
to get a backup SQL script for the database.
Now create the Docker file, called Dockerfile
with the following contents:
FROM percona:latest COPY tmp/wp_backup.sql /tmp/ COPY load_db.sh / COPY backup.sh / RUN chmod +x /load_db.sh RUN chmod +x /backup.sh |
This take the latest Percona image and copies in our database backup along with our two helper scripts. Lastly it makes the scripts executable so we can actually run them!
Come out of the percona
directory and create another file called db.env
. As the name hints at, this is a file containing the database environment variables used by all the containers that need database connection information.
You can vary the contents from mine if you want to use different names for your database and user, but for now make the contents:
MYSQL_DATABASE=wpdocker MYSQL_USER=wpdocker MYSQL_PASSWORD=password MYSQL_RANDOM_ROOT_PASSWORD=1 WORDPRESS_DB_HOST=wpdb |
That's everything we need and to build our Percona container. Use this command to do just that:
docker build ./percona |
All being well this will output an image ID which we can then use to run a container with:
docker run --env-file db.env -name percona -d caf6680063ae |
Your image ID at the end will be different from mine. If you want to check you're up and running then you can run:
docker exec -it percona mysql -uwpdocker -p wpdocker |
After the prompt for your password, set in the db.env
file then you should find yourself in the familiar MySQL command line client.
The last file to create is another helper script. You'll notice that there is an environment variable called MYSQL_RANDOM_ROOT_PASSWORD
which causes the generation of a random password for the root
user on startup. It outputs this just once, so if needed, you must search the logs for GENERATED ROOT PASSWORD
. I found this was a bit irritating, so created a script to help. If you want to do the same, create a file called dbpass.sh
and make it executable with chmod +x dbpass.sh
. Place the following script in the file:
#!/bin/bash docker logs percona 2>&1 | grep PASSWORD | sed -e 's/GENERATED ROOT PASSWORD\: //g' | awk 'NR==1 { printf("%s", $0); next } { printf("\n%s", $0) }' | pbcopy |
This is a bit hacky, but it searches the logs of the container for a line with PASSWORD
in it. The sed
command removes GENERATED ROOT PASSWORD:
at the start of the line and the awk
command makes sure the end of the line has carriage returns stripped. Lastly it pipes it through pbcopy
to place it on my clipboard. This is Mac specific, and I don't know if there's an equivalent for Linux, so feel free to remove that. It will just echo the password to the screen instead.
Now we can run our load_db.sh
script with:
docker exec -e MYSQL_ROOT_PASSWORD=aihohjohz7Ahhohx9fidohpheideik percona ./load_db.sh |
Your password will hopefully be different! Getting a backup of the database is similar:
docker exec -e MYSQL_ROOT_PASSWORD=aihohjohz7Ahhohx9fidohpheideikoo percona ./backup.sh > db20170225.sql |
There's some additional work I'll do here when this is a production environment. Organisation and rotation of the backup files for example. There's a good script I use elsewhere that backs up MySQL databases via a daily cron job.
So there we have it! One layer of the application complete. Any application requiring a MySQL database could use the same setup too. After all that scripting it's time to reward myself with a strong cup of coffee!