Backup a docker-compose project, including all images, named and unnamed volumes, container filesystems, config, logs, and databases

#!/bin/bash
# =========================================================================== #
# Description:        Backup a docker-compose project, including all images, named and unnamed volumes, container filesystems, config, logs, and databases..
# Details:            Backup a docker-compose project, including all images, named and unnamed volumes, container filesystems, config, logs, and databases..
# edit it so you can add environment variables for containers in the docker compose file so you can specify if you want to make backups of the attached volumes or not? For Example when backing-up Plex i dont want to backup the volume that contains my music and movies.
# Made for:           Linux, docker-compose (Debian & Ubuntu).
# Requirements:       doxker-compose | ssh-keygen | ssh-copy-id root@127.0.0.1 (replace IP)
# Make executable:    chmod +x docker-compose-backup.sh
# Crontab @weekly:    0 0 * * MON /home/${staging_siteUser}/docker-compose-backup.sh 2>&1
# =========================================================================== #
#
# Variables: Source | Production
# set -o xtrace
set -o errexit
set -o errtrace
set -o nounset
set -o pipefail
IFS=$'\n'
now=$(date)
volume_exeption=("/media/Movies"  "/run/udev")
echo "[START] $now"
# Fully backup a docker-compose project, including all images, named and unnamed volumes, container filesystems, config, logs, and databases. 
project_dir="${1:-$PWD}"
if [ -f "$project_dir/docker-compose.yml" ]; then
    echo "[i] Found docker-compose config at $project_dir/docker-compose.yml"
else
    echo "[X] Could not find a docker-compose.yml file in $project_dir"
    exit 1
fi

project_name=$(basename "$project_dir")
backup_time=$(date +"%Y-%m-%d_%H-%M")
backup_dir="$project_dir/backups/$backup_time"

# Source any needed environment variables
[ -f "$project_dir/docker-compose.env" ] && source "$project_dir/docker-compose.env"
[ -f "$project_dir/.env" ] && source "$project_dir/.env"


echo "[+] Backing up $project_name project to $backup_dir"
mkdir -p "$backup_dir"

echo "    - Saving docker-compose.yml config"
cp "$project_dir/docker-compose.yml" "$backup_dir/docker-compose.yml"

# Optional: pause the containers before backing up to ensure consistency
#docker-compose pause

# Optional: run a command inside the contianer to dump your application's state/database to a stable file
echo "    - Saving application state to ./dumps"
mkdir -p "$backup_dir/dumps"
# your database/stateful service export commands to run inside docker go here, e.g.
#   docker compose exec postgres env PGPASSWORD="$POSTGRES_PASSWORD" pg_dump -U "$POSTGRES_USER" "$POSTGRES_DB" | gzip -9 > "$backup_dir/dumps/$POSTGRES_DB.sql.gz"
#   docker compose exec redis redis-cli SAVE
#   docker compose exec redis cat /data/dump.rdb | gzip -9 > "$backup_dir/dumps/redis.rdb.gz"

for service_name in $(docker-compose config --services); do
    echo "    - Pause service $service_name for backup"
    docker-compose pause $service_name

    container_id=$(docker-compose ps -q "$service_name")

    service_dir="$backup_dir/$service_name"
    echo "[*] Backing up ${project_name}__${service_name} to ./$service_name..."
    mkdir -p "$service_dir"
    


    # save config
    echo "    - Saving container config to ./$service_name/config.json"
    docker inspect "$container_id" > "$service_dir/config.json"

    # save logs
    echo "    - Saving stdout/stderr logs to ./$service_name/docker.{out,err}"
    docker logs "$container_id" > "$service_dir/docker.out" 2> "$service_dir/docker.err"

    # save data volumes
    mkdir -p "$service_dir/volumes"
    for source in $(docker inspect -f '{{range .Mounts}}{{println .Source}}{{end}}' "$container_id"); do
        if   [[ "${volume_exeption[@]}"  =~ $source    ]]
        then
            echo "    - Volume $source found in exeption list, skipped !"
        else  
            volume_dir="$service_dir/volumes$source"
            echo "    - Saving $source volume to ./$service_name/volumes$source"
            mkdir -p $(dirname "$volume_dir")
            cp -a -r "$source" "$volume_dir"
        fi
    done
    echo "    - UnPause service $service_name"
    docker-compose unpause $service_name




done

echo "[*] Compressing backup folder to $backup_dir.tar.gz"
tar -zcf "$backup_dir.tar.gz" --totals "$backup_dir" && rm -Rf "$backup_dir"

echo "[√] Finished Backing up $project_name to $backup_dir.tar.gz."
curl "https://GOTIFY_URL/message?token=YOUR_TOKEN" -F "title=Backup $project_name" -F "message=Finished Backing up $project_name to $backup_dir.tar.gz." -F "priority=5"


# Resume the containers if paused above
#docker-compose unpause
1 Like

Thank you for the docker backup.
Its my next project.

1 Like