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:

  1. Run the database in a container
  2. 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