Overview
The beauty of Docker is how portable your applications become. Beyond that it also allows to version control our entire instance, providing a mechanism for quick rollbacks, updates, and audits. This tutorial will show you how to host your WordPress site with Docker by creating an image for it and deploying it.
Run WordPress in Docker
The simpliest example of running a WordPress site in Docker is too pull down the official WordPress image.
docker pull wordpress
If you prefer to use a specific version of WordPress, we can specify that when we pull an image. For example, we can pull down version 4.9.5.
docker pull wordpress:4.9.5
To run a WordPress container from the image we pulled down, we runt he following command.
docker run -d -p 80:80 wordpress:4.9.5
Verify that the image is running by using the docker ps command. The output will show you the containers state, name, and network information.
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 41442d5c2e9b wordpress:4.9.5 "docker-entrypoint.s…" 3 seconds ago Up 2 seconds 0.0.0.0:80->80/tcp awesome_tu
Great. We can see our WordPress container is running. Let’s test that we can access the site from a web browser.
Great. We can see our WordPress container is running. Let’s test that we can access the site from a web browser.
It looks like everything is working. We are able to deploy a new WordPress site, configure it, and post content. But what if you wanted a custom configuration out of the box, rather than a vanilla install? You will need to create your own Docker image based on the WordPress one you’re using.
Creating Your Dockerfile
- Create your workspace for building a new image.
mkdir ~/Workspace/Docker/Wordpress
- Create a new empty file called Dockerfile in the workspace.
touch ~/Workspace/Docker/Wordpress/Dockerfile
- Open the Dockerfile in a text editor.
vi ~/Workspace/Docker/Wordpress/Dockerfile
- Add the following lines.
- Save your changes and exit the text editor.
- Build your custom WordPress image.
docker build -t myblog/wordpress:1.0.0 ~/Workspace/Docker/Wordpress
Running Your Custom WordPress Docker Container
Let’s run a container based on our new Docker image.
- Start a new container based on your image.
docker run -d -p 80:80 myblog/wordpress:1.0.0
- Use docker ps to verify the container is running.
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8a5cb628c0c0 myblog/wordpress:1.0.2 "docker-entrypoint.s…" 15 seconds ago Up 13 seconds 0.0.0.0:80->80/tcp nifty_hopper
- Open a web browser and check the site is accessible.
Customize Your WordPress Image
We made a new image based on the official WordPress one. However, there’s no difference between the two. Let’s customize ours to match our needs.
We’ll be seeding our new image with our theme pre-installed. We’ll also add a couple of plugins, too.
- In your Docker image’s workspace, create a new directory for your theme.
mkdir -p themes/mytheme
- Create a new directory for your plugins.
mkdir plugins
- Extract your theme into the themes directory or clone it from your repository.
git clone http://github.com/example/mytheme.git themes/mytheme
- Extract each plugin in the plugin directory.
cd plugins tar xvf path/to/plugin1.tar.gz tar xvf path/to/plugin2.tar.gz
- Use the COPY Dockerfile instruction to copy the theme and plugins to your image during build. Open your Dockerfile and add the following lines
COPY themes/mytheme /var/www/html/themes/mytheme COPY plugins/plugin1 /var/www/html/plugins/plugin1 COPY plugins/plugin2 /var/www/html/plugins/plugin2
Making Your Themes, Plugins, and Uploads Persistent
The problem with seeding your WordPress image with your themes, plugins, and uploads is that any changes to them will not persist. This is because Docker containers are ephemeral — all changes to it while running will be lost when the container is stopped.
By using Docker’s volumes feature we can ensure all changes to certain directories are preserved when we restart the container.
- Open your Dockerfile in a text editor.
vi Dockerfile
- Add a volume for your themes, plugins. and uploads WordPress directories.
VOLUME ["/wp-content/themes/mytheme","/wp-content/plugins","/wp-content/uploads"]
- Save your changes and exit the text editor.
- Build a new version of your WordPress image.
docker build -t myapp:0.0.1 .
Let’s run the new image and test that all changes to themes, plugins, or uploads are persistent.
- Start a new a container based on your latest image.
docker run -d -p 80:80 myapp:0.0.1
- Verify that the container is running.
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES 8a5cb628c0c0 myblog/wordpress:1.0.2 "docker-entrypoint.s…" 15 seconds ago Up 13 seconds 0.0.0.0:80->80/tcp nifty_hopper
- Open the WordPress site in a web browser.
- Install a plugin.
- Upload a few images.
- Stop your WordPress container. First identify the docker images ID using the docker ps command, and use it with the docker stop command.
docker ps
docker stop nifty_hopper
- Verify that the container is no longer running.
docker ps
CONTAINER ID IMAGE COMMAND CREATED STATUS PORTS NAMES
- View the contents of the plugins, themes, and uploads directories.
ls ./plugins ls ./themes ls ./uploads
- Start a new WordPress container based on your image.
docker run -d -p 80:80 myapp:0.0.1
- Open your WordPress site in a web browser.
- Verify that your plugins and images are still available.
Specifying Mount Targets
We now have persistent storage for parts of our WordPress site that need to persist longer than the lifecycle of our container. All volumes are written to an unspecified location on the filesystem managed by Docker when they are created.
To specify the location on your filesystem you wish for the volumes to mount from, you can do so using the -v
flag.
docker run -d -p 80:80 -v themes/mytheme:/var/www/html/wp-content/themes/mytheme -v plugins:/var/www/html/wp-content/plugins -v uploads:/var/www/html/wp-content/uploads myapp:0.0.1
- Open your WordPress site in your web browser by navigating to http://localhost/.
- Verify your theme is available.
- Verify your plugins are available.
- Upload some images to your WordPress instance.
- From the command line, verify that the images you uploaded are available in your uploads directory.
Lower Your Container’s Privileges
Your container will run as Root by default. This can lead to unexpected security
Your container will run as Root by default. This can lead to unexpected security
The Dockerfile has a USER instruction that allows you to specify a user with the least amount of privileges required to run your container. If you are mounting volumes from your filesystem, the user or a group it is a member will need access to the directories.
- Create a new user for your WordPress container.
useradd wpuser1
- Grant ownership of the themes, plugins, and uploads directory the container will mount from to our new user.
chown -R wpuser1 themes
chown -R wpuser1 plugins
chown -R wpuser1 uploads
- Add the USER directive to your Dockerfile.
USER wpuser1
Running Containers in Production
In a production
We can achieve this in a number of ways. The simplest approach is to set the container’s restart policy. The following policies can be used.
off (Default) | A container will not be restarted automatically |
on-failure | A container will restart automatically after a failure. A limit can be applied by appending :<int> to the end. For example, limiting restarts to 5 failures only we would use on-failure:5. |
unless-stopped | A container will always restart automatically unless it has been manually stopped. |
always | The container will always restart itself |
A good policy
We set the policy when the container is started using the -restart flag followed by the policy. The following example shows you how to set the restart policy to unless-stopped.
docker run -d -p 80:80 -restart unless-stopped myblog:0.0.1
Putting it all together our docker command for running WordPress would
Now, maintainability starts becoming a problem if we have to continue to remember to execute such a lengthy command. We can greatly simplify it all by introducing docker-compose.
Using Docker Compose
Docker compose is a tool built in Docker that allows us to define the starting conditions of our containers.
example
To start our WordPress site we now only need remember to run docker-compose up. All of the volumes and environment variables needed to run our WordPress site are defined the docker-compose.yml file.
Orchestration
While simply running the docker command directly and setting a restart policy or using Docker Compose is a good entry into running containers in production, the next evolution of your environment should be to introduce orchestration.
The two most popular orchestration solutions for Docker are Kubernetes and Docker Swarm.
This topic is beyond the scope of this tutorial. Setting up an orchestration layer is rather complex, and is unlikely to be beneficial when only running a few containers. It would not be a very cost optimized way of running your blog.
However, if you were running a large number of WordPress sites that needed high availability, then orchestration would be greatly beneficial.