How to Setup a new WordPress Project with Docker

Erika Dike
The Andela Way
Published in
7 min readJul 29, 2019

In a not so distant past, life as a developer was not as fun as it is today. A lot of tasks took more time than they should and many hours were spent chasing around bugs that left us scratching our heads wondering what newly installed package messed up our local development environment. Thus, forcing us in the worst of times to start over. But those days are gone (at least for me). Adding Docker to my workflow has made my life as a developer much saner and my computer is happier for that. I can’t imagine starting a project these days without containerization at the back of my mind. If you work on multiple client projects, containerization could make your life more enjoyable. It might add more complexity and time initially but that fizzles away as you get more comfortable with the technology.

Introduction to Isolation

This is not an article about Docker: I won’t go into details about what Docker is and its capabilities. However, I think it will be helpful to write a few things about the technology so we know what it tries to solve and why it matters.

Most developers I know typically have a single work machine but they do tend to work on multiple projects at a time. Each of these projects has different and conflicting software dependencies. One project might only be compatible with PHP 5.0 while another is on the cutting edge with PHP 7. This could also extend to the database layer where different projects require different versions of MySQL.

There are a few approaches that were used prior to Docker. Programming languages had virtual environments where you create one virtual environment per project and specify what versions of software that project uses. All the dependencies of the project are local to that project; i.e. projects do not share software packages amongst themselves. Another popular solution was the use of virtual machines. A virtual machine is a software program that acts as a separate computer. It is also capable of running its own applications and programs like a separate computer.

Now to my favourite isolation approach: containerization. Containerization is a lightweight alternative to virtual machines that involves encapsulating an application in a container with its own operating environment. While Virtual Machines include an entire Operating System, Containerization technologies share a single host operating system and relevant binaries, libraries or drivers across containers. The most popular containerization technology is the open-source Docker, created by Docker, Inc.

Now to create the project

Most popular software packages already have their docker images packaged and available for download on docker hub. Developers can also package their own applications as Docker images for global distribution via docker hub or internal distribution within their organizations. In this tutorial, we are going to be making use of images that have already been packaged for us.

We can create and configure containers by hand in docker by writing commands on our terminal. However, I prefer to define the configurations for each service/container in a YAML configuration file using a tool called Docker Compose (also developed by the Docker, Inc team).

To follow the rest of the tutorial, you will need to have both Docker and Docker Compose installed.

Project Structure

The goal of this project is to set up an environment that allows us to work on our WordPress plugins and themes. This environment will serve as a sandbox where we can quickly test our changes without ever having to restart our containers. It will also be extremely easy to move the project to a different machine.

|__ docker-compose.yml|__ plugins|  |__ name-of-plugin|  |__ ...|__ themes|  |__ name-of-theme|  |__ ...

We will define our containers in the docker-compose.yml.

Now to the docker-compose configuration file

As the title suggests, we are going to be creating three containers for our project:

  1. wordpress
  2. mysql
  3. phpmyadmin

They will all be defined under the services field in our YAML configuration file.

WordPress container

This is the container that will house the WordPress application. Think of this as a separate stand-alone machine. This is also the machine you will hit to access the WordPress site.

services:
wordpress:
image: wordpress:5.2.1
restart: always
ports:
- 8081:80
environment:
WORDPRESS_DB_PASSWORD: example

First, we define the name of the service to be wordpress. Next, we specify the image, this tells docker what image to download on docker hub. The restart field is saying we want Docker to restart the container whenever it fails. In ports, we are telling Docker to expose this service on host port 8081 and tunnel that to port 80 on the WordPress container. This means that anyone hitting our host machine on port 8081 will be tunnelled to port 80 on the WordPress container. Finally, in the environment field, we define all the environment variables that should be supplied to our container. The WORDPRESS_DB_PASSWORD variable is required by the WordPress image. This is the password it will use to connect to the MySQL container.

MySQL container

Our database lives in this container. It won’t be exposed to the world like the WordPress container but we do want it to be reachable from the WordPress container. Docker Compose takes care of that for us by making sure that all the containers defined in a file are able to talk to each other unless we specify otherwise. We do not specify what port number to expose here because the port 3306 is already exposed by the mysql image.

