Docker のvolumeのbackupとrestore

2022/04/10に公開

概要

MySQLのデータベースをDockerのvolumeにマウントしているときのバックアップするためのshell scriptです。

考え方は以下の通りです。

  • バックアップ用shell script create_snapshot.sh
    • MySQLのデータベースのDockerのvolumeと別途バックアップ用のvolumeを作業用のubuntuにマウントして、バックアップ用のvolumetarでコピーします。
sh create_snapshot.sh -t docker_volume_backup_shell_script_db_data -b bck_volume
  • リストア用shell script restore_snapshot.sh
    • MySQLのデータベースのDockerのvolumeと別途バックアップ用のvolumeを作業用のubuntuにマウントして、tarファイルをMySQLのデータベースのDockerのvolumeに解凍します。
sh restore_snapshot.sh -t docker_volume_backup_shell_script_db_data -b bck_volume

試し用のリポジトリ

MySQLを例にして、ためせるリポジトリを作りました。

README上から順番に打ち込んで、バックアップとリストアができることを体験ください。

https://github.com/junara/docker_volume_backup_shell_script

シェルスクリプト

バックアップ用shell script

while getopts b:t:i OPTION; do
  case $OPTION in
  b) bck_volume=$OPTARG ;;
  t) tgt_volume=$OPTARG ;;
  i) bck_docker_image=$OPTARG ;;
  esac
done

if [ -z "$bck_volume" ]; then
  echo '-b must be needed. Please write back up Docker volume name.'
  exit 1
fi

if [ -z "$tgt_volume" ]; then
  echo '-t must be needed. Please write back up target Docker volume name.'
  exit 1
fi

if [ -z "$work_docker_image" ]; then
  work_docker_image="ubuntu:latest"
fi

bck_directory="bck"
tgt_directory="tgt"
bck_tar_file="bck.tar"

echo '===START==='
echo '===START RESET BACKUP VOLUME===' &&
  docker volume rm -f $bck_volume &&
  docker volume create $bck_volume &&
  echo '===END RESET BACKUP VOLUME===' &&
  echo '===START BACKUP===' &&
  docker run --rm -v $bck_volume:/$bck_directory -v $tgt_volume:/$tgt_directory $work_docker_image bash -c "cd / && tar cvf $bck_directory/$bck_tar_file $tgt_directory" &&
  echo "===Docker volume [$tgt_volume] is copied to [$bck_tar_file] file in Docker volume [$bck_volume] ===" &&
  echo '===END BACKUP===' &&
  echo '===FINISH==='

while getopts b:t:i OPTION; do
  case $OPTION in
  b) bck_volume=$OPTARG ;;
  t) tgt_volume=$OPTARG ;;
  i) bck_docker_image=$OPTARG ;;
  esac
done

ここでoption引数をとります。 -b, -t, -iを引数に取ることができます。

  • -bbck_volume変数。これは、バックアップを保存するDocker volume名です。
  • -ttgt_volume変数。これは、バックアップ元のDocker volume名です。
  • -ibck_docker_image変数。これは、volumeをマウントしてtarコマンドを実行するdocker imageです。defaultは ubuntu:latestです。tarが実行できればどんなimageでもいいです。
if [ -z "$bckup_volume" ]; then
  bck_volume="bck_volume"
fi

-b-tは、必ず指定して欲しいので、指定されていない場合は、exit 1としてエラーとしています。

  docker volume rm -f $bck_volume &&
  docker volume create $bck_volume &&

バックアップ用のボリュームを一旦削除して、作り直します。

docker run --rm -v $bck_volume:/$bck_directory -v $tgt_volume:/$tgt_directory $work_docker_image bash -c "cd / && tar cvf $bck_directory/$bck_tar_file $tgt_directory"

バックアップ元とバックアップ先の両方のvolumeをマウントし、 tar cvf バックアップ先 バックアップ元でtarファイルにバックアップします。

リストア用shell script

while getopts b:t:i OPTION; do
  case $OPTION in
  b) bck_volume=$OPTARG ;;
  t) tgt_volume=$OPTARG ;;
  i) work_docker_image=$OPTARG ;;
  esac
done

if [ -z "$bck_volume" ]; then
  echo '-b must be needed. Please write back up Docker volume name.'
  exit 1
fi

if [ -z "$tgt_volume" ]; then
  echo '-t must be needed. Please write back up target Docker volume name.'
  exit 1
fi

if [ -z "$work_docker_image" ]; then
  work_docker_image="ubuntu:latest"
fi

bck_directory="bck"
tgt_directory="tgt"
bck_tar_file="bck.tar"

echo '===START==='
echo '===START RESET TARGET VOLUME===' &&
  echo "===Delete all data in [$tgt_volume] Docker volume." &&
  docker run --rm -v $tgt_volume:/$tgt_directory $work_docker_image bash -c "rm -rf $tgt_directory/*" &&
  echo '===END RESET TARGET VOLUME===' &&
  echo '===START COPY BACKUP VOLUME TO TARGET DIRECTORY===' &&
  echo "=== Restore data from [$bck_tar_file] in [$bck_volume] Docker volume to [$tgt_volume] Docker volume." &&
  docker run --rm -v $bck_volume:/$bck_directory -v $tgt_volume:/$tgt_directory $work_docker_image bash -c "cd /$tgt_directory && tar -xvf /$bck_directory/$bck_tar_file --strip-components=1" &&
  echo '===END COPY BACKUP VOLUME TO TARGET DIRECTORY==='
echo '===FINISH==='

引数の考え方は、バックアップ用shell scriptと同じです。

docker run --rm -v $tgt_volume:/$tgt_directory $work_docker_image bash -c "rm -rf $tgt_directory/*"

一旦バックアップ元のvolumeをrm -rfで削除します。

docker run --rm -v $bck_volume:/$bck_directory -v $tgt_volume:/$tgt_directory $work_docker_image bash -c "cd /$tgt_directory && tar -xvf /$bck_directory/$bck_tar_file --strip-components=1"

基本は、バックアップ用shell scriptと同じです。 バックアップ元とバックアップ先のvolumeを両方マウントしtar xvfでリストアします。

特記すべきは --strip=1です。これがないと、tarでまとめたフォルダ名が作られてしまいます。--strip=1をつけることにより、階層を一つ飛ばすことができます。
結果的に最上位のフォルダが作られません。

https://linuxjm.osdn.jp/html/GNU_tar/man1/tar.1.html

--strip-components=NUMBER
抽出時にファイル名の先頭から NUMBER 個の構成要素 (訳注: 要するに、NUMBER 個のディレクトリ部分) を取り去る

Discussion