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:
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
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!