Using Docker Compose to Migrate WordPress Website on Docker

23 / Jun / 2016 by Raghu Sharma 0 comments

03.docker-wordpress

Docker is a like your mini virtual machine that is very light on your host resources. Unlike virtual machines, which need their own kernel, Docker creates virtualized experience on top of your running kernel. The mini virtual machines provided by Docker are called “containers”. These containers are platform independent and can be reused for deploying applications on different environments.

In this blog post, we will migrate an existing WordPress website on Docker. We will use Nginx as the web server (with php5-fpm for PHP support) and MySQL as the database solution. We will create 2 images (for Nginx and MySQL) and use Docker Compose to link them.

The steps followed assume that the Docker server is a separate machine from the current WordPress server. However, both of these can be the same machine in which case you do not need to transfer the files to the other machine. This setup can be used by developers as well for running the WordPress website on their own machine.

Prerequisites:

This blog post assumes that the target machine is running Linux based OS with Docker and Docker Compose installed. Below are the requirements for this setup:

  • Operating System: Any Linux machine (Ubuntu 14.04 server is used for this demo)
  • Docker version 1.11.2
  • Docker Compose version 1.7.1

So let’s start. Below are the steps you need to follow.

STEPS:

1. Backup website files and database.

Before starting with the migration, we need to take backup of website files used by WordPress and the database used by WordPress. Let’s start by backing up the DocumentRoot for WordPress website:

root@ubuntu-wp-server:~# tar -czf wordpressback.tgz wordpress/

Now let’s dump the WordPress database.

root@ubuntu-wp-server:~# mysqldump -u root -p wordpress | gzip > wordpress.sql.gz
Enter password:

Enter your MySQL password when prompted. We have compressed the database dump so that the transfer is faster.

Note: We assume that there are no write queries on the database in this migration process. This migration can be achieved with zero downtime with proper strategy.

root@ubuntu-wp-server:~# gzip wordpress.sql

2. Setup new DocumentRoot and DB for Docker containers

Now let’s transfer these files onto the Docker server. You can also use your own machine for Docker. In that case, you do not need to transfer the files.

root@ubuntu-wp-server:~# scp wordpressback.tgz wordpress.sql.gz \
> wp-docker.com:/docker-data/wordpress/
root@wp-docker.com's password:
wordpressback.tgz 100% 7589KB 7.4MB/s 00:00
wordpress.sql.gz 100% 90KB 89.6KB/s 00:00

We are using these 2 Docker images:

  1. wpmysql
  2. wpnginx

Note: These images can be pulled from Docker Hub with following commands:

docker pull raghuttnd/ttnblog_wpmysql
docker pull raghuttnd/ttnblog_wpnginx

We will shortly have a look at the Dockerfiles used to create these 2 images and the Docker Compose files that we have used to bring up these containers.

Now that the dump file and the website tar is transferred on the Docker server, we need to extract the files and prepare the DocumentRoot directory which wpnginx container will use.

The directory “/docker-data/wordpress” will be used as the DocumentRoot for our website to be hosted on Docker. We will mount this directory inside the Docker container.

root@ubuntu-docker:~# cd /docker-data/wordpress/
root@ubuntu-docker:/docker-data/wordpress# tar -xzf wordpressback.tgz --strip 1
root@ubuntu-docker:/docker-data/wordpress# rm wordpressback.tgz

The DB dump file needs to be in a separate directory. We will use the directory “/docker-data/dbdump/” for keeping this file and mount this directory inside the wpmysql container.

root@ubuntu-docker:~/docker/compose/wordpress# mv wordpress.sql.gz /docker-data/dbdump/
root@ubuntu-docker:~/docker/compose/wordpress# gunzip /docker-data/dbdump/wordpress.sql.gz

Here, we need to make changes in the wp-config.php file according to our new setup. We need DB name, DB User, DB Password and DB Host. These will be created in our wpmysql container. So once our Docker Compose file is ready, we will come back and make these changes.

3. Docker Setup

The Docker setup involves setting up the images using the Dockerfiles and Entrypoint scripts (launch scripts).
Now we need to bring up the Docker containers. The containers used for this demo are based on ubuntu:14.04 image.

wpnginx:
The image used for Nginx is created using this Dockerfile:

FROM ubuntu:14.04
RUN apt-get update

