ストレージクラスをGlacier系に変更したS3オブジェクトをダウンロードする

カメラで撮った写真をとりあえずS3に置くっていうことをしていた結果、コストがかなりかさんでしまいました…
とりあえず少し安くしようということでGlacier(Flexible Retrieval)にストレージ変更したりしてたんですが、復元の必要が出てきたり色々と気づくことがあったので、
Glacierクラスオブジェクトのダウンロード手順や、料金に関する注意などを書きます。

Glacierからの取り出し(復元)方法

素朴に aws s3 cp すると以下のようにGlacier系のストレージクラスのオブジェクトはスキップされます。

warning: Skipping file s3://<bucket>/<object>. Object is of storage class GLACIER. Unable to perform download operations on GLACIER objects. You must restore the object to be able to perform the operation. See aws s3 download help for additional parameter options to ignore or force these transfers.

aws s3api を使った復元方法

Glacierからの復元は aws s3api restore-object を使う方法が一般的のようです。

https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/restoring-objects.html

aws s3api restore-object --bucket DOC-EXAMPLE-BUCKET --key dir1/example.obj --restore-request '{"Days":25,"GlacierJobParameters":{"Tier":"Standard"}}'

上記復元リクエストをすると、スタンダードクラス、低冗長のオブジェクトとして一時的なコピーが作成されます。
↑の例では25日間コピーが維持されるようです。
https://repost.aws/ja/knowledge-center/restore-s3-object-glacier-storage-class

復元進行状況の確認

aws s3api head-object コマンドでオブジェクトの復元進行状況を確認できます。

aws s3api head-object --bucket awsexamplebucket --key dir1/example.obj

↓のように ongoing-request=“true” となっている場合は復元が進行中(未完了)

{
    "Restore": "ongoing-request=\"true\"",
    ...
}

↓のように ongoing-request=“false” となっている場合は復元が完了しており、
expiry-date まで一時コピーが保存されます。ダウンロード等する場合はこのexpiry-dateまでにする必要があります。

{
    "Restore": "ongoing-request=\"false\", expiry-date=\"Sun, 13 Aug 2017 00:00:00 GMT\"",
    ...
}

aws s3api restore-object をprefix以下のオブジェクトに再帰的にやる

aws s3api restore-object には、 aws s3 cp でいう --recursive オプションがありません。
そのため、 s3://<bukect>/<prefix>/ 以下のすべてのオブジェクトを復元したいといった場合に少し工夫が要りそうです。

まず以下のようなコマンドで再帰的な復元リクエストをやりました。

aws s3 ls s3://<bucket>/<prefix>/ --recursive | awk '{print $4}' | xargs I@ sh -c 'echo @; aws s3api restore-object --bucket <bucket> --restore-request '\''{"Days": 1,"GlacierJobParameters":{"Tier":"<取り出しオプション>"}}'\'' --key @'

復元されたオブジェクトをダウンロードする

復元が完了したら、expiry-dateまでの間ダウンロードすることができます。

aws s3 cp s3://<bucket>/<prefix>/<obuject> ./ 

復元が完了しないままcpしようとすると以下のように失敗します

download failed: s3://<bucket>/<object> to <object> An error occurred (InvalidObjectState) when calling the GetObject operation: The operation is not valid for the object's storage class

aws s3 cp –recursive などで一括ダウンロードする

aws s3 sync や --recursive オプションをつけた aws s3 cp では、復元されているオブジェクトでも相変わらず以下のようにスキップされるようでした。

warning: Skipping file s3://<bucket>/<object>. Object is of storage class GLACIER. Unable to perform download operations on GLACIER objects. You must restore the object to be able to perform the operation. See aws s3 download help for additional parameter options to ignore or force these transfers.

以下のようなワンライナーで再帰的なダウンロードをするようにしました。

bucket="<bucket>"; prefix="<prefix>"; aws s3 ls s3://${bucket}/${prefix} --recursive | awk '{print $4}' | bucket="${bucket}" prefix="${prefix}" xargs -I@ sh -c 'echo @; filepath=$(echo @ | sed "s|$prefix||"); echo $filepath; aws s3 cp s3://$bucket/@ "./${filepath}" --force-glacier-transfer'

(後から分かったんですが) aws s3 cp に --force-glacier-transfer オプションをつけることでglacier復元オブジェクトを含めて cp できるっぽいです。明らかにこっちのほうが効率が良さそうです。

aws s3 cp s3://<bucket>/<prefix>/ ./ --recursive --force-glacier-transfer

Glacierの見落としがちな(見落としていた)料金

https://aws.amazon.com/jp/s3/pricing/

  • 取り出し
    • これはまぁよく意識されるかなと思います
    • Glacier Flexible Retrievalなどでは、StandardやBulkといった取り出しオプションによっても料金が変わります
  • ストレージクラス変更
    • Glacierからスタンダードや、別のGlacierクラスに変更する場合、取り出し料金がかかります
  • 復元された一時コピーオブジェクト
    • 先述したようにGlacierからの復元は一時的にスタンダードクラスのオブジェクトが作られます
    • 一時コピーは restore-request で指定したDaysの期間保存され、スタンダード(低冗長)のストレージ料金がかかるので、適切に設定したほうがいいです
  • 最小ストレージ期間
    • 最小ストレージ期間が経過する前に、オブジェクトが削除、上書き、ストレージクラス変更などされた場合は、最小ストレージ期間の残りの日割り料金が請求されます
    • IA, One-Zone-IA は30日
    • Instant Retrieval と Flexible Retrieval は90日、Deep Archive は180日

結構軽い気持ちでとりあえずGlacierに、としてたけど、最小ストレージ料金は盲点でした