Running Craft CMS in a Docker container on Microsoft Azure
For the deployment of the TIQ marketing website 2020 redesign we decided to Dockerize the application and run in on Azure. I couldn’t find a lot about this setup on the Internet, so I’ve put in the time to figure it out. Hopefully it can save you some time.
Docker Compose on Azure
Since Docker Compose is in “Public Preview Azure, it’s a bit more difficult to assert whether you’ve made a mistake or ran into a limitation of the Preview. You can read more about the limitation of the Preview before going down this road. Pay special attention to the fine print on this page:
“Any other options not explicitly called out are ignored in Public Preview”
Consider yourself warned.
Although Microsoft starts with the S1 App Service Plan for Wordpress, the memory consumption was a bit too high for my taste (usually 40-50% on an inactive state). I can recommend using the P1V2 instance for Craft CMS, which offers twice the RAM in the same price range.
Building a good image
I can recommend having a look at the urbantrout/craftcms image. What I like about it, is the clean separation of services. I’ve learned a lot from this Docker image, but finally decided to build my own due to custom needs.
Note: the sample Docker Compose configuration will not work out of the box on Azure, because it uses the volumes_from option which is unsupported in the Azure Public Preview. See “Issue #2” below for a workaround.
Database options
For running a database, there are two options:
- Run the database in a container
- Use a separate SQL database to connect with
It’s usually not recommended to run a database in a container for production environments.
A solution for automated backups
However you set up your database, it’s always a good plan to have a backup. I also wanted to keep a backup of all the assets that get uploaded using the Control Panel.
Azure allows you to mount a File Share on a Docker container (Settings > Configuration > Path Mappings).
For example, if your volume is named craft_backups:
# docker-compose.yml
# ...
volumes:
- craft_backups:/backups
environment:
- BACKUP_INTERVAL: 21600 # in seconds
# ...
Now the File Share contents are available under the /backups path, you can use them for making backups. After spending some time trying out both, I’ve settled with some simple backup/restore shell scripts.
Call these scripts when starting your container:
# /scripts/startup.sh
restore() {
/scripts/restore.sh
}
backup() {
while true
do
sleep $BACKUP_INTERVAL
/scripts/backup.sh &
done
}
The backup script, called every xx seconds (as set in the BACKUP_INTERVAL environment variable):
# /scripts/backup.sh
#!/bin/bash
webroot='/var/www/html'
# Periodic backup of database + assets to /backups
$webroot/craft backup/db \
&& cp -r $webroot/storage/backups/*.sql /backups/database \
&& cp -r $webroot/web/YOUR_ASSETS /backups/assets
The restore script, called once during the container startup:
# /scripts/restore.sh
#!/bin/bash
set -x -e
webroot='/var/www/html'
backup_dir="/var/www/html/storage/backups"
backup_file=$(ls /backups/database -t | grep ^YOUR_CRAFT_SITE_NAME_.*\.sql$ | head -n 1)
if [ ! -d $backup_dir ]; then
mkdir -p $backup_dir
fi
cp /backups/database/$backup_file $backup_dir/$backup_file
cp -r /backups/assets/YOUR_ASSETS $webroot/web
Issue #1: the Azure web interface
Uploading and updating the Docker Compose file from the Azure interface isn’t the best experience. Sometimes it’s slow or unresponsive. Increase your productivity by using the Azure CLI. I’ve created a shell script to make it easier to run frequently used Azure commands during development:
# azure.sh
#!/usr/bin/env bash
set -x -e
case $1 in
update)
az webapp config container set --resource-group RESOURCE_GROUP_NAME --name RESOURCE_NAME --multicontainer-config-type compose --multicontainer-config-file docker-compose.yml
;;
tail)
az webapp log tail --resource-group RESOURCE_GROUP_NAME --name RESOURCE_NAME
;;
start)
az webapp start --resource-group RESOURCE_GROUP_NAME --name RESOURCE_NAME
;;
stop)
az webapp stop --resource-group RESOURCE_GROUP_NAME --name RESOURCE_NAME
;;
*)
echo "Please provide a command"
;;
esac
Issue #2: (lack of) volumes_from support
The Nginx container needs access to the static assets that reside in the webroot of the Craft CMS container. Instead of using the volumes_from option, this can also be achieved with a shared volume between the containers:
# docker-compose.yml
services:
nginx:
depends_on:
- craft
volumes:
- web:/var/www/html/web
...
craft:
volumes:
- web:/var/www/html/web
...
volumes:
web:
Hopefully this will speed up your time getting started with Docker Compose on Azure!
Sources
- Image courtesy: 24 Security Icons by Erdem Kirmitci