DEV Community

Cover image for Automate backing up your Docker volumes
offen.software
offen.software

Posted on

Automate backing up your Docker volumes

Docker is an ubiquitous tool for us while building Offen, a fair and open source web analytics software. It is foundational for our development setup, but we also use it for deploying our own Offen instance to production.

One thing that we found missing was a simple and lightweight tool for taking and managing remote backups of Docker volumes. This is why we wrote our own tool called offen/docker-volume-backup which. In this post I'd like to introduce you to the tool and how to use it for automatically taking backups of the Docker volumes in your own setup.


Introduction to Docker volumes

Volumes are Docker's way of managing persistent data. As Docker containers themselves are ephemeral, volumes can be mounted into the container's filesystem, enabling you to persist data beyond the lifecycle of a container. Volumes are commonly used for storing database data or similar.

For example, this is how you would use a Docker volume to persist data for an Offen container:

docker volume create offen_data
docker run -d \
  -v offen_data:/var/opt/offen \
  offen/offen:latest
Enter fullscreen mode Exit fullscreen mode

In the running container, data stored in /var/opt/offen will be persisted in the offen_data volume and can be reused in other containers.

Using offen/docker-volume-backup

offen/docker-volume-backup is designed to run sidecared next to an application container and periodically take backups of volumes to any S3 compatible storage (i.e. AWS S3 itself or storages like MinIO or Ceph). It can run on any schedule you wish and it can also take care of rotating away old backups after a configured retention period.

If needed, it can temporarily stop and restart your running containers to ensure backup integrity.

Using alpine as the base image and using the MinIO client instead of AWS CLI for uploading files to the remote storage keeps the image small and lightweight.

Defining the sidecar container

The easiest way of managing such a setup is using docker-compose. A compose file that backs up its volumes would look something like this:

version: '3'

services:
  offen:
    image: offen/offen:latest
    volumes:
      - db:/var/opt/offen
    labels:
      - docker-volume-backup.stop-during-backup=true

    backup:
    image: offen/docker-volume-backup:v1.0.2
        # Ideally, those values should go into an `env` file or Docker secrets
        # as they contain credentials. It's easier to spell them out here
        # in the context of this tutorial though.
    environment:
            # A backup is taken each day at 2AM
            BACKUP_CRON_EXPRESSION: "0 2 * * *"
            # Backups are stored with a timestamp appended
            BACKUP_FILENAME: "offen-db-%Y-%m-%dT%H-%M-%S.tar.gz"
            # Backups older than 7 days will be pruned.
            # If this value is not given, backup will be kept forever.
            BACKUP_RETENTION_DAYS: "7"
            # Credentials for your storage backend
            AWS_ACCESS_KEY_ID: "<YOUR_ACCESS_KEY>"
            AWS_SECRET_ACCESS_KEY: "<YOUR_SECRET_KEY>"
            AWS_S3_BUCKET_NAME: "my-backups"
            # If given, backups are encrypted using GPG
            GPG_PASSPHRASE: "<SOME_KEY>"
    volumes:
            # This allows the tool to stop and restart all
            # containers labeled as docker-volume-backup.stop-during-backup
      - /var/run/docker.sock:/var/run/docker.sock:ro
            # All volumes mounted to /backup/<some-name> will be backed up
      - db:/backup/offen-db:ro

volumes:
  db:
Enter fullscreen mode Exit fullscreen mode

Of course, you can also use the image using plain Docker commands:

docker volume create offen_data
docker run -d \
  -v offen_data:/var/opt/offen \
  -l docker-volume-backup.stop-during-backup=true
  offen/offen:latest
docker run -d \
  -v offen_data:/backup/offen-db:ro \
  -v /var/run/docker.sock:/var/run/docker.sock:ro \
  --env-file backup.env \
  offen/docker-volume-backup:v1.0.2
Enter fullscreen mode Exit fullscreen mode

Manually triggering a backup

Instead of running the backups on a regular schedule, you can also execute the command in a running container yourself:

docker exec <container_ref> backup
Enter fullscreen mode Exit fullscreen mode

Restoring a volume from a backup

To recover from a backup, download and untar the backup file and copy its contents back into the docker volume using a one-off container created for just that purpose:

docker run -d \
  --name backup_restore \
  -v offen_data:/backup_restore
  alpine
docker cp <location_of_your_unpacked_backup> backup_restore:/backup_restore
docker stop backup_restore && docker rm backup_restore
Enter fullscreen mode Exit fullscreen mode

The volume is now ready to use in other containers. Alternatively, you can use a one-off volume created beforehand.

More information

Detailed documentation and the source code is available at the GitHub repository and at Docker Hub. Source code is licensed under the Mozilla Public License 2.0.

Wrapping up

Knowing you have remote backups around in case of unexpected infrastructure glitches helps moving forward with confidence and not too much worry. I hope this article demonstrated that adding them to your Docker setup is only a matter of configuring an additional container, and helps you get going with your backups so you can move forward with your product.

Written by Frederik Ring

Top comments (0)