Docker backup

All those containers. All that setup. All that data. I'd better keep it safe!

Portainer makes a nice web interface, & it does have the option to manually download a backup (settings, then scroll right to the bottom). That's not as good as scripting the whole thing to happen automatically.
It happens that portainer actually saves its stacks as docker-compose.yml files within the "/data" directory - which I have mapped to a directory that I can read (instead of as a data container).

Step 1 - Backup location

Not a lot of point in backing things up if they go in the same place as the original files (we're not just trying to idiot proof things here, but also to deal with a possible disk failure). So, I'll need a backup folder as a "temporary" location (& a plan to keep that backed up with a separate on site & off site location so that I can have multiple backups).
For now let's say that I'll use a folder "/backup" on a disk at "/media/MyDisk".

Step 2 - Back up the docker-compose files

I could just copy the portainer data directory, but it would be nice to make things smaller if possible (we don't need quick access after all). The files aren't in use in a fashion that means that they might be changing, so we can just go ahead & copy them (unlike a live database for example)
tar is the typical command for doing this... (replace the bits inside the <> with the appropriate actual values)

tar -cvpjf <path & name for backup file>.tar.bz2 <portainer data directory>
/compose

	c - create a new backup archive.

	v - verbose mode, tar will print what it's doing to the screen.

	p - preserves the permissions of the files put in the archive.

	j - compress the backup file with 'Bzip2' to make it smaller.

	f <filename> - specifies where to store the backup

You may need 'sudo su' first

You can test that the files are in there by listing them (doesn't check integrity!)

tar -jtvf <path & name for backup file>.tar.bz2

Step 3 - data

In theory we now have a copy of the compose files needed to recreate the docker setup that portainer knows about. However, there will be a lot of bind mounts & configurations that have been set up over time.
I keep things tidy by using a single directory for all of the container specific things (like databases), but keep the purely data things (like video or audio files) in more generic locations.
We can extract the volume assignments from the docker-compose.yml files by a bit of scripting magic:

sed -n "/volumes:/,/:$/p"  <path to>/docker-compose.yml | grep ' \- ' | grep -oP '(?<=\/).*?(?=\:)'

breaking this down:
The sed command extracts the lines from "volumes:" to the next line that ends in a ":" - inclusive. for the docker-compose file that we specified.
The first grep command then only matches lines that have a " - ", which should be our volume assignments.
The second grep command then pulls out the bind mount for the volume (the text between the "/" & the ":")
The output is then send to the console, but we can use it in a script too.

Questions: What about the places where there are docker volumes? Or if the mapping is to a directory for audio/video/etc?
Well, I'm tidy about these things & use bind mounts inside the directory that I use for docker things, so anything not there is either data or system stuff or an actual docker volume (which needs a different backup plan). So, I could use "' | grep -oP '(?<=\/<my docker directory>).*?(?=:)' to pull the specific lines out (minus the path that I use for docker things), then add it back in for the script later. Don't forget to escape ("\") each "/" in the path though!