-
-
Save faghani/a555c63839d5c88703c517f3feb54b79 to your computer and use it in GitHub Desktop.
Backup docker volumes
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
#!/usr/bin/env python3 | |
"""Backs up and restores data-only volumes to/from host backup directory using | |
rsync. Only backup named volumes, which is arbitrarily set to ones having a name | |
length < 40 characters. | |
1. Create a Docker image containing rsync (named rsync) | |
https://github.com/firecat53/dockerfiles/tree/master/rsync | |
``docker build -t rsync .`` | |
2. Run ./docker_backup.py -h | |
""" | |
import argparse | |
import platform | |
import docker | |
BACKUP_DIR = "/var/backups/{}/docker".format(platform.node()) | |
def parse_arguments(): | |
"""Parse command line options. | |
Returns: args | |
""" | |
arg_parse = argparse.ArgumentParser(description="Backup or restore named Docker volumes") | |
arg_parse.add_argument('mode', choices=['backup', 'restore'], | |
help="Choose backup or restore") | |
arg_parse.add_argument('volumes', nargs='*', default=[], | |
help="Zero or more volumes to backup or restore. " | |
"Default is all available (< 40 char name) for " | |
"backup and none for restore") | |
arg_parse.add_argument('--force', '-f', action='store_true', default=False, | |
help="Overwrite existing volume contents on " | |
"restore.") | |
arg_parse.add_argument('--exclude', nargs='*', default=[], | |
help="List of directories to exclude from backup") | |
return arg_parse.parse_args() | |
def run(): | |
"""Main script entrypoint | |
""" | |
args = parse_arguments() | |
client = docker.DockerClient() | |
try: | |
client.images.get("rsync") | |
except docker.errors.ImageNotFound: | |
print("Rsync image not found. Build it and try again") | |
return | |
vols = client.volumes.list() | |
vols = [i for i in vols if len(i.name) < 40] | |
if args.exclude: | |
exclude = '--exclude "' + '" --exclude "'.join(args.exclude) + '"' | |
else: | |
exclude = "" | |
if args.mode == 'backup': | |
vols = [i for i in vols if i.name in args.volumes] \ | |
if args.volumes else vols | |
cmd = "rsync -aAXq --delete {} /mnt/ /backup/".format(exclude) | |
if args.mode == 'restore': | |
vols = [i for i in vols if i.name in args.volumes] \ | |
if args.volumes else [] | |
cmd = "rsync -aAXq --delete {} /backup/ /mnt/".format(exclude) | |
if not vols: | |
print("No containers backed up or restored") | |
return | |
for vol in vols: | |
try: | |
client.volumes.get(vol.name) | |
except docker.errors.NotFound: | |
print("{} does not exist.".format(vol.name)) | |
continue | |
vol_back = {"{}/{}".format(BACKUP_DIR, vol.name): | |
{'bind': '/backup', 'mode': 'rw'}, | |
vol.name: {'bind': '/mnt', 'mode': 'rw'}} | |
client.containers.run(image='rsync', | |
remove=True, | |
command=cmd, | |
volumes=vol_back) | |
if __name__ == '__main__': | |
run() |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment