Ubuntu

Dockerのvolumeをバックアップ

Dockerのvolumeのバックアップをするには、バックアップ用のコンテナでボリュームをマウントし、ファイルを取り出す操作が必要。
ホームラボの話なので、サービスが一時的に停止しても良いという前提で、雑なバックアップの手順を整理しておくことにした。



広告


いま、ホームラボの中心となるサーバーで稼働しているのは、Samba ad dc、Kopano、Giteaの3システム。
それぞれのシステムごとにdocker-compose.ymlがあって、5つのコンテナが起動している。
コンテナを停止させずにバックアップするのであれば、違ったアプローチをしていくことになるが、コンテナを停止させられる環境なので、ボリューム丸ごとコピー方式とした。

コンテナのバックアップそのものはワンライナーでいけるけれど、

  • 丸ごとコピーとはいえ、Samba ad dcでは拡張属性を取得しておく必要がある。
  • 操作ミスでボリュームが消えてしまうのを防ぐため、3システムのボリュームを掴むコンテナを作っておきたい。

という理由で、コンテナを作り込むことにしている。

ワンライナーのご参考、ここではlsしてみている。
バックアップ用のボリュームをもう1つ用意して、そこにファイルをコピーするのが常套手段のようだ。

$ sudo docker run --rm -v samba_private:/mnt alpine:latest ls -la /mnt
total 10236
drwxr-xr-x    7 root     root          4096 Aug 21 04:36 .
drwxr-xr-x    1 root     root          4096 Aug 25 14:05 ..
-rw-------    1 root     root          2326 Aug 20 10:03 dns_update_cache
-rw-r--r--    1 root     root          3663 Aug 20 10:03 dns_update_list
…

ファイル構成

Samba ad dcでHOGEDOMAINというドメインを管理しているので、hd-backupというディレクトリを作り、そこにファイルを作っていく。
リポジトリはこちら

~/hd-backup/
   ├ baseimage/
   │  └ Dockerfile
   ├ mkbaseimage.sh*
   ├ Dockerfile
   ├ docker-compose.yml
   ├ entrypoint.sh*
   ├ backup.sh*
   └ do-backup*

*実行権限を付ける

ベースとなるイメージの作成

バックアップにはAlpine Linuxを使わせていただくことにした。
サイズが小さくてありがたい。

Sambaは拡張属性のバックアップも取りたいのでsamba-toolが動かせるように、samba-dcパッケージをインストールする。
https://pkgs.alpinelinux.org/packages

このsamba-dcパッケージをインストールするのに、まぁまぁな量のダウンロードをするので、スクリプト差し替えを気軽に実行できるように、ベースイメージを作成することにした。

~/hd-backup/baseimage/Dockerfile

FROM alpine:latest
RUN apk add samba-dc tzdata

ベースイメージを構築するためのスクリプトを作成する。

~/hd-backup/mkbaseimage.sh

#!/bin/bash
cd $(dirname ${0})
sudo docker build -t custom/backup:0.0.1 -f $PWD/baseimage/Dockerfile .

スクリプトに実行権を付けて、実行する。

$ cd ~/hd-backup
$ chmod +x mkbaseimage.sh
$ ./mkbaseimage.sh

$ sudo docker image ls
REPOSITORY      TAG            IMAGE ID       CREATED          SIZE
custom/backup   0.0.1          a65abe7e79f3   41 minutes ago   153MB
…

Dockerfile

ベースイメージにスクリプトを2つ登録。

  • コンテナが起動したら動作するスクリプト。
  • バックアップスクリプト。

~/hd-backup/Dockerfile

FROM custom/backup:0.0.1
ADD entrypoint.sh /
Add backup.sh /
ENTRYPOINT ["/entrypoint.sh"]

docker-compose.yml

Dockerfileでコンテナを作り、バックアップ対象となるボリュームをマウントするdocker-compose.ymlを作成する。

コンテナでvolumes指定をしているが、コンテナに存在しないディレクトリは作られるし、存在するディレクトリは置き換えられたような状態になる。
volumesの定義では、名前を明確に指定し、それが外部のボリュームであることを指定している。

バックアップ先は、ホストの /var/backups とした。
バックアップファイル名にホスト名を使用するので、hostnameを適宜設定。

拡張属性をバックアップするためNTACLを作成するが、samba-toolコマンドが/etc/samba/smb.confを読み込んで動作するようなので、マウントポイントはdocker-compose.ymlで正確に合わせた。

一方、KopanoとGiteaは単純にファイルをバックアップするだけなので、/tmp配下にマウントポイントを作成している。

~/hd-backup/docker-compose.yml

version: "3.9"
services:

  backup:
    build: ./
    image: custom/backup:1.0.0
    container_name: backup
    restart: "no"
    environment:
      TZ: Asia/Tokyo
      DO_BACKUP: "true"
    hostname: hogedomain
    volumes:
      # Samba ad dc
      - samba_etc:/etc/samba
      - samba_lib:/var/lib/samba
      - bind_etc:/etc/bind
      - bind_lib:/var/lib/bind
      - lam:/var/lib/ldap-account-manager
      # Kopano
      - kopano:/tmp/kopano/var/lib/kopano/attachments
      - kopano_db:/tmp/kopano/var/lib/mysql
      # Gitea
      - gitea:/tmp/gitea/data
      - /home/git/.ssh:/tmp/gitea/data/git/.ssh
      - gitea_db:/tmp/gitea/var/lib/mysql
      # Backup directory
      - /var/backups:/mnt/backups

volumes:
  bind_etc:
    name: samba_bind_etc
    external: true
  bind_lib:
    name: samba_bind_lib
    external: true
  lam:
    name: samba_lam
    external: true
  samba_etc:
    name: samba_samba_etc
    external: true
  samba_lib:
    name: samba_samba_lib
    external: true
  kopano:
    name: kopano_kopano
    external: true
  kopano_db:
    name: kopano_kopano_db
    external: true
  gitea:
    name: gitea_gitea
    external: true
  gitea_db:
    name: gitea_mysql
    external: true

entrypoint.sh

コンテナが起動すると呼び出され、バックアップスクリプトを実行して終了するだけのスクリプト。
リストアの場合は、起動後になかでゆっくりと操作をしたいと思ったので、DO_BACKUP変数にtrueが与えられなかった場合は、無限ループに入るようにした。

~/hd-backup/entrypoint.sh

#!/bin/ash

echo "Start container with parameter : $@"

trap sig_term SIGTERM

sig_term() {
    echo "CATCH SIGTERM"
    wait
    exit 0
}

# Execute paramater.
exec "$@"

if [[ $DO_BACKUP == "true" ]]; then
    exec /backup.sh
    exit 0
fi

# Infinity roop.
while : ; do sleep 1 ; done

実行権を付けておく。

$ chmod +x entrypoint.sh

backup.sh

Samba ad dcのバックアップは、本来ならばsamba-toolコマンドを使うべき。
今回は、ある日ある時に戻れれば良い、という割り切りバックアップ。

tarボールの連結については、ここで教えてくれたやり方で実施。
連結前と連結後をそれぞれ展開し、diffを取ってみたところ、差分はなかった。
Stack Overflow / BusyBox tar: append workaround given limited disk space?

実行すると、Sambaのディレクトリにあるソケットを圧縮しようとしてワーニングが表示される。
Alpineのtarには、ワーニングの出力を止めるオプションがなかったので、そのままにしている。

~/hd-backup/backup.sh

#!/bin/ash

# Create backup files.
TMP_TARGET=/mnt/backups/backup-$(hostname)-$(date +'%Y-%m-%d-%H-%M-%S').tar
echo $TMP_TARGET

#
# Samba
#
echo "Samba"

# make NTACL file.
cd /var/lib/samba
find ./sysvol -exec ash -c 'TMP=$(samba-tool ntacl get "{}" --as-sddl); echo "samba-tool ntacl set \"$TMP\" \"{}\""' \; > NTACL

# make tarball.
cd /
tar -cvf $TMP_TARGET.1 \
    etc/samba etc/bind \
    var/lib/samba/private var/lib/samba/sysvol var/lib/samba/NTACL var/lib/samba/bind-dns \
    var/lib/bind \
    var/lib/ldap-account-manager
rm var/lib/samba/NTACL

#
# Kopano
#
echo "Kopano"
cd /tmp
tar -cvf $TMP_TARGET.2 \
    kopano/var/lib/kopano/attachments \
    kopano/var/lib/mysql

#
# Gitea
#
echo "Gitea"
cd /tmp
tar -cvf $TMP_TARGET.3 \
    gitea/data \
    gitea/var/lib/mysql

#
# merge tarball.
#
echo "Merge"
head -c -$((512*2)) $TMP_TARGET.1 > $TMP_TARGET
head -c -$((512*2)) $TMP_TARGET.2 >> $TMP_TARGET
head -c -$((512*2)) $TMP_TARGET.3 >> $TMP_TARGET
rm $TMP_TARGET.1 $TMP_TARGET.2 $TMP_TARGET.3

echo "Archive"
gzip $TMP_TARGET

# Finish.
echo "Backed up."

バックアップを実行

バックアップスクリプトは、バックアップ対象のコンテナが止まっている前提で書いた。
そこで、バックアップ対象のコンテナを止めてバックアップを実行し、その後にコンテナを起動するスクリプトを作った。

~/hd-backup/do-backup.sh

#!/bin/bash
cd $(dirname ${0})
docker container stop gitea gitea_db kopano kopano_db samba
docker compose up --build
#docker compose down
docker container start samba kopano_db kopano gitea_db gitea

バックアップ対象のSambaやKopano、Giteaのコンテナを手でメンテナンスしている時に、ミスでボリュームが消えたら大変。
今回、バックアップ対象のボリュームを削除できなくするのを目的の1つにしているので、ここではあえてbackupコンテナを削除しないことにした。
これにより「参照しているコンテナがいる」状態になるので、ボリュームを削除できない。

このスクリプトを実行。
cornに登録しておけば、忘れずにやってくれるだろう。

$ sudo ./do-backup.sh

雑すぎるけれども、ホームラボではこれくらいで十分。
場所や状況によっては、この程度のバックアップでも良いかもしれない。

リストア

リストアは、コンテナを起動したあと中に入ってやるつもり。
コンテナを起動する前に、環境変数を変更する。

~/hd-backup/docker-compose.yml

…
  backup:
…
    environment:
      TZ: Asia/Tokyo
      DO_BACKUP: "false"
…

コンテナを起動して、コンテナの中に入る。

$ sudo docker compose up -d
$ sudo docker exec -it backup ash --login

バックアップファイルは、以下に置かれている。

# ls -la /mnt/backups/backup-$(hostname)*
-rw-r--r--    1 root     root      94364577 Sep 21 00:01 /mnt/backups/backup-hogedomain-2022-09-20-15-00-45.tar.gz
-rw-r--r--    1 root     root      94735800 Sep 21 23:38 /mnt/backups/backup-hogedomain-2022-09-21-14-37-48.tar.gz
-rw-r--r--    1 root     root     103409960 Sep 26 21:28 /mnt/backups/backup-hogedomain-2022-09-26-12-28-11.tar.gz
-rw-r--r--    1 root     root     107503016 Oct  9 05:19 /mnt/backups/backup-hogedomain-2022-10-09-05-19-21.tar.gz

展開して、しかるべき場所にファイルを復元する。

# cd /mnt
# tar zxvf backups/backup-hogedomain-2022-10-09-05-19-21.tar.gz

バックアップの中に、以下のファイルがある。

var/lib/samba/NTACL

samba-tool ntacl set "O:LAG:BAD:P(A;OICI;0x001f01ff;;;BA)(A;OICI;0x001200a9;;;SO)(A;OICI;0x001f01ff;;;SY)(A;OICI;0x001200a9;;;AU)" "./sysvol"
samba-tool ntacl set "O:LAG:BAD:P(A;OICI;0x001f01ff;;;BA)(A;OICI;0x001200a9;;;SO)(A;OICI;0x001f01ff;;;SY)(A;OICI;0x001200a9;;;AU)" "./sysvol/hogeserver.hogeddns.jp"
…

これは、バックアップを作成した際に、Samba ad dcで拡張属性を取り出して、リストア用の設定スクリプトにしたもの。
ファイルを展開しただけでは拡張属性が復元できないので、しかるべき場所に復元したら、var/lib/samba相当のディレクトリに移動して、スクリプトを実行する。
そして、NTACLファイルは、実行後削除する。

さいごに

Nextcloud all in one を試した時に、周りのコンテナを起動したり停止したりしていた。
今回のコンテナでそれができれば、もう少しきめ細やかなバックアップができるようになるので、どうやっているのか知りたいなぁ。

コメントはこちらから お気軽にどうぞ ~ 投稿に関するご意見・感想・他