Docker in 2020: Did Someone Say Isolation? (Part I)
Well, 2020 has given me a fair bit a free time, and I finally figured it was time to dive into Docker. My first experience with Docker was back in 2014, when I spun up a vanilla Ubuntu container, installed Apache, set up a hello-word site, and then realized nothing was persistent. This was quickly followed by uninstalling Docker. In the time between then and now, container usage has taken off, and it’s gotten to a point where it’s difficult to ignore.
For awhile now I haven’t had a scalable solution to hosting a large number of sites. On one end of the spectrum, you can give each site it’s own isolated VM, but this is resource heavy and now you have an endless number of VMs to manage. On the other side of the spectrum, you can host all the sites on one VM using vhosts. While this is easier on the computing resources, this lacks in security, and also makes resource limits tricky. Docker is a good fit for a task like this; you can spin up isolated websites in a matter of minutes using one image. In this project, we’ll start small with a simple website setup, and grow it out into a more polished configuration in future posts. For these examples, I spun up a CentOS 8 VM (which I’m already regretting, but more on that another time), and installed the latest version of Docker, which is 20.10.
The main use case I’d like to explore is isolated WordPress sites. There’s a few different ways to go about this, but the container philosophy would say each WordPress setup should get its own web and database containers. This is light on storage, as all web and database instances would use the same respective image, but a little heavy on memory. We’ll go over some ways to optimize this in a later post. For a starting point, the Docker site has a great little tutorial on getting a WordPress site up and running, with example compose files. Now for anyone that may not be familiar with compose files, these are a tremendous help in defining the entire application stack. For instance, you can define a WordPress container, a database container, a shared network for the two, persistent volumes to store the data on; really any type of state that you want the stack to have. Of course you could define every one of these settings on the command line when launching the container(s), but this can get very tedious. A compose files is a great way to wrap all these settings up in one well organized configuration file. After the compose file is written, a separate tool, docker-compose, can be used to handle the setup and teardown of all objects defined in the file.
For people unfamiliar with running containers in production, the lack of persistence may seem odd. You fire up a container, it does some work, and then all changes are destroyed when the container shuts down. But this is where persistent volumes come into play. Going back to our WordPress stack, we have a WordPress web server container, and a MySQL database container. By default, the WordPress files get installed at /var/www/html when the web container starts. We can set this to be a persistent volume in the compose file. When the container is started, it mounts the persistent volume at /var/www/html, and the state of the WordPress files are restored to how they were the last time the container was running. The same thing applies to the database. These files are stored at /var/lib/mysql. These is the only directories that needs to be persistent in their respective containers. Defining this persistent volume in the compose file is all we need to do.
Below is the example compose file from Docker Hub, it uses the official WordPress and MySQL images to form a WordPress stack. As with most images, the more popular configuration options can be set using environment variables. If there’s an option that needs to be set that isn’t directly mapped to an environment variable, we can usually mount a configuration file. Lastly, note that containers can reference other containers using the names defined in the services section of the compose file. Docker accomplishes this by running an internal DNS service.
version: '3.1'
services:
wordpress:
image: wordpress
restart: always
ports:
- 8080:80
environment:
WORDPRESS_DB_HOST: db
WORDPRESS_DB_USER: exampleuser
WORDPRESS_DB_PASSWORD: examplepass
WORDPRESS_DB_NAME: exampledb
volumes:
- wordpress:/var/www/html
db:
image: mysql:5.7
restart: always
environment:
MYSQL_DATABASE: exampledb
MYSQL_USER: exampleuser
MYSQL_PASSWORD: examplepass
MYSQL_RANDOM_ROOT_PASSWORD: '1'
volumes:
- db:/var/lib/mysql
volumes:
wordpress:
db:
This compose file could be taken directly from the site, launched with docker-compose, and would result in a working, albeit insecure, WordPress site. In Part II, we’ll harden this compose file, and show how to host multiple WordPress sites from the same Docker server.
Leave a Reply
You must be logged in to post a comment.