My Docker setup for Craft CMS

I get asked this question often, so I figured I would document how I setup my Craft installations that are powered by Docker. There are three main components to my setup; a Dockerfile, Makefile, and docker-compose.yml.

Dockerfile

The Dockerfile is the main "workhorse" for my flow, it should represent the entirely of the application and should be near identical to production as possible. Some people opt for a `Dockerfile.dev` and `Dockerfile.production` but I personally find this as a cumbersome workflow; especially when your team grows someone will forget to update one and push a deployment.

I always keep my Dockerfile in "production" mode. This means I don't install xdebug or other local development tools, for those requirements I tend to place those commands in the Makefile (e.g. `make xdebug` which will execute the installation steps inside the local docker container). This flow also allows the CI/CD tools to install xdebug in the staging or test process when needed.

Apache Configuration File

This Dockerfile uses the PHP Apache image as a base, since we modified a few items (specifically the path to the document root) we need to add our own Apache configuration. You can see this in the COPY step in the Dockerfile above.

A lot of load balanced applications will also need to set the `X-Proto-Forwarded` header to properly pass HTTPS


Docker Compose

This file is used for local development, instead of running a long list of docker commands, the docker-compose file allows you to "bootstrap" your applications dependencies such as PostgreSQL and Redis.

There are a few key items of note in the docker-compose file.

  1. cached will increase performance when loading files between the host machine and docker image. Docker has a nice write up here
  2. volumes will create a volume that stores your PostgreSQL data between rebuilds. Since Docker images are made to be ephemeral, this is critical to keeping your work locally

Makefile

Instead of writing a lot of local scripts and storing in the code repository, I tend to use a Makefile. This allows me, or anyone on the team, to add repeatable commands to use among the team. There are some specifics to tagging the images and pushing to the Docker Container Registry, but the one command specific to Craft is local, using the Craft CLI to quickly install your local development environment with one command

This is not a complete example, as it is missing a few build steps like testing.

One really interesting thing to note is the Makefile syntax which is a little difficult to find `SOMETHING ?= this`. This will check for the environment variable SOMETHING and if it is not found, it will default to something. This allows your CI/CD tools to be really flexible and define variables for each build step.