さくらのクラウドのディスクの自動バックアップを自作してみる

## 概要
さくらのクラウドには[自動バックアップ](https://manual.sakura.ad.jp/cloud/appliance/autobackup/index.html)という機能がありますので、まずはこちらの利用を検討するのがよいと思われます。  
以下の希望がある場合は、本処理が参考になる可能性があります。

* 実行時間を指定したい
* 週次以外のスケジュールを指定したい

## 手法
[usacloud](https://docs.usacloud.jp/usacloud/)という CLIクライアントを利用して、対象となるディスクを特定し、アーカイブを作成後、保存世代数を超える過去分を削除するスクリプトを作成します。  
この処理を、cron で好きな時間帯に実行することで、お手製の自動バックアップとする形です。  
今回は自前のサーバなどを用意しなくてもすむように、GitHub Actions を使用して、指定した時間帯で usacloud のコンテナを作成し、スクリプトを実行するようにしています。

***
**注意事項**
* スクリプトはあくまでもサンプルなので、エラー処理等は一切入れていません。必要に応じて修正ください。
* 全ゾーンを対象に、 `myautobackup` タグが付いたディスクをすべてバックアップ対象としています。
* アーカイブ名は `myautobackup-年月日-コピー元ディスクID` とし、 `myautobackup` タグを付与しています。
* 保存世代数は `ROTATE` で指定しています。
* アーカイブ作成コマンドには `--no-wait` をつけることで、作成完了まで待たずに次の処理にすすむようにしてあります。ただし、それでも数十秒程度は時間がかかるものと思われます。

***

## 基本的な流れ
1. GitHub のリポジトリを `プライベート` で作成してください。

	* パブリックで作成して公開してしまうと、ログが見えることになるので危険です。

1. 該当リポジトリ内の Settings で、Secrets内の Actions に以下 Actions secrets を設定してください。

	```Console:Name
	SAKURACLOUD_ACCESS_TOKEN
	SAKURACLOUD_ACCESS_TOKEN_SECRET
	```

1. 以下ファイルを配置してください。

	```shell:backup.sh
	#!/bin/bash
	
	TODAY=`TZ='Asia/Tokyo' date "+%Y%m%d"`
	TARGET_TAG="myautobackup"
	NAME="myautobackup-${TODAY}"
	TAGS="myautobackup"
	ROTATE=2

	for Zone in tk1a tk1b is1a is1b
	do
		echo "---- List Target Disks of $Zone ----"
		DiskIds=`usacloud disk ls --tags $TARGET_TAG --zone $Zone --query="reverse | .[].ID" --query-driver=jq | xargs`

		for DiskId in $DiskIds
		do
			echo "---- Create Archive $DiskId ----"
			usacloud archive create --source-disk-id $DiskId --name "${NAME}-${DiskId}" --tags $TAGS -y --zone $Zone -q --no-wait

			# sort by CreatedAt or Name
			ArchiveIds=`usacloud archive ls --scope user --tags $TAGS --zone $Zone --output-type json --query "map(select( .SourceDiskID==$DiskId )) | sort_by(.CreatedAt) | reverse | .[${ROTATE}:]|.[].ID" --query-driver=jq | xargs`
			for Id in $ArchiveIds
			do
				echo "---- Delete Archive $Id ----"
				usacloud archive delete -y $Id --zone $Zone
			done
		done
	done

	echo "---- Archives ----"
	usacloud archive ls --scope user --tags $TAGS --zone all	
	```

	```yaml:.github/workflows/backup.yml
	name: Backup
	
	on:
	#  push:
	#    branches:
	#      - main
	  schedule:
	    - cron:  '20 0 * * *'
	
	jobs:
	  node-docker:
	    runs-on: ubuntu-latest
	    container: #起動するコンテナイメージを指定
	      image: ghcr.io/sacloud/usacloud #指定のdockerイメージを使用
	
	    env:
	      SAKURACLOUD_ACCESS_TOKEN: ${{ secrets.SAKURACLOUD_ACCESS_TOKEN }}
	      SAKURACLOUD_ACCESS_TOKEN_SECRET: ${{ secrets.SAKURACLOUD_ACCESS_TOKEN_SECRET }}
	      SAKURACLOUD_ZONE: "is1a"
	    steps: #dockerコンテナ内でステップを実行
	      - name: Log usacloud version
	        run: |
	          usacloud -v #バージョンの確認
	          cat /etc/os-release #Linuxバージョンの確認
              apk add --update --no-cache tzdata
	      - uses: actions/checkout@v2 #次ステップでファイル読み込むのでクローンが必要
	      - name: Run a script
	        run: sh ./backup.sh
	```

1. `backup.yml` にあるとおり、日本時間の毎日 9:20頃に実行されるようになっていますので、必要に応じて実行時間を変更してください。

	```
	schedule:
		- cron:  '20 0 * * *'
	```

	* 上記指定だと実際には 11時過ぎに実行されたりしました。負荷の少なそうな時間帯を探すか、おとなしく自前の実行環境を用意した方がいいかもしれません。
	* 実行時間については公式の[情報](https://docs.github.com/ja/actions/using-workflows/events-that-trigger-workflows#schedule)も参照ください。

	```
	ノート: scheduleイベントは、GitHub Actionsのワークフローの実行による高負荷の間、遅延させられることがあります。 
	高負荷の時間帯には、毎時の開始時点が含まれます。 
	遅延の可能性を減らすために、Ⅰ時間の中の別の時間帯に実行されるようワークフローをスケジューリングしてください。
	```

1. `backup.sh` にあるとおり、保存世代数は 2 になっていますので、必要に応じて変更してください。

	```
	ROTATE=2
	```

## サンプルログ
実行時のログを確認すると、以下のように見えます。  
このときは 2つのディスクが対象になっていて、うち 1つはすでに 2つのアーカイブがあったため、作成後に古い 1つが削除されています。

```
Run sh ./backup.sh
---- List Target Disks of tk1a ----
---- List Target Disks of tk1b ----
---- Create Archive ***********5 ----
***********8
---- Delete Archive ***********2 ----
---- Create Archive ***********4 ----
***********9
---- List Target Disks of is1a ----
---- List Target Disks of is1b ----
---- Archives ----
+------+--------------+-----------------------------------+----------------+-------+-------------+
| Zone |      ID      |               Name                |      Tags      | Scope | Description |
+------+--------------+-----------------------------------+----------------+-------+-------------+
| tk1b | ***********4 | myautobackup-20220327-********... | [myautobackup] | user  | -           |
| tk1b | ***********0 | myautobackup-20220327-********... | [myautobackup] | user  | -           |
| tk1b | ***********8 | myautobackup-20220328-********... | [myautobackup] | user  | -           |
| tk1b | ***********9 | myautobackup-20220328-********... | [myautobackup] | user  | -           |
+------+--------------+-----------------------------------+----------------+-------+-------------+
```

## 最後に
さくらのクラウドを利用している時点でなんらかサーバはあるわけなので、その中で cron で設定すればいいわけですが、やはりサービス利用のサーバとは役割上わけたいところですし、とはいえこのためだけに管理サーバを別途用意するのにお金をかけるのも・・・という場合には、こういった方法もお手軽でおもしろいかなと思います。  
サーバの作成も Terraform で実行している場合は、そのコードとまとめて管理することもできて、ちょうどよいかもしれません。  
参考になれば幸いです。  
どうぞよいさくらのクラウドライフを！