diff --git a/Dockerfile b/Dockerfile index 440d157..f6bbf0f 100644 --- a/Dockerfile +++ b/Dockerfile @@ -1,16 +1,15 @@ -FROM ubuntu:xenial +FROM alpine:3.6 MAINTAINER Kevin Wittek +RUN apk update +RUN apk add docker +RUN apk add py-pip +RUN apk add bash +RUN apk add gzip +RUN rm -rf /var/cache/apk/* -RUN apt update && apt -y install apt-transport-https ca-certificates curl -RUN apt-key adv \ - --keyserver hkp://ha.pool.sks-keyservers.net:80 \ - --recv-keys 58118E89F3A912897C070ADBF76221572C52609D -RUN echo "deb https://apt.dockerproject.org/repo ubuntu-xenial main" | tee /etc/apt/sources.list.d/docker.list -RUN apt update && apt -y install docker-engine -RUN curl -L https://github.com/docker/compose/releases/download/1.9.0/docker-compose-`uname -s`-`uname -m` > /usr/local/bin/docker-compose -RUN chmod +x /usr/local/bin/docker-compose +RUN pip install docker-compose COPY docker_volume_backup.sh / - -ENTRYPOINT ["/docker_volume_backup.sh", "/project/docker-compose.yml"] \ No newline at end of file +COPY docker_full_backup.sh / +ENTRYPOINT ["/docker_volume_backup.sh", "/project/docker-compose.yml", "/docker_full_backup.sh"] diff --git a/README.md b/README.md index e2744fe..18ba1e3 100644 --- a/README.md +++ b/README.md @@ -3,29 +3,69 @@ Scripts for easy backup and restore of Docker volumes ## Usage -``` +```bash ./docker_volume_backup.sh {compose_file_path} {project_name} {backup_path} {backup_or_restore} {restore_date} +# or +./docker_full_backup.sh {compose_file_path} {project_name} {backup_path} {backup_or_restore} {restore_date} ``` ## Examples +### docker_volume_backup.sh + Backup -``` +```bash ./docker_volume_backup.sh /home/kiview/Gitlab/docker-compose.yml gitlab $(pwd)/backup backup ``` Restore -``` +```bash ./docker_volume_backup.sh /home/kiview/Gitlab/docker-compose.yml gitlab $(pwd)/backup restore 2016-10-19 ``` + +### docker_full_backup.sh + +```bash +MODE=backup # or restore + +path=/opt/mydocker/project1/docker-compose.yml +project=project1 +BACKUP_DIR=/tmp/mybackups +DATE=xxxx-xx-xx + +#export EXCLUDE_CONTAINER=1 +#export EXCLUDE_VOLUMES=1 + +./docker_full_backup.sh $path $project $BACKUP_DIR $MODE $DATE +``` + ## Docker Container Usage -After building your container, you can use it like this: + +After building your container, + +```bash +docker build -t docker_volume_backup . +# or +./build.sh ``` -docker run -v "/home/kiview/Gitlab/:/project" \ - -v "$(pwd)/backup:/backup" \ - -v /var/run/docker.sock:/var/run/docker.sock \ - docker_volume_backup:latest Gitlab /backup backup + +you can use it like this: + +```bash +PROJECT_DIR # path to directory that contains the docker files, e.g. docker-compose.yml, Dockerfile, ... +PROJECT_NAME # Name of the docker container, default is the directory name where docker-compose.yml is stored +BACKUP_DIR # directory where the tar-files are stored / readed +MODE # backup or restore +DATE # if MODE=restore than the date who should restore + +# $MODE=backup --> $DATE is ignored +docker run \ + -v "$PROJECT_DIR:/project" \ + -v "$BACKUP_DIR:/backup" \ + -v /var/run/docker.sock:/var/run/docker.sock \ + docker_volume_backup:latest $PROJECT_NAME /backup $MODE $DATE ``` -Note you don't need to provide the path to docker-compose.yml. It is assumed to be mounted under /project/docker-compose.yml. \ No newline at end of file + +Note you don't need to provide the path to docker-compose.yml. It is assumed to be mounted under /project/docker-compose.yml. diff --git a/build.sh b/build.sh new file mode 100755 index 0000000..183a3eb --- /dev/null +++ b/build.sh @@ -0,0 +1,17 @@ +#!/bin/bash + +# get location of script +SOURCE="${BASH_SOURCE[0]}" +while [ -h "$SOURCE" ]; do # resolve $SOURCE until the file is no longer a symlink + DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + SOURCE="$(readlink "$SOURCE")" + [[ $SOURCE != /* ]] && SOURCE="$DIR/$SOURCE" # if $SOURCE was a relative symlink, we need to resolve it relative to the path where the symlink file was located +done +DIR="$( cd -P "$( dirname "$SOURCE" )" && pwd )" + +# +if [ -z "$1" ] ; then + docker build -t docker_volume_backup "$DIR" +else + docker build -t docker_volume_backup "$1" +fi diff --git a/docker_full_backup.sh b/docker_full_backup.sh new file mode 100755 index 0000000..d25e0fd --- /dev/null +++ b/docker_full_backup.sh @@ -0,0 +1,121 @@ +#!/bin/bash + +alpine=alpine:3.6 +cdir=containers +vdir=volumes +compose_file_path=$1 +project_name=${2,,} +backup_path=$3 +backup_or_restore=${4:-backup} +date_suffix=${5:-$(date -I)} + +DO_CONTAINER=${EXCLUDE_CONTAINER:-0} +DO_VOLUMES=${EXCLUDE_VOLUMES:-0} + +set -e + +function backup_volume { + volume_name=$1 + backup_destination=$2 + + docker run --rm -v $volume_name:/data -v $backup_destination:/backup $alpine tar -zcvf /backup/$vdir/$volume_name-$date_suffix.tar.gz /data +} + +function backup_container { + container_id=$1 + backup_destination=$2 + fname="$backup_destination/$cdir/$container_id-$date_suffix.tar.gz" + + docker export $container_id | gzip > $fname +} + +function restore_volume { + volume_name=$1 + backup_destination=$2 + date=$date_suffix + + docker run --rm -v $volume_name:/data $alpine find /data -mindepth 1 -delete + docker run --rm -v $volume_name:/data -v $backup_destination:/backup $alpine tar -xvf /backup/$vdir/$volume_name-$date.tar.gz -C . +} + +function restore_container { + container_id=$1 + backup_destination=$2 + date=$date_suffix + fname="$backup_destination/$cdir/$container_id-$date_suffix.tar.gz" + + ["$(docker ps -a | grep $container_id)"] && docker rm -f $container_id + gunzip -c $fname | docker load +} + + +function main { + echo "Docker backup script for project: $project_name" + echo " mode: $backup_or_restore" + + if [ "$backup_or_restore" == "backup" ] ; then + mkdir -p $backup_path/$cdir + mkdir -p $backup_path/$vdir + fi + + echo " stopping running containers" + docker-compose -f $compose_file_path -p $project_name stop + + if [ $DO_CONTAINER != 0 ] ; then + echo " container are excluded" + else + echo " enter container images" + #declare -a containers=() + #readarray -t containers < <(docker container ls --all -f name=$project_name | awk '{if (NR > 1) print $1}') + #for c in "${containers[@]}" + #do + #docker ps --all --quiet -f name=$project_name | while read -sr c ; do + docker-compose -f $compose_file_path -p $project_name ps -q | while read -sr c ; do + if [ "$backup_or_restore" == "backup" ] + then + echo " perform container backup: $c" + backup_container $c $backup_path + fi + + if [ "$backup_or_restore" == "restore" ] + then + echo " restore container from backup: $c" + restore_container $c $backup_path + fi + done + fi + + if [ $DO_VOLUMES != 0 ] ; then + echo " volumes are excluded" + else + echo " mounting volumes and performing backup/restore..." + #declare -a volumes=() + #readarray -t volumes < <(docker volume ls -f name=$project_name | awk '{if (NR > 1) print $2}') + #for v in "${volumes[@]}" ; do + docker-compose -f $compose_file_path -p $project_name config --volumes | while read -sr line ; do + # TODO: if it possible to get volumes ID's, put it in here! + v="${project_name}_$line" + if [ "$backup_or_restore" == "backup" ] + then + echo " perform volume backup: $v" + backup_volume $v $backup_path + fi + + if [ "$backup_or_restore" == "restore" ] + then + echo " restore volume from backup: $v" + restore_volume $v $backup_path + fi + done + fi + + echo " restarting containers" + docker-compose -f $compose_file_path -p $project_name start + + # write date_id to file + echo "$date_suffix $project_name" >> "$backup_path/stored-backups.ids" + + echo "finished" +} + +main diff --git a/docker_volume_backup.sh b/docker_volume_backup.sh index 91940f2..eb78bec 100755 --- a/docker_volume_backup.sh +++ b/docker_volume_backup.sh @@ -1,5 +1,6 @@ #!/bin/bash +alpine=alpine:3.6 compose_file_path=$1 project_name=${2,,} backup_path=$3 @@ -13,7 +14,7 @@ function backup_volume { backup_destination=$2 date_suffix=$(date -I) - docker run --rm -v $volume_name:/data -v $backup_destination:/backup ubuntu tar -zcvf /backup/$volume_name-$date_suffix.tar /data + docker run --rm -v $volume_name:/data -v $backup_destination:/backup $alpine tar -zcvf /backup/$volume_name-$date_suffix.tar /data } function restore_volume { @@ -21,8 +22,8 @@ function restore_volume { backup_destination=$2 date=$3 - docker run --rm -v $volume_name:/data ubuntu find /data -mindepth 1 -delete - docker run --rm -v $volume_name:/data -v $backup_destination:/backup ubuntu tar -xvf /backup/$volume_name-$date.tar -C . + docker run --rm -v $volume_name:/data $alpine find /data -mindepth 1 -delete + docker run --rm -v $volume_name:/data -v $backup_destination:/backup $alpine tar -xvf /backup/$volume_name-$date.tar -C . } function main { @@ -30,9 +31,12 @@ function main { docker-compose -f $compose_file_path -p $project_name stop echo "Mounting volumes and performing backup/restore..." - volumes=($(docker volume ls -f name=$project_name | awk '{if (NR > 1) print $2}')) - for v in "${volumes[@]}" - do + #declare -a volumes=() + #readarray -t volumes < <(docker volume ls -f name=$project_name | awk '{if (NR > 1) print $2}') + #for v in "${volumes[@]}" ; do + docker-compose -f $compose_file_path -p $project_name config --volumes | while read -sr line ; do + # TODO: if it possible to get volumes ID's, put it in here! + v="${project_name}_$line" if [ "$backup_or_restore" == "backup" ] then echo "Perform backup"