services:...  mysql:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
volumes:
- mysql-data:/var/lib/mysql
...
volumes:
mysql-data:

We will skip explaining terms that were covered in the WordPress service. Here we also define an environment variable: MYSQL_ROOT_PASSWORD. The value of MYSQL_ROOT_PASSWORD is used as a password for the root user. Next, we specify a volume to use to hold our data. Docker containers are designed to be stateless, they neither read nor store information about their state from one session to the next. So whenever, we bring down/destroy our docker setup we lose all information we collected in that session. In the case of a database, we do not want to lose the information in the database. Named volumes as we have defined in the mysql service instructs docker to persist the data from the container unto the host machine. In the above snippet, we are telling Docker to persist data from the container’s /var/lib/mysql directory to our host machine. We do not have to specify the actual location on our host machine where this data should be persisted. We only to identify the volume by giving it a name. This way, we can have multiple containers share the same persistent volume.

phpmyadmin container

This service is not required to get our WordPress setup up and running but it is “a nice to have” as it presents us with an easy way to interact with the database.

services:
...
phpmyadmin:
image: phpmyadmin/phpmyadmin
restart: always
environment:
PMA_HOST: mysql
ports:
8082:80

Again, we won’t go over repeated ideas but focus on new ones or variants of what we have seen. This time we define another new environment variable: PMA_HOST. This is required by the phpmyadmin image and tells it the hostname of our database container. Docker-compose uses the name of the service as the hostname of the container, hence we specify mysql as the value for PMA_HOST. Similar to how we exposed the WordPress container, we also expose this container on port 8082 on our machine.

Making our plugin directory available on Docker

The last step is to expose our plugin to the WordPress container. We need to know a couple of things to do this: the location of our plugin on our host machine and the location of the plugin within the WordPress container. Based on the project structure we outlined at the top, our plugin should be in the plugins directory of our project. We can specify the source location in two ways either relatively or by providing the full path. We will be going with the relative approach for the location of the plugin on the host machine and the absolute approach for the location of the plugin within docker.

Take a look at our WordPress service with the plugin volume defined.

services:
wordpress:
image: wordpress:5.2.1
restart: always
ports:
- 8081:80
environment:
WORDPRESS_DB_PASSWORD: example
volumes:
- ./plugins/new-plugin:/var/www/html/wp-content/plugins/new-plugin
...

We have named the plugin: new-plugin. And this would be its name both on the host machine and within the WordPress container.

Tying it all together

version: ‘3.1’services:
mysql:
image: mysql:5.7
restart: always
environment:
MYSQL_ROOT_PASSWORD: example
volumes:
- mysql-data:/var/lib/mysql
wordpress:
image: wordpress:5.2.1
restart: always
ports:
- 8081:80
environment:
WORDPRESS_DB_PASSWORD: example
volumes:
- ./plugins/new-plugin:/var/www/html/wp-content/plugins/new-plugin

phpmyadmin:
image: phpmyadmin/phpmyadmin
restart: always
environment:
PMA_HOST: mysql
ports:
- 8082:80
volumes:
mysql-data

Once we have our configuration, we can fire up our docker cluster with the docker-compose command: docker-compose up -d. This command will pull all our images and fire up our containers. So that when you hit

http://localhost:8081/wp-admin

you will find that you are directed to WordPress’ setup page where you will be asked to set up your new WordPress instance. You can also visit the phpmyadmin site by opening up http://localhost:8082 on your browser. Use the credentials below to access the phpmyadmin server:

username — root
password — example

You should update the passwords above to more secure versions for anything outside of demonstration purposes.

Conclusion

Once you get the hang of it, Docker makes it really easy to get a project up and running in a short time. But its allure (at least for me), is that it makes it even easier to move your projects around and work on multiple projects without worrying about conflicting dependencies giving you a bad day.

This post didn’t scratch the surface on the capabilities and features of Docker. My main goal was to show how you would set up a WordPress development environment easily with Docker. For more information on docker and docker-compose, check out the documentation on their site. You can also get started with this resource, also from Docker, Inc.

--

--

Erika Dike
The Andela Way

I write software and occasionally publish stuff about some things I found interesting.