WordPress Team Workflow

Recently I made and article on how to use Docksal with Docker to build a WordPress site. Now I want to go a little deeper and setup WordPress on Docker with out relying on Docksal.

Why Use Docker?

Docker allows us to run all the code, dependences and even operating systems, self contained into individual units, completely separate from the machine that it is running on. Unlike virtual machines, Docker uses containers that are light weight and faster to spin up and down.

The beauty of this, is that we can then share this configuration with any machine running Docker and our developments will install and run in exactly on each developers computer.

What is Docker Compose?

Docker has a Docker Compose tool that comes with Docker Desktop. This works by creating a docker-compose.yml file in your project that you run from the terminal using docker compose up. This will setup your local project environments on Docker.

The purpose of docker-compose is to function as the Docker CLI but to issue multiple commands much more quickly. This keeps you from having to write a ton of commands with the CLI and makes it easier to work with multiple containers.

With Docker and Docker Compose we can specify what services or containers our WordPress site will need. Then we can spin up and manage all of them as a whole to create our local dev environment.

What WordPress Will Need To Run

To run WordPress we currently need PHP 7.4 or higher and MySQL 5.7 or higher and Apache or Nginx. The Docker Hub offical WordPress image comes with PHP and Apache, so we will not need to worry about that. We will also be installing phpMyAdmin to interface with the database.

Install Docker

Installing Docker is easy. Just go to Docker Desktop, choose your operating system and download Docker Desktop. Follow the download instructions and open Docker.

docker-compose.yml

Create a project folder and in that folder create a file named docker-compose.yml or docker-compose.yaml. This is going to be the main configuration file that hold all of the services and containers we will need for our WordPress site to run.

Version

First we specify the version. We will use Dockers latest which right now is 3.9. This will give us access to all the latest syntax goodies and techniques.

Services

After that we need a services heading. Each item in this section is a container spun up to form our Docker compose network. Indents are part of the syntax for Docker Compose, so be sure to tab over under services.

Images

The image tag pulls an image from the Docker Hub which is essentially a pre-built bundle of software. For WordPress we need a MySQL container, phpMyAdmin container and WordPress container.

Volumes

Because containers are temporary by nature, any data we create will be lost if the container are restarted. For WordPress specifically this means we would lose things like images, plugins, themes and all of that would get deleted.

To get around this we can create a Docker volume for persistent data. Volumes are files systems you create out site of a container, that are then mounted on the inside of the container once they are spun up.

Because the data is stored outside of the container, when the WordPress container is restarted or goes down, all of the data will be safe and mounted again once the container goes backup.

At the bottom of the compose file we will create a volumes heading at the same level of services that will be for the database volume. This will hold all of our database information.

volumes:
db_data:

Then in the db services we link to the volume folder.

    volumes:
- db_data:/var/lib/mysql

Environments

The environment variable allows you to pass information into our containers. Check the Docker Hub page for the images you are using and environment variables for that image. These are the same secretes you would use to create a MySQL database in cPanel.

Database - MySQL

MySQL expects a few environment that you would normally setup in cpanel like MYSQL_DATABASE, MYSQL_USER, MYSQL_PASSWORD and MYSQL_ROOT_PASSWORD.

WordPress

We will need to expose a port from the container and map it to a port on the host machine using - '8000:80'. The 8000 number is the host number we choose for our server and the default 80 port will map that to the containers internal port for WordPress.

This will give us http://localhost:8000/ for a local URL.

Networks

In Docker there are several types of networks to allow you to create secure communication between containers. Bridge networks are the most commonly used. We are going to be using a bridge network to handle communication between all of our services/containers.

To create a network in Docker Compose we add networks at the same level as services. Then give it a name that we use in each of the services.

networks:
wpsite:

Then use that name in each of the services to connect to our new network.

    networks:
- wpsite

Now if we list our networks by running docker network ls we see the the new network we named wpsite in the list, at the end of the name of our project folder. There are also the three default Docker created networks bridge, host and none.

Setup Docker

We can delete unused networks by running docker network prune or use docker network --help to see all these options.

Final Code

Putting it all together.

# version of the compose file
version: '3'

services:
# database
db:
image: mysql:5.7
# create a volume mysql-data and map it
# to where MySQL is in the container
volumes:
- db_data:/var/lib/mysql
# if the server reboot the container restarts
restart: always
# https://hub.docker.com/_/mysql -> environment variables
environment:
MYSQL_ROOT_PASSWORD: password
MYSQL_DATABASE: wordpress
# create a new user beyond the default root user
# for the wordpress installation
MYSQL_USER: wordpress
MYSQL_PASSWORD: wordpress
# run all services on a docker network
# call it what ever you want
networks:
- wpsite
# https://hub.docker.com/_/phpmyadmin
# gui for database
# set a port to access on local machine
# 80 to map to container
phpmyadmin:
depends_on:
- db
image: phpmyadmin/phpmyadmin
restart: always
ports:
- '8080:80'
# define mysql server name and password
environment:
PMA_HOST: db
MYSQL_ROOT_PASSWORD: password
networks:
- wpsite
# https://hub.docker.com/_/wordpress
wordpress:
depends_on:
- db
image: wordpress:latest
# map ports to access from our local machine
# 8000 on local machine map to 80 in the container
ports:
- '8000:80'
restart: always
# show wordpress files that are in the apache web root/container by
# mapping from our current project folder
# to the container
volumes: ['./:/var/www/html']
# wordpress environment variables
# host is the db service
# 3306 is the default port for mysql
# match db user and pass
environment:
WORDPRESS_DB_HOST: db:3306
WORDPRESS_DB_USER: wordpress
WORDPRESS_DB_PASSWORD: wordpress
# map the volume of db data and the network of wpsite
networks:
- wpsite
networks:
wpsite:
volumes:
db_data:

Now in the terminal for your project run docker compose up to spin up our local environment. To detach, the Docker Compose network, and run it in the background, instead of keeping a terminal window actively running, use docker compose up -d.

It will take a bit to bring all the images into your machine. Once all the images are downloaded you can go to localhost:8000 to setup WordPress. Then you can go to localhost:8080 to login to phpMyAdmin.

To login to phpMyAdmin with the root user, use user: root and password: password or to login with the new user, use user: wordpress and password: password.

Once you new environment is up and running just start Docker and your container should auto start the server.

Conclusion

There many ways to setup the Docker Compose file depending on the type project. As your projects get more dynamic you can also work with the Dockerfile to manage the build environments. Docker has great documentation at the Docker reference and there is a lot to learn. Luckily the are more and more resource to help along the way.

Resources