さくらのクラウドで出来るだけ安価にバックアップサーバを運用する工夫

この記事は、ビットスター Advent Calendar 2021 の2日目です。
明日は、@pyjackalさんの「[import thisで親父の小言を表示する](https://qiita.com/pyjackal/items/cfdb55051b1d3307eca1)」です。

# はじめに

弊社ビットスターのグループ企業であるさくらインターネット社が提供しているパブリッククラウドサービス「さくらのクラウド」。弊社も自社用に顧客用にと頻繁に使っていますが、サーバを運用する上で切り離せないのが「バックアップ」です。

この記事では、私が業務の中でさくらのクラウドでサーバのバックアップを取得する際に工夫している事例をご紹介します。

# バックアップ方法の選択肢

さくらのクラウドでサーバのバックアップを行う場合、幾つかの選択肢があります。
選択肢ごとにメリットとデメリットをまとめてみました。

## 手動でディスクをコピーする

:::note info
コントロールパネルから数クリックで完了するので簡単
コピーしたディスクはサーバにマウントして使える
:::

:::note alert
手動なので自動化できない
ディスク全体のコピーになるので時間（とお金）が掛かる
:::

## 手動でアーカイブを取得する

:::note info
コントロールパネルから数クリックで完了するので簡単
:::

:::note alert
手動なので自動化できない
アーカイブは直接マウントできないのでディスクとして復元する必要がある
:::

## 自動バックアップ機能でアーカイブを取得する

:::note info
自動化できるので、一度設定したら何もしなくてもよい
:::

:::note alert
バックアップのタイミングを時間単位で厳密に指定できない
:::

## NFSアプライアンスの共有領域をマウントしてコピーする

:::note info
必要なデータをcpコマンド等で普通にコピーするだけでよいので簡単
:::

:::note alert
ユーザー認証機構がないので別でセキュリティを確保する必要がある
:::

## バックアップサーバに転送する

:::note info
任意のスクリプトで自由度の高いバックアップができる
OSのユーザー管理やファイアウォール機能等が使えるのでセキュリティを確保しやすい
:::

:::note alert
バックアップサーバ自体を運用する必要がある
:::

# バックアップの要件

今回は、

* バックアップは自動で行いたい
* 重要なバックアップデータなので、セキュリティを高く保ちたい
* タイミングを厳密に指定してバックアップしたい

といった要件がありましたので、**バックアップサーバに転送する**方法を選択することにします。

# 困ること

バックアップサーバ方式を選択した場合に困ることとしては、**バックアップしていない時にもバックアップサーバの課金が発生する**ということです。ディスクコピーやアーカイブ、自動バックアップ等はクラウド基盤上で動作する機能のため、処理が完了すればコンピューティングに関する課金は終了しますが、サーバの場合は一度作成すると、動いている限りはずっと課金されることになります。

ただでさえ、バックアップが実際に復元等の目的で利用される頻度は非常に低いですし、バックアップが終わったらサーバが動いている必要はありません。セキュリティ的にも停止している方が安全であるとも言えます。

# 解決方法

課題を解決するために、これらのことをやってみることにします。

* バックアップされる側のサーバでcronを使ってバックアップスクリプトを起動する
* バックアップ開始時にバックアップサーバを起動する
* rsyncを使って差分のみをバックアップする
* バックアップ終了時にバックアップサーバを停止する

これによりバックアップ時間を短縮し、必要最小限の利用分に課金を抑えることができるはずです。

# 設定手順

## 想定環境

次の様な環境が存在しているものとします。

<dl>
  <dt>サーバ</dt>
  <dd>ホスト名：server</dd>
  <dd>IPアドレス：10.0.0.10</dd>
  <dd>OS：CentOS 7</dd>
  <dd>バックアップ元ディレクトリ：/var/www/html</dd>
  <dt>　</dt>
  <dt>バックアップサーバ</dt>
  <dd>ホスト名：backup</dd>
  <dd>IPアドレス：10.0.0.11</dd>
  <dd>OS：CentOS 7</dd>
  <dd>バックアップ先ディレクトリ：/backup</dd>
</dl>

## バックアップサーバへのSSH公開鍵認証ログイン設定

サーバ上で動作するバックアップスクリプトがrsyncでデータを転送するには、パスワード認証ではなく公開鍵認証にしておく必要がありますので、下記の要領で秘密鍵・公開鍵を生成し、バックアップサーバへ公開鍵を登録しておきます。（一部伏字にしています）

今回はroot所有のファイルもバックアップする必要がありますので、双方ともrootアカウントを使用します。

```bash:server
# ssh-keygen
Generating public/private rsa key pair.
Enter file in which to save the key (/root/.ssh/id_rsa): /root/.ssh/id_backup
Enter passphrase (empty for no passphrase):  <-- エンターだけ押す
Enter same passphrase again:  <-- エンターだけ押す
Your identification has been saved in /root/.ssh/id_backup.
Your public key has been saved in /root/.ssh/id_backup.pub.
The key fingerprint is:
SHA256:******************************************* root@server
～省略～
# ssh-copy-id root@backup
```

## Usacloudの導入

先程解決方法として挙げた中に、「バックアップサーバを起動する」「バックアップサーバを停止する」という内容がありましたが、これを実現するためにはさくらのクラウドが提供しているAPIを使って、サーバの起動、停止を自動処理として記述する必要があります。

PHPやPython等のプログラミング言語を使って、APIにアクセスするクライアントを作成する方法もありますが、コマンドや引数を指定するだけでAPIを操作できるCLIツールである「[Usacloud](https://github.com/sacloud/usacloud)」が公開されていますので、こちらを使うこととします。

Usacloudの導入方法やアカウント情報の設定方法については、非常に分かりやすい[公式ドキュメント](https://docs.usacloud.jp/usacloud/installation/start_guide/)が準備されていますのでここでは省略します。

## バックアップスクリプトの作成

Usacloudを使ってバックアップサーバの起動、終了を行い、rsyncを使って差分バックアップ転送を行うスクリプトを作成します。今回は必要な処理に絞って簡略化し、下記の様な内容で作成してみました。

```bash:/usr/local/sbin/backup.sh
#!/bin/bash

# バックアップサーバを起動する
/usr/local/bin/usacloud server power-on backup -y

# サーバのステータスをチェック
/usr/local/bin/usacloud server ls

# バックアップサーバがSSHでアクセス可能になるまで待機する
while :
do
  ssh -i ~/.ssh/id_backup root@backup true
  if [ $? -eq 0 ]; then
    break
  fi
  sleep 1
done

# rsyncでバックアップサーバに差分転送する
rsync -e "ssh -i ~/.ssh/id_backup" -av --delete --numeric-ids /var/www/html/ backup:/backup/

# バックアップサーバを停止する
/usr/local/bin/usacloud server power-off backup -y

# サーバのステータスをチェック
/usr/local/bin/usacloud server ls
```

ちょっと工夫したところとしては、バックアップサーバを起動した際に、usacloud自体は起動処理後すぐにコマンドが終了してしまうので、実際にサーバのOSが起動しSSHでアクセス可能になるまではタイムラグが発生し、rsyncが失敗する可能性があります。そのため、SSHでアクセス可能になるまで待機する処理を入れています。

## バックアップスクリプトの自動実行設定

作成したバックアップスクリプトは、cronに登録して自動実行される様にします。
今回は深夜の2:00に実行される様にし、バックアップスクリプトの標準出力・標準エラー出力はログファイルにリダイレクトする様にしておきます。

```bash
# crontab -e
※下記の行を追加
0 2 * * * /usr/local/sbin/backup.sh >> /var/log/backup/backup.log 2>&1
```

## バックアップの実行

バックアップの実行はcronで行われますので、ログファイルを見て正常にバックアップが行われているかを確認します。

```bash
# cat /var/log/backup/backup.log
+------+--------------+--------+------+-----+--------+--------------+----------------+----------------+----------+-----+
| Zone |      ID      |  Name  | Tags | CPU | Memory |  IPAddress   | Upstream(Mbps) | InstanceStatus |  InstanceHost  |
+------+--------------+--------+------+-----+--------+--------------+----------------+----------------+----------+-----+
| is1a | ************ | server | -    | 4   | 8      | 10.0.0.10/24 | switch/1000    | up             | sac-is1a-sv*** |
| is1a | ************ | backup | -    | 2   | 4      | 10.0.0.11/24 | switch/1000    | up             | sac-is1a-sv*** |
+------+--------------+--------+------+--------------+--------------+----------------+----------------+----------+-----+

ssh: connect to host backup port 22: Connection refused
sending incremental file list
wordpress/wp-config.php
wordpress/wp-contents/uploads/***.jpg
…
sent ***,***,*** bytes  received *,*** bytes  **,***,***.** bytes/sec
total size is **,***,***  speedup is *.**

+------+--------------+--------+------+-----+--------+--------------+----------------+----------------+----------+-----+
| Zone |      ID      |  Name  | Tags | CPU | Memory |  IPAddress   | Upstream(Mbps) | InstanceStatus |  InstanceHost  |
+------+--------------+--------+------+-----+--------+--------------+----------------+----------------+----------+-----+
| is1a | ************ | server | -    | 4   | 8      | 10.0.0.10/24 | switch/1000    | up             | sac-is1a-sv*** |
| is1a | ************ | backup | -    | 2   | 4      | 10.0.0.11/24 | switch/1000    | down           | sac-is1a-sv*** |
+------+--------------+--------+------+--------------+--------------+----------------+----------------+----------+-----+
```

ログの最初に、usacloudでサーバを起動した後のサーバのステータスが表示されていますが、backupサーバの「InstanceStatus」が「up」になっていますので、サーバの起動が成功したことが分かります。

次に、

```
ssh: connect to host backup port 22: Connection refused
```

というログが記録されていますが、これはSSHがアクセス可能になるまで待機する処理が行われた際に残ったものです。

その後rsyncの転送ログが残っており、バックアップ処理本体も正常に行われたことが確認出来ます。

最後に、バックアップ終了後にusacloudでサーバを停止した後のサーバステータスが表示されていますが、backupサーバの「InstanceStatus」が「down」になっていますので、サーバの停止が成功したことが分かります。

# コストダウン効果

今回実施した作業で、バックアップサーバはバックアップ開始時に起動し、バックアップ終了後に停止する様になりました。さくらのクラウドでは、インスタンスが停止している時間は課金が行われませんのでコストダウン効果が期待できますが、どのくらいの効果があったのでしょうか。

ユースケースにより異なりますが、バックアップの所要時間が2時間であった場合の試算は下記の通りとなります。

※バックアップサーバ（2C4G）石狩第1ゾーンで計算（税込）
※ディスク費用が別途必要。ディスクはサーバ停止中も課金されます

| 稼働時間 | 月額 | 年額 | 削減率 |
|:-----:|:------:|:------:|:------:|
| 24時間/日 | 4,620円 | 55,440円 | - |
| 2時間/日 | 1,500円 | 18,000円 | -67% |

なんと、7割近くのコスト削減となりました。

# まとめ

今回はあくまで一例ですが、クラウドのメリットとして「必要な時に必要なだけ」という点はよく知られていますが、実際にそのメリットを活用している事例は意外に少ない様です。

クラウドは機能性が高い分、サービスの単価としては高めに設定されているので、従来のオンプレミスや専用サーバ、VPS等の延長として同じ様な使い方をしているとコスト的には負担が大きくなってしまいます。

例えば業務サーバ等の場合、利用されない夜間や休日等に停止することで大きくコストを削減できる可能性もありますので、クラウドの活用方法の一つとして、「必要な時だけ起動する」を徹底してみるのもよいのではないでしょうか。