Docker. It’s everywhere. I use it at work and at home. It’s amazing for doing development in environments that more closely match production (such as running a full Laravel stack with queues, Redis, database, local mailmog for catching test email).
In order to learn more about docker, and improve my ability to roll out sites I host, I decided that I wanted to move a whole bunch of WordPress sites to docker. The existing setup is based on Ubuntu 16.04 LTS running on Nginx and PHP-FPM with per user resource pools for better security and site resource allocation. PHP 7.0 has been end of life for some time and it’s definitely time to update. Ubuntu LTS likely won’t track current PHP versions due to the way PHP’s release cycle has changed to be effectively 2 years. That means before Ubuntu 20.04 (released just days ago) is end of Life, PHP 7.4 will have been in end of life for over a year and won’t have had active support for over 2 years! Docker, I think, will allow me to better update the environments and keep them in line with the PHP release cycle. Hopefully it also makes them easier to migrate to new operating systems later.
I’ve already had experience with Traefik as a reverse proxy and it’s fantastic for handling Lets Encrypt SSL certificates with multiple sites out of the box. I can easily add docker containers with labels and they’ll appear automatically in Traefik; magic!
So here’s what I had in my head when I started:
- VM running Ubuntu Server 20.04 LTS
- A docker user that manages and has permissions over everything
- A docker-compose file in that user’s home folder. This file runs the core config for Traefik and any other main containers I need (maybe fail2ban too).
- Each site exists in a subdirectory named after it’s domain name. Within that there’s a docker-compose file related to that site and any files are stored there too.
- Database instances either per site or provided by the host
So that gives you something that looks like:
/home/docker/docker-compose.yml # traefik
/home/docker/aptgetlife/docker-compose.yml # wordpress and MySQL
/home/docker/aptgetlife/public_html/ # site files
/home/docker/aptgetlife/mysql/ # database files
Problem: The docker PPA for ubuntu doesn’t exist for 20.04!
Ubuntu’s apt packages are often out of date, by default I jump straight into the docker doc website in order to get the latest possible version. Or not. There was no PPA available for 20.04 yet!
Fallback was to use apt. Since it’s a new release it was an up to date docker package. It may be worth changing to the PPA once it’s available.
Problem: Packet loss on ubuntu 20.4
While editing the master docker compose file, my ssh connection kept hanging and dropping. Following some pings I discovered that there was an intermittent network connection. It isn’t clear if this was caused by the docker networking packages, KVM drivers or Ubuntu 20.04 itself. It has only been out a day so there’s possible issues with the OS itself.
Fallback was to go back to Ubuntu 18.04 which didn’t have any issues! I’ll jump back to 20.04 after it’s bedded in a little and hopefully the issue will go away.
Problem: The traefik network can’t be seen by individual sites
This is a new one to me and I’ve never done this before so I didn’t have any experience of the setup. I have named my internal network traefik in my main docker-compose file. This works great. Traefik will create the network and the traefik container will connect to it fine. What didn’t work was the per-site docker-compose file connecting to the network. It wanted to create it’s own version named after the folder it was in. I discovered that as of docker-compose format version 3.5 (https://github.com/docker/compose/issues/3736) it allows you to use named containers.
networks: aptgetlife: # network for this container and associated resources like MySQL traefik: # link to Traefik for inbound traffic external: name: traefik
Problem: wordpress site URLS
Okay. This is one of my pet hates with WordPress. WordPress requires a site URL. This apparently was “www.” and I’d set it up on the new system without. It turned out easier to change the configuration to use “www.” instead of convincing WordPress to change the URL. This worked. Except no style sheets or Javascript would load. This, as it turns out, is due to WordPress loading insecure URLs for these assets. I attempted to use tools to update the SQL file and edited the wp-config.php file but neither would solve this problem.
sed -i 's|http://www.aptgetlife.co.uk|https://www.aptgetlife.co.uk|g' wp_aptgetlife.sql
This actually defeated me. I really don’t understand WordPress and how insistent it is to load resourced on particular URLs.
What have I learned?
Well, I’ve learned a lot about docker-compose, networking, override files. I know my architecture will work. I have also learned that I dislike WordPress. Alot. I’m sure the site asset problem is fixable, but I don’t have the patience to deal with it. I’m not interested in fixing WordPress related problems. Even though this project failed, and it is something I wanted to use for moving my hosted sites to, I have gained a lot of knowledge in the process. So instead of taking the failure “I have not deployed my sites using docker”, I am trying to look at the benefits of the knowledge I’ve gained and reflecting on the project as a learning experience. Hopefully a little bit of a retrospective will embed some key technical details in my brain for future DevOps! It’s also important to research what’s possible with systems architecture and I’d have looked into this before starting if it were a work project, but because it’s a personal project I didn’t feel the need. This was almost a playground, a trial run to see if it was even feasible. I think I learnt more and more quickly through this make, fail, make, fail, make, fail iterative approach. I had a definable success for each of the failures and a learning experience from each while overcoming them.
My big takeaway is that docker-compose has some great features in 3.5+ that I didn’t know existed. There’s some great information about networking (and in particular the section at the end about “external” or pre-existing docker networks) on their website https://docs.docker.com/compose/networking/