AWS Glacier にCLIでアーカイブをアップロード／ダウンロードする

# 概要

突然ディスクアクセスできなくなってしまい、中のデータが復旧できず、、、
という不幸に見舞われた経験があるのでアーカイブの平均年間耐久性99.999999999%
のAWS Glacierに手を出してみました。

ざっくり言うと、毎月10GBのダウンロード、1000リクエスト以上の利用をしなければ、
ストレージ料金だけなので東京リージョンで1か月あたり 0.005USD/GB
つまり
　500GB保存：毎月約300円
　1TB保存　：毎月約600円
　　※1USD約110円計算
という定額料金でデータが消えてしまうリスクがほぼなくなるというサービス
（ちなみにS3のストレージ料金は約0.025USD/GBくらい）

[Glacier 料金詳細](https://aws.amazon.com/jp/glacier/pricing/ "Glacier 料金詳細")

ただ、S3からのライフサイクルを利用しないとデータの保存、ダウンロードがGUIからできず、
AWS SDK や REST API、CLIを使うというちょっと玄人向けのサービス

あと気をつけないといけないことが、取り出したいと思ったときに取り出せない
取り出しリクエストをして通常3～5時間待たないといけないこと。
（早く取り出すこともできるけどお金がかかる）

これらが許容できれば安くて高信頼のディスクが使える。
ということでその手順を展開。

## 手順

今回はCLIを使った手順を採用したのでとりあえずCLIを入れる。

インストール方法は以下を参照
（Pythonが入っていればpipで一発）

[AWS コマンドラインインターフェイス](https://aws.amazon.com/jp/cli/ "AWS コマンドラインインターフェイス")

後はアップロードと必要な時にダウンロードするだけ。

アップロードは簡単。アップロード用のコマンドを実行するだけ。
ダウンロードには少し手間がかかる。ダウンロード用のアーカイブ取得用のジョブを実行後、
準備ができたら、アーカイブダウンロード用のコマンドを実行する必要がある。

ダウンロードには、アーカイブを指定するのための archiveId が必要になる。
archiveId は、アップロード用のコマンド実行結果の戻り値として取得する。

他にもいろいろ選択肢があるようだけど今回は一番シンプルなものを採用。
必要なコマンドは以下だけ。

* アップロード
 * アーカイブのアップロード
 * アーカイブの確認ジョブ（※）
* ダウンロード
 * アーカイブの取得ジョブ
 * アーカイブのダウンロード

※アーカイブの確認ジョブは任意。ダウンロードに必要な archiveId とかを忘れた時に実行する

手順の詳細は、以下の公式ページを参照。

[Amazon Glacier でのアーカイブのアップロード](https://docs.aws.amazon.com/ja_jp/amazonglacier/latest/dev/uploading-an-archive.html "Amazon Glacier でのアーカイブのアップロード")

[Amazon Glacier アーカイブの取得](https://docs.aws.amazon.com/ja_jp/amazonglacier/latest/dev/downloading-an-archive-two-steps.html "Amazon Glacier アーカイブの取得")

では、それぞれのコマンドを以下に記載。

## アーカイブのアップロード

```
aws glacier upload-archive --account-id %ACCOUNT_ID% --vault-name %VAULT_NAME% --archive-description %ZIP_DESC% --body %ZIP_FILENAME%
```
※ %で囲まれているのは変数。自身の値で適宜変更する。

%ACCOUNT_ID%：AWSのアカウントID
%VAULT_NAME%：GlacierのGUIで作るボールトと言われるアーカイブを格納するための箱の名前を指定する
%ZIP_DESC%：任意項目だけど、ファイル名ではなく、archiveId で管理されるため付けておいた方が後々わかりやすい（２バイト文字は使えない。。。）
%ZIP_FILENAME%：アップロードするファイル名

コマンド実行後、アップロードが完了すると戻り値に archiveId が返される（ダウンロードするときに必要）
ただ、GUIのアーカイブ数などに反映されるのは数時間後（多分、他のリージョンとかに複製しているからのはず）

100MB を超えるサイズのアーカイブをアップロードする際にはマルチパートアップロードが推奨されている
ようだけど、マルチパートアップロードはまだ試せていない。
上記のコマンドで1GB程度まではアップロードすることができた。

アップロード時の破損に備えて checksum を指定する場合は以下のコマンド

```
aws glacier upload-archive --account-id %ACCOUNT_ID% --vault-name %VAULT_NAME% --archive-description %ZIP_DESC% --checksum %ZIP_CHECKSUM% --body %ZIP_FILENAME%
```

%ZIP_CHECKSUM%：チェックサム。計算ロジックは以下を参照

[チェックサムの計算](https://docs.aws.amazon.com/ja_jp/amazonglacier/latest/dev/checksum-calculations.html "チェックサムの計算")

どちらのコマンドも戻り値は以下のようになる。
archiveId が、ダウンロードするときに必要になるため超重要。

```json:戻り値
{
    "archiveId": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "checksum": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
    "location": "/xxxxxxxxxx/vaults/vaultname/archives/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
```

## アーカイブの確認ジョブ

archiveId を忘れてしまったときに実行する。
このコマンドはジョブの開始命令をするだけなのでジョブが完了したら
下記のアーカイブのダウンロードコマンドを実行してボールト内のアーカイブの一覧が記載された
jsonファイルを取得する

```
aws glacier initiate-job --account-id %ACCOUNT_ID% --vault-name %VAULT_NAME% --job-parameters file://inventory-retrieval.json
```

```json:inventory-retrieval.json
{
  "Type": "inventory-retrieval"
}
```

%ACCOUNT_ID%：AWSのアカウントID
%VAULT_NAME%：ボールトID

```json:戻り値
{
    "location": "/xxxxxxxxxx/vaults/vaultname/archives/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "jobId": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
```

## アーカイブの取得ジョブ

このコマンドもジョブの開始命令をするだけ。
完了したらアーカイブのダウンロードコマンドを実行してアーカイブファイルを取得する。
archive-retrieval.json の ArchiveId にアーカイブのアップロードコマンドの戻り値か
アーカイブの確認ジョブで確認したダウンロード対象の ArchiveId を指定する。

```
aws glacier initiate-job --account-id %ACCOUNT_ID% --vault-name %VAULT_NAME% --job-parameters file://archive-retrieval.json
```

```json:archive-retrieval.json
{
  "Type": "archive-retrieval",
  "ArchiveId": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
  "Description": "Retrieve archive on 2018-06"
}
```

%ACCOUNT_ID%：AWSのアカウントID
%VAULT_NAME%：ボールトID

```json:戻り値
{
    "location": "/xxxxxxxxxx/vaults/vaultname/archives/XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
    "jobId": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXX"
}
```

以下のエラーが発生した時は、、、

```
An error occurred (PolicyEnforcedException) when calling the InitiateJob operation: InitiateJob request denied by current data retrieval policy.
```

Glacierの設定を変更する

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/844045e0-e07e-c0d1-de98-949fbd3ce3a7.png)

例えば、「取得制限なし」にすればエラーは出なくなる。
このエラーは、取り出しポリシーに違反した要求があったよ。というもの。
「無料利用枠のみ」の場合、無料利用枠の1か月につき10GBを日割りしたバイト数（約300MB）を
超えたアーカイブ取得要求をした場合に発生するため、「取得制限なし」にすればエラーは出なくなる。
1か月につき10GBを超えないように自分で取り出し容量を把握しないとならないが(^^;)

[Glacier のデータ取り出しポリシー](https://docs.aws.amazon.com/ja_jp/amazonglacier/latest/dev/data-retrieval-policy.html "Glacier のデータ取り出しポリシー")

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/77753bdb-6189-6b67-a0c6-f6fa1e6d3fb4.png)



## アーカイブのダウンロード

実際にアーカイブをダウンロードする時に実行するコマンド。
アーカイブの取得ジョブの戻り値で取得した jobId を指定してダウンロードする。

```
aws glacier get-job-output --account-id %ACCOUNT_ID% --vault-name %VAULT_NAME% --job-id %JOB_ID% %OUTPUT_FILENAME%
```

%ACCOUNT_ID%：AWSのアカウントID
%VAULT_NAME%：ボールトID
%JOB_ID%：アーカイブの取得ジョブ（または、アーカイブの確認ジョブ）の戻り値のジョブID
%OUTPUT_FILENAME%：ダウンロード後のファイル名

```json:戻り値
{
    "status": 200,
    "acceptRanges": "bytes",
    "contentType": "application/octet-stream",
    "checksum": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxx"
}
```

## アーカイブの削除

アーカイブを削除する時に実行するコマンド。アーカイブのアップロードコマンドの戻り値か
アーカイブの確認ジョブで確認したダウンロード対象の ArchiveId を指定する。

```
aws glacier delete-archive --account-id %ACCOUNT_ID% --vault-name %VAULT_NAME% --archive-id %ARCHIVE_ID%
```

%ACCOUNT_ID%：AWSのアカウントID
%VAULT_NAME%：ボールトID
%ARCHIVE_ID%：アーカイブID

## 参考

ジョブを開始したら数時間待つ必要がある。
以下のコマンドを実行すれば、ジョブ状態確認（処理中か完了済みかなど）が可能。

```
aws glacier list-jobs --account-id %ACCOUNT_ID% --vault-name %VAULT_NAME%
```
%ACCOUNT_ID%：AWSのアカウントID
%VAULT_NAME%：ボールトID

```戻り値
{
    "JobList": [
        {
            "CompletionDate": "2018-06-20T17:26:36.824Z",
            "VaultARN": "arn:aws:glacier:ap-northeast-1:xxxxxxxxxx:vaults/vaultname",
            "RetrievalByteRange": "0-713471680",
            "Tier": "Standard",
            "SHA256TreeHash": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            "Completed": true,
            "JobId": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX,
            "ArchiveId": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            "JobDescription": "Retrieve archive on 2018-06",
            "ArchiveSizeInBytes": 713471681,
            "Action": "ArchiveRetrieval",
            "ArchiveSHA256TreeHash": "XXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXXX",
            "CreationDate": "2018-06-20T13:36:08.186Z",
            "StatusMessage": "Succeeded",
            "StatusCode": "Succeeded"
        }
    ]
}
```

ボールトごとに完了通知用のSNSを指定することもできるため
コマンドではなくこちらの設定を利用することも可能。

![image.png](https://qiita-image-store.s3.amazonaws.com/0/188544/4d649020-97eb-32a7-561e-a28510679c44.png)

以上。
これで突然データが壊れるリスクから解放される(^^)
同じ思いの人がいたら使ってみては？
それでは良いAWSライフを！

## 更新履歴

20181223 PolicyEnforcedException のエラーについて追記
20190223 アーカイブの削除について追記