#Install nginx
RUN apt-get -y install \
nginx \
php5-fpm \
php5-mysql \
wget
#Clear the DocumentRoot
RUN rm -rf /usr/share/nginx/html/*
#Copy the default configuration
COPY conf/default /etc/nginx/sites-available/
RUN mkdir /root/scripts
COPY launch.sh /root/scripts/
ENTRYPOINT /bin/bash /root/scripts/launch.sh

The launch script starts Nginx and php5-fpm in background and continues running:

#!/bin/bash
service nginx start
service php5-fpm start
tail -f /var/log/nginx/{access.log,error.log}

You can see the Nginx logs with the command:

# docker logs -f wpnginx-container

wpmysql:
The Dockerfile used for this image is:

FROM ubuntu:14.04
RUN apt-get update

#Install mysql non-interactive
RUN echo mysql-server mysql-server/root_password password mysqlpass | debconf-set-selections
RUN echo mysql-server mysql-server/root_password_again password mysqlpass | debconf-set-selections
RUN apt-get -y install mysql-server
RUN sed -i '/bind-address/c\bind-address            = 0.0.0.0' /etc/mysql/my.cnf
RUN mkdir /root/scripts
COPY launch.sh /root/scripts/
RUN touch /var/lib/mysql/firstrun
RUN ln -s /var/lib/mysql/local.cnf /root/.my.cnf

ENTRYPOINT /bin/bash /root/scripts/launch.sh

The default root password used in this image is overridden when the image is brought up the first time (using the launch script).

Here, as you can see that the ENTRYPOINT for this image is a launch script. This launch script does the following (using environment variables):

  1. Creates the root password for the first time.
  2. Creates the WordPress database.
  3. Creates the WordPress user and sets its password.
  4. Optionally populate the above database using the dump file if the dump file is provided in the environment variable “WORDPRESS_DUMP_FILE” (and removes the dump file if the dump is successful).

Here comes the launch script for wpmysql:

#!/bin/bash

FIRSTRUN="/var/lib/mysql/firstrun"
WORKDIR="/dockerinit/"
MYSQLCRED="/root/.my.cnf"
mkdir -p $WORKDIR

if [ -e $FIRSTRUN ]
then
	if [ -z $MYSQL_ROOT_PASSWORD ]
	then
		echo >&2 "You are running the script for first time."
		echo >&2 "Please specify MYSQL_ROOT_PASSWORD environment variable."
		exit 1
	else
		service mysql start
		echo "Resetting root password for first time."
		mysql -u root -pmysqlpass <<-EOSQL
			DELETE FROM mysql.user WHERE User='root' ;
			CREATE USER 'root'@'%' IDENTIFIED BY '${MYSQL_ROOT_PASSWORD}' ;
			GRANT ALL ON *.* TO 'root'@'%' WITH GRANT OPTION ;
			DROP DATABASE IF EXISTS test ;
			FLUSH PRIVILEGES ;
		EOSQL
		>$MYSQLCRED
		echo "[client]" >> $MYSQLCRED
		echo "user=root" >> $MYSQLCRED
		echo "password=${MYSQL_ROOT_PASSWORD}" >> $MYSQLCRED
		rm $FIRSTRUN
	fi
fi

#Setting passed env variables
WORDPRESS_DB_USER=${ENV_WORDPRESS_DB_USER:=wpuser}
WORDPRESS_DB_PASSWORD=${ENV_WORDPRESS_DB_PASSWORD:=wppass}
WORDPRESS_DB_NAME=${ENV_WORDPRESS_DB_NAME:=wordpress}

service mysql start

echo "Initializing database.."
mysql <<-EOSQL
	CREATE DATABASE IF NOT EXISTS $WORDPRESS_DB_NAME ;
	GRANT ALL ON $WORDPRESS_DB_NAME.* TO '$WORDPRESS_DB_USER'@'%' IDENTIFIED BY '$WORDPRESS_DB_PASSWORD' ;
	FLUSH PRIVILEGES ;
	EOSQL

#Checking if there is any file for restoring the DB dump
if [[ -n $WORDPRESS_DUMP_FILE ]]
then
	if [[ -f $WORDPRESS_DUMP_FILE ]]
	then
		echo "Checking if there is any file for restoring the DB dump"
		mysql -u ${WORDPRESS_DB_USER} -p${WORDPRESS_DB_PASSWORD} $WORDPRESS_DB_NAME < $WORDPRESS_DUMP_FILE
		if [[ $? -eq 0 ]]
		then
		  rm -f $WORDPRESS_DUMP_FILE #So that we dont accidentally dump again
		fi
	else
		echo >&2 "The dump file specified in variable WORDPRESS_DUMP_FILE does not exist."
		exit 2
	fi
fi

service mysql stop
/usr/bin/mysqld_safe

Before bringing up the Nginx container, we need to make sure that MySQL container is running. So we will use Docker Compose for solving this dependency issue. The docker-compose.yml file to be used is:

version: '2'
services:
nginx-wordpress:
image: wpnginx
hostname: wphost
container_name: wpnginx-container
volumes:
- "/docker-data/wordpress/:/usr/share/nginx/html/"
ports:
- 80:80
depends_on:
- mysql-wordpress

mysql-wordpress:
image: wpmysql
hostname: wpmysqlhost
container_name: wpmysql-container
volumes:
- /docker-data/dbdump/:/dbdump
- wp-mysql-data:/var/lib/mysql
environment:
- MYSQL_ROOT_PASSWORD=ttndpass
- ENV_WORDPRESS_DB_USER=wpuser
- ENV_WORDPRESS_DB_PASSWORD=wppass
- ENV_WORDPRESS_DB_DATABASE=wordpress
- WORDPRESS_DUMP_FILE=/dbdump/wordpress.sql

volumes:
wp-mysql-data:

In this file, we have passed few environment variables to MySQL image. Below are the variables used:

  • MYSQL_ROOT_PASSWORD – Password for MySQL root user.
  • ENV_WORDPRESS_DB_USER – The new WordPress username.
  • ENV_WORDPRESS_DB_PASSWORD – Password for above WordPress user.
  • ENV_WORDPRESS_DB_DATABASE – Database name to be used by WordPress.
  • WORDPRESS_DUMP_FILE – Path to the dump file which needs to be restored to above database.

One last step before bringing up the Docker containers: We need to make DB connection changes in the wp-config.php file. The DB host in this file will be the name of MySQL service defined in the Compose file above (mysql-wordpress).

4. Bring up the Containers:

Now let’s bring up the containers using Docker Compose. The following command can be executed to run the containers in background:

root@ubuntu-docker:~/docker/compose/wordpress# docker-compose up -d
Creating wpmysql-container
Creating wpnginx-container

That’s all folks.

It might seem like a lot but once the ground work is done (the Dockerfile and docker-compose.yml), there is not much left to take care of. If you just want to use these images, without going into the whole process of creating them, you can pull them from Docker Hub as mentioned earlier.

FOUND THIS USEFUL? SHARE IT

Leave a comment -