さくらのクラウドで自動バックアップ機能が利用できない場合に独自スクリプトで対処する

さくらのクラウドで自動バックアップ機能を利用しようとしたところ「東京第1ゾーンでは新規受付を停止させていただいております」と表示されており、自動バックアップ機能の追加ができませんでした。サポートに問い合わせたところ「2018年7月11日時点で受付再開の予定は立っていない」とのことだったため、独自スクリプトで自動的にバックアップを行うことにしました。自動バックアップ機能はβ版として公開されていたので、このようなかたちになっても仕方がない感はあります。

<img width="1283" alt="pic11.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/1ffeb8b7-cffc-933d-9e76-409f8244f92d.png">

## 独自スクリプトの仕様
- 独自スクリプトはPHPで開発する。
- 独自スクリプト内でさくらのクラウド内のリソースを操作するためのAPIを実行することでバックアップを行う。
- バックアップ先はさくらのクラウドのアーカイブとする。
- バックアップは1世代管理とする。
- バックアップを作成するプログラムと削除するプログラムの2種類を作成する。
- スクリプトはCRONなどから定期実行する。

# 手順
## さくらのクラウドのAPIキーを取得する。
1.さくらのクラウドにログイン(https://secure.sakura.ad.jp/cloud/ )し、「APIキー」をクリックする。
<img width="1276" alt="pic1.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/a49e874b-a0c7-f407-a512-232496435c12.png">

2.対象アカウント(赤枠箇所)をクリックする。
<img width="1280" alt="pic2.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/9bcc0f96-f5fd-5b26-30a9-bc745827c3eb.png">

3.「追加」をクリックする。
<img width="1285" alt="pic3.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/a74421ee-9fa2-4713-a175-d2a047c19dd3.png">

4.以下の通り、必要情報を入力する。 ※API名は何でもOK。
<img width="1285" alt="pic4.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/820f902c-4214-2ce0-f6fe-bb5e79793bc7.png">

5.APIキー登録された。
<img width="1284" alt="pic5.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/ab461f2f-854b-d114-4f71-6f9c53650943.png">

6.「アクセストークン」「アクセストークンシークレット」を独自スクリプトで利用するため控えておく。
<img width="1283" alt="pic6.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/21d5f154-2ecd-6f4e-a778-da7f211f12bd.png">

## 独自スクリプト作成
### バックアップスクリプト①(アーカイブ作成スクリプト)
~~~ php:create_archive.php
<?php
// 利用するAPIは拠点に応じて書き換える
$url = 'https://secure.sakura.ad.jp/cloud/zone/tk1a/api/cloud/1.1/archive'; // 東京第1ゾーン
//$url = 'https://secure.sakura.ad.jp/cloud/zone/is1a/api/cloud/1.1/archive'; // 石狩第1ゾーン
//$url = 'https://secure.sakura.ad.jp/cloud/zone/is1b/api/cloud/1.1/archive'; // 石狩第2ゾーン
//$url = 'https://secure.sakura.ad.jp/cloud/zone/tk1v/api/cloud/1.1/archive'; // Sandbox

// APIキー
$access_token = 'xxxxxxxxxxxxxxxxxxxxxxx';
$access_token_secret = 'xxxxxxxxxxxxxxxxxxxxxxx';

// 作成するアーカイブに関する情報
$create_target_name = 'xxxxxxxxxxxxxxxxxxxxxxx';
$create_target_description = '独自スクリプトによる自動バックアップ';
$target_disk_id = '000000000000';

// アーカイブ作成
exec('curl --user "' . $access_token . '":"' . $access_token_secret . '" -X POST -d \'{"Archive":{"Name":"'. $create_target_name . '","Description":"' . $create_target_description . '","SourceDisk":{"ID":"' . $target_disk_id . '"}}}\' ' . $url, $e, $r);

// 処理結果を通知する。slackなどに通知してもOK。

~~~

### バックアップスクリプト②(不要アーカイブ削除スクリプト)
~~~ php:gc_archive.php
<?php
// 利用するAPIは拠点に応じて書き換える
//$url = 'https://secure.sakura.ad.jp/cloud/zone/tk1a/api/cloud/1.1/archive'; // 東京第1ゾーン
//$url = 'https://secure.sakura.ad.jp/cloud/zone/is1a/api/cloud/1.1/archive'; // 石狩第1ゾーン
//$url = 'https://secure.sakura.ad.jp/cloud/zone/is1b/api/cloud/1.1/archive'; // 石狩第2ゾーン
//$url = 'https://secure.sakura.ad.jp/cloud/zone/tk1v/api/cloud/1.1/archive'; // Sandbox

$zone = '/tk1a/api/cloud/1.1/archive'; // 東京第1ゾーン
//$zone = '/is1a/api/cloud/1.1/archive'; // 石狩第1ゾーン
//$zone = '/is1b/api/cloud/1.1/archive'; // 石狩第2ゾーン
//$zone = '/tk1v/api/cloud/1.1/archive'; // Sandbox

// APIキー
$access_token = 'xxxxxxxxxxxxxxxxxxxxxxx';
$access_token_secret = 'xxxxxxxxxxxxxxxxxxxxxxx';

// 削除対象のアーカイブ名
$gc_target = 'xxxxxxxxxxxxxxxxxxxxxxx';

// 新しい順に並び替えるときに使用する関数
function SortASC($x, $y)
{
    if ($x->CreatedAt == $y->CreatedAt) {
        return 0;
    }
    return ($x->CreatedAt < $y->CreatedAt) ? -1 : 1;
}

// 現状のアーカイブ一覧を取得
$archives = array();
$json = file_get_contents('https://' . $access_token . ':' . $access_token_secret . '@secure.sakura.ad.jp/cloud/zone' . $zone);
$r = json_decode($json);
if ($r->Archives && is_array($r->Archives)) {
    foreach ($r->Archives as $v) {
        if (strpos($v->Name, $gc_target) === 0 && $v->Availability == 'available' && $v->Scope == 'user') {
            $archives[$v->Name][] = $v;
        }
    }
}

// 最新のアーカイブを残し、古いアーカイブは全て削除する。
foreach ($archives as $name => $a) {
    usort($a, 'SortASC');
    $v = array_pop($a);
    if ($a && is_array($a)) {
        foreach ($a as $v) {
            exec('curl --user "' . $access_token . '":"' . $access_token_secret . '" -X DELETE https://secure.sakura.ad.jp/cloud/zone' . $zone . '/' . $v->ID, $e, $r);
        }
    }
}
~~~

## 独自スクリプトの動作確認
1.バックアップスクリプト①「create_archive.php」を実行し、アーカイブが作成されるか確認する。作成時間はディスクの容量により前後する。
<img width="1282" alt="pic7.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/88aed959-1f40-df34-426c-0750654e7584.png">
アーカイブ作成中は有効状態が「コピー中」になり、作成が完了すると「利用可能」に変わる。「コピー中」に後述するバックアップスクリプト②「gc_archive.php」を実行しても「コピー中」のアーカイブは削除されない(削除エラーになる)。
<img width="1284" alt="pic8.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/a1ea6738-e907-409b-e07b-cec0299ccbb7.png">

2.アーカイブの作成が完了するとこのような表示になる。この状態から、バックアップスクリプト②「gc_archive.php」を実行し、古い方のアーカイブのみが削除されるか確認する。
<img width="1282" alt="pic9.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/8bd2ee12-cf67-e2e5-7adc-e0c1e9e3fe20.png">

3.古い方のアーカイブが削除されていることを確認する。
<img width="1286" alt="pic10.png" src="https://qiita-image-store.s3.amazonaws.com/0/269537/5c3e9f6b-d9e1-6f2e-3a01-62d822b7e6ae.png">

## CRONやジョブを利用し、独自スクリプトを定期実行する
ここでは、CentOS7と「cronie-noanacron」を利用して定期実行を実現します。

1.指定時刻通りにジョブを実行したいので、「cronie-noanacron」をインストールする。※遅延実行する「cronie-anacron」は利用しない。

~~~ terminal:terminal
$ sudo yum -y install cronie-noanacron
$ sudo yum -y remove cronie-anacron
~~~

2.自動実行の設定を追記する。 
アーカイブ作成後に削除処理を行う。そのため、一時的にアーカイブが2世代存在することになる。
アーカイブが作成されると課金されるため、2世代存在する時間を極力減らしたい場合は、バックアップスクリプト②「gc_archive.php」の実行時間を調整する必要がある(定期的に実行してもOK)。アーカイブの容量によっては作成に時間がかかる場合があるため、バックアップスクリプト①と②の実行間隔が短い場合、②の実行に失敗(アーカイブ作成中の場合、削除エラーが発生する)する可能性があるため注意が必要。

~~~ terminal:/etc/cron.d/dailyjobs
# 毎日03:00に実行
0 3 * * * root /xxx/php /xxx/yyy/create_archive.php
# 毎日03:30に実行
30 3 * * * root /xxx/php /xxx/yyy/gc_archive.php
~~~


3.crondを再起動する。

~~~ terminal:terminal
$ sudo systemctl restart crond
~~~

4.実行ログを確認

~~~ terminal:terminal
$ sudo less /var/log/cron
~~~


## 参考
【php】さくらのクラウドのAPIで日次バックアップ作成スクリプト
https://www.softel.co.jp/blogs/tech/archives/5414