#!/bin/sh # Purpose {{{ ## Backup data of a Docker container. ## To do that, the script will : ## Try to stop the corresponding systemd unit (or docker if no related service is found) ## Make a archive of the container's data to a backup path ## Restart the container service (or docker.service) ## Clean old backup # }}} # How-to use {{{ ## First argument should be the absolut path to the container's data. ## The data directory and the container should have the same name. # }}} # Vars {{{ DEBUG=0 ## Nomber of backup to keep keep_backup="3" ## Manage arguments {{{ ## Expect at least 1 argument and 2 maximum case $# in 1 ) ## Absolut path to the container data ct_data_path="${1}" ## Absolut path to store the archives. ## A sub-directory will be created for the container docker_backup_path="/mnt/backup/docker" ;; 2 ) ct_data_path="${1}" docker_backup_path="${2}" ;; * ) cat << HELP container.backup -- Backup data of a given Docker container. EXAMPLE : - Backup data of FIRST_CT container require the absolut path to data container.backup /srv/docker/FIRST_CT - Select the directory to store the backup of hello_world container container.backup /srv/docker/hello_world /media/usb/docker.backup HELP exit 1 ;; esac ct_name=$(basename -- "${ct_data_path}") docker_data_path=$(dirname -- "${ct_data_path}") ct_backup_path="${docker_backup_path}/${ct_name}" ## }}} # }}} # Tests {{{ ## Ensure container data directory exists {{{ if [ ! -d "${ct_data_path}" ]; then printf '\e[0;31m%-6s\e[m\n' "Docker data directory doesn't seems available : ${ct_data_path} ." exit 1 else [ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Test arg — Path to Docker data : ${ct_data_path} ." [ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Test arg — Container name to backup : ${ct_name} ." fi ## }}} ## Ensure backup directory exists {{{ if [ ! -d "${docker_backup_path}" ]; then printf '\e[0;31m%-6s\e[m\n' "Backup directory doesn't seems available : ${docker_backup_path} ." exit 1 else [ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Test arg — Path to store the backup : ${docker_backup_path} ." fi ## }}} # }}} # Get container service name {{{ ct_service_name=$(find /etc/systemd -type f -iname "*${ct_name}*.service" -printf "%f\n") ## If no specific systemd service exists, the docker.service will be used if [ "${ct_service_name}" = "" ]; then ct_service_name="docker.service" [ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Service name — No specific service found for ${ct_name} container, the ${ct_service_name} will be stopped." else [ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Service name — Service name of ${ct_name} container to stop : ${ct_service_name} ." fi # }}} # Stop the container service {{{ systemctl stop "${ct_service_name}" [ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Service management — Service ${ct_service_name} was stopped." # }}} # Backup container data {{{ ## Create the directory to store archive if doesn't already exist if [ ! -d "${ct_backup_path}" ]; then mkdir -p -- "${ct_backup_path}" [ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Backup data — ${ct_backup_path} was created." fi ## Backup container data tar czf "${ct_backup_path}/${ct_name}-backup.$(date '+%Y%m%d-%H%M').tar.gz" --directory "${docker_data_path}" "${ct_name}" [ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Backup data — Data of ${ct_name} container were successfully backuped ${ct_backup_path}/${ct_name}-backup.$(date '+%Y%m%d-%H%M').tar.gz" # }}} # Restart the container service {{{ systemctl start "${ct_service_name}" [ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Service management — Service ${ct_service_name} was started." # }}} # Remove old backups {{{ cd -- "${ct_backup_path}" || exit 1 [ "${DEBUG}" -eq "0" ] && printf '\e[1;35m%-6s\e[m\n' "DEBUG : Cleaning — Keep only the ${keep_backup} newest backups." find . -type f | sort | head -n -"${keep_backup}" | xargs -d '\n' rm -f -- cd -- - > /dev/null || exit 1 # }}} exit 0