Docker is great for deploying apps in a consistent manner at great speed. If you've got your configuration backed up, it's also pretty easy to replicate a docker stack on completely new hardware in a matter of minutes.

However, Docker isn't just about configuration. It's also about data. Your Docker containers normally do stuff with data. For example, your PassBolt password manager will store your precious passwords. Your Grav CMS container will store your blog entries. You really want to back up your data!

Sometimes, it's enough to back up your bind mounted directories with plain old rsync. That's what I do with Grav. It's a flat file system CMS without any risk of data corruption - even if I back up the contents of my website while the website Docker container is running. My PassBolt password manager is a whole different story. I've set it up with named volumes that Docker itself manages for storing my GPG keys, my database and anti-phising images. At the very least, I needed to back up my keys and database consistently. It seems the safest way to back up a named volume, or bind mounted volume for that sake, is the following procedure:

  1. Stop all containers that use the volume you'd like to back up
  2. Start a backup container. Mount the volume you'd like to back up. Bind mount a backup directory.
  3. Back up your data with the backup container.
  4. Stop and remove the backup container.
  5. Start your production containers again.

Of course, this is a handful to do manually, so I automated the process with a bash-script that runs every night. The general steps are the following.

First, define the relation between services, containers and volumes. I'm sure this can be done automatically with the Docker API, but I defined the dependencies manually.

# Container > Volumes to back up
declare -A CONTAINER_VOLUMES
CONTAINER_VOLUMES=(
  ["passbolt passbolt_db"]="home-server_docker_passbolt_db home-server_docker_passbolt_gpg home-server_docker_passbolt_images"
  ["nextcloud-db nextcloud-redis nextcloud-app nextcloud-web"]="home-server_docker_nextcloud-db home-server_docker_nextcloud-db-logs home-server_docker_nextcloud-redis home-server_docker_nextcloud-html"

I define an list of maps between containers that are needed to run a certain service and their volumes. In this case, the passbolt service is dependant on two containers, passbolt and passbolt_db. If I take down those two containers, the passbolt service is down, and I can safely back up the three named volumes home-server_docker_passbolt_db, home-server_docker_passbolt_gpg and home-server_docker_passbolt_images.

I iterate over the list of maps and take down the services I want to back up, one by one. First I take down passbolt with its containers, back up its volumes and restore the service, before I pass on to taking down nextcloud, back it up and restore the service, and so on.

In short, it looks like this:

for containers in "${!CONTAINER_VOLUMES[@]}";
do
  docker stop ${containers} &> /dev/null

  volumes=( ${CONTAINER_VOLUMES[${containers}]} )
  for volume in "${volumes[@]}";
  do
    docker run --rm -v ${volume}:/volume -v ${BACKUP_DIR}:/backup ubuntu bash -c "cd /volume && tar -zcf /backup/${volume}.tar ." &> /dev/null
  done
  docker start ${containers} &> /dev/null
done
  • So basically, I first stop all containers.
  • Then I start a "throwaway" ubuntu image where I mount one volume at a time and back it up to a common backup-directory with a gzip compressed tar-archive. The backup directory is bind mounted, so it stays in the host filesystem when the backup container is automatically removed upon completion of the backup.
  • When all volumes belongning to a service are backed up, the containes are started again.
  • The whole process takes a few seconds! Of course, I don't have huge amounts of data, a few hundred megabytes each backup, but that is the case for most home users anyway.

Restoring your volumes is quite easy. You do more or less the same process, except you reverse the tar-command, extracting from backup to the volume. You may want to throw in an rm -rf too if you restore form a crashed volume.

At the aweome garage github account you find the complete script with restore examples. The backup job also detects statuses and sends an email when the backup jobs are completed. Take a look and back up your critical container volumes too!

Previous Post Next Post