Docker – Part 1 – Intro
Yet another blog series on docker? Yep. What makes it different to the rest? No idea, but you might find it useful anyhow.
This series is written from a perspective of a WordPress dev who has only dabbled with docker before. The ultimate aim is to build a dev environment from scratch.
This is part 1, a gentle introduction to the terminology and what it’s all about.
What is docker?
Back when I were a lad, if you wanted a sand boxed environment in which to play around with things without messing up your hard fought OS config, you had to do it inside a VM.
A classic Virtualbox VM contained a full operating system, from the kernel to the user apps. Networking, volume management, and sheer size of images (usually more 2Gb) meant that it was a bit of a pain. You also had to wait through the installation process each and every time you wanted a new vm.
Docker came along and allowed us to forgo needing the full underlying OS and instead us the kernel and other low level OS layers from the host operating system. Instead of having to run through a full OS install, you instead just take a base OS and then layer on top of it.
It’s not all sunshine and rainbows though. VM software was a fairly painless setup guided by a GUI. You created a new vm, attached a .iso of the OS and away you went.
Docker, on the other hand, is a bit more involved. It’s mainly done through the command line and uses specific text files to define the environment and then create it. There are GUI and VSCode extensions for day-to-day management, but you still need to create these sand boxed systems by hand, or use a pre-configured environment that someone else has created.
Images, Containers, and composition
A docker environment is made up of containers. These are isolated processes. By default, they sit on their own internal network and don’t open any ports unless you specify them. They also, by default, don’t have access to your file system.
To allow a container to be reached, we specifically need to open a port. To allow a container access to our file system we need to explicitly mount a volume. Somewhat similar to the old VM days but just more pragmatic, and more light weight.
To create a container, we first need an image. You can think of an image as being a class, and a container being an object instantiated from that class in that the image is your blueprint, and your container is a running build of that blueprint.
For a simple WordPress setup, the classic server stack would be:
- Web server
- PHP
- MySQL
We could create one single docker image, based on Ubuntu Server, and configure the whole stack inside it. But to do this, would be to miss out on why we would want to use docker in the first place over a traditional LAMP stack (Linux, Apache, MySQL, and PHP) installed inside our OS. The individual technologies don’t matter here, but in essence a basic stack to run a WordPress site.
The key to docker is its isolated process nature – let me explain…
Lets say you have an Ubuntu Server container running and all is well with the world. Then, lets say a new version of PHP is being released and you need to test your site with it to make sure you’re not going to encounter any issues with the version upgrade.
For this single container architecture, we would need to change the underlying image, rebuild the container with these changes and then test. What if during that testing phase, your client phones up with an emergency? You need to roll back, rebuild, and get on with fixing the problem.
Instead, because all containers are isolated processes we could re-architect with the following:
- NGINX container to be our web server
- PHP-FPM container which NGINX will use to execute our PHP
- MySQL container that keeps our database separate from everything else
This could also be an Apache setup. Choose what works for you and your hosting environment.
Doing it like this would allow us to swap out individual pieces of our setup with less disruption. But also, with more containers comes more headaches. This is where docker compose comes in.
We define our services: web server, php handler, MySQL and then tell it what versions we should be using. This means at any point we can stop all our running containers, pull down the new php version container, make a quick change to our compose file, and get it up and running.
We could have containers for php7 and php8, both running at the same time without conflicting. Making flipping back and forward a lot more trivial than installing a whole new VM or re-installing our LAMP stack.
Sounds good? Well lets move on to part 2.