This presentation is a quick lightning talk which I presented during the Drupal DevOps Roundtable at DrupalSouth Shorts 2021.
No doubt you know docker already
Docker around
Docker is everywhere:
- Hosting providers have been using docker containers for years
- GovCMS (OpenShift/Kubernetes running docker containers)
- CI use docker containers, e.g. Github Actions
- Local Development frameworks use docker containers
Docker on your laptop
You probably use docker every day:
- Lando - e.g. lando drush status
- GovCMS - e.g. ahoy drush
- pygmy up
- Docksal, DDEV
Do you happen to be familiar with any of these? :)
What is Docker
Let’s borrow a definition from docker.com:
Docker is an open platform for developing, shipping, and running applications. [1]
Side note: They don’t say an open source platform, but an open platform. Can you feel the difference?
Most Docker definitions don’t bother talking about virtualization. That’s because Docker does not provide virtualization itself, Docker uses or consumes OS-level virtualization.
A bit of Docker Terminology
I have seen people confused by these terms:
- Docker image
- Docker container
- Docker registry/docker hub
Let’s look at a diagram from docker documentation:
Docker container vs. docker image
To clarify the differences, we can use an application package metaphor:
Docker image - a “package” you download, e.g. firefox.
Docker container - running that “package”, possibly several instances of it. E.g. running multiple Firefox profiles.
Or, my favourite PHP class/object metaphor:
<?php
// Define docker image
//
class NginxImage inherits DockerImage
…
// Create docker containers
$nginx_ssl_proxy = new NginxImage(443, proxy_config)
$nginx_webserver = new NginxImage(80, webserver_config)
The docker image is the class here, while the docker containers are objects, instances of the class.
Docker registry
A registry is a storage and content delivery system for named (and tagged) docker images. It might store images called, for example, "php:7.3" or "nginx:latest".
To extend our application package metaphor where the firefox package was the docker image (and each running instance of the firefox package was a docker container), the (web)server hosting the firefox package (mozila.org website or Ubuntu repository) would be a Docker registry.
Docker run
This is a docker command, which creates and runs a new docker container from the docker image. If the image does not exist locally, it tries to pull it from a docker registry.
Here we run a docker container/instance of the mbentley/cowsay docker image. We can see the image is not available locally, so it gets pulled it from docker hub - the default docker registry - and run.
Think of the above as an attempt to run an instance of the cowsay binary. As it is not available on the local system, it gets automatically downloaded from the internet and executed.
Dockerfile
Not all docker images get pulled from the Docker registry. You can build your own docker image. Dockerfile contains the instructions to assemble the docker image.
A nice definition from docker.com [2]:
A Dockerfile is a text document that contains all the commands a user could call on the command line to assemble an image.
Here is the Dockerfile [3] for the mbentley/cowsay image we ran above:
FROM debian:stretch
RUN apt-get update && apt-get install -y cowsay
COPY docker.cow /usr/share/cowsay/cows/docker.cow
ENTRYPOINT ["/usr/games/cowsay","-f","docker"]
CMD ["moby","dock"]
Docker compose
This has nothing to do with your favourite PHP composer, it is a tool for defining and running multi-container Docker applications / stacks.
Say you want to run drupal and need 3 services (3 docker containers) for that - a MySQL container, a php-fpm container, and an Nginx container. Here is how this could look like described in a docker-compose.yaml:
When starting the above-defined stack (by running "docker-compose up"), the docker images for the MySQL and webserver services get pulled from a docker registry (as "mysql:5.7" and "nginx:1.21.1-alpine"), unless they have been already downloaded / are present locally. The image for the drupal (php-fpm) service gets built - its definition will be read from a file called Dockerfile.drupal. If all goes well, there are now 3 containers running.
Give me a practical use example
We use BackstopJS, a framework for automating visual regression tests. Some might install it via npm, but we don’t fear docker, so we might create a one-line script in ~/.local/bin/backstopjs containing:
docker run --rm --user 1000 --shm-size 2048m \
--add-host="www.google-analytics.com:127.0.0.1" \
--add-host="google-analytics.com:127.0.0.1" \
-v "$(pwd)":/src backstopjs/backstopjs "$@"'
Now when we execute “backstopjs”, it will run the backstopjs as a docker container - it will pull the backstopjs docker image if it is not stored locally yet.
Viola, we now have backstopJS available without installing anything.
Spring cleanup, the docker way
We have had enough fun with pulling docker images, building an image, and creating docker containers. Time to clean up! We would:
Check what containers are running - docker ps
Stop containers - docker kill <container>
Delete old containers - docker rm <container>
Delete old images - docker rmi <image>
Now let’s mention the hammer tool: docker system prune
(but check the manual first. You have been warned :)
Links
[1] https://docs.docker.com/get-started/overview/
[2] https://docs.docker.com/engine/reference/builder/
[3] https://hub.docker.com/r/mbentley/cowsay/dockerfile