AMIをS3に明示的なオブジェクトとして保存してみた!! [いつの間にできるようになっていたんだぃ!?]

2021年4月のアップデートでEBS-backedなAMIをS3に明示的なオブジェクトとして保存できるようになっていました。ユーザ側からは確認できないS3にしか保存できないと思っていたので驚きです!操作やそのメリットなどについてまとめてみます。
2023.06.22

はじめに

清水です。「AMIをS3に保存する」という操作を考えてみます。AMIの実体であるEBSスナップショットはS3に保存されるものだから、AMIを取得することはイコールS3に保存することである、といえます。またかつて主流だったinstance store-backedなインスタンスでは、AMI作成時にアップロード先のS3バケットを指定する必要があったため、よりS3に保存することを意識していたかもしれません。

筆者は永らく「AMIをS3に保存する」という操作は上記2つのイメージだったのですが、先日ふと「 EBS-backedなAMIをオブジェクトとして明示的にS3に保存すること 」が可能になっていることに気が付きました。つまり、現在一般的に使われているEC2から取得したAMIについて、S3バケット内にS3のオブジェクトとして保存が可能になっている、ということです。

具体的には以下ドキュメントに記載があります。CreateStoreImageTaskなどのAPIを使用します。

個人的にはこの機能、とても驚きました。従来からEBS-backed AMIは、その実体のEBSスナップショットは内部的にS3に保存されているけれど、S3オブジェクトとして確認することなどはできない、という先入観があったためですね。詳細を調べてみると2年ほど前のアップデートであり速報性もなにもないのですが、けっこうびっくりな機能だったので、その利点やアップデート内容などについてまとめてみたいと思います。

従来までの「AMIをS3に保存する」

さて、まずは従来まで、つまりCreateStoreImageTaskなどのAPIを使う以前の「AMIをS3に保存する」操作についてもう一度おさらいしておきましょう。

CreateImageでのAMIの取得

最も一般的な「AMIをS3に保存する」操作は、EC2からAMIを取得することではないでしょうか。APIでいえばCreateImage、マネジメントコンソールからなら「Actions > Image and templates > Create image」で操作できます。

この操作を行うことでAMI (Amazon Machine Images)が作成されます。その実体はEBSスナップショットとインスタンスを構成する管理情報で、このEBSスナップショットが実際はS3に保存されているかたちです。(参考: AWS Solutions Architect ブログ: AWSトレーニングでよくいただくご質問シリーズ - 第一回 Amazon Machine Image (AMI) とスナップショットの違い

ただし、このEBSスナップショットはAWSが管理するS3バケットに保存され、ユーザ側からはS3の具体的なオブジェクトとして確認や管理を行うことはできません。あくまでEBSスナップショットは内部的にS3に保存されている、というかたちです。

instance store-backedなAMIの作成

ところでこのCreateImageでAMIが作成できるのはEBS-backedなインスタンスだけです。いまではあまり使われることはありませんが、EC2インスタンスにはinstance store-backedというタイプもあります。instance store-backedはルートボリュームがインスタンスストアで構成されており、Amazon EC2のサービス開始当初(2006年)から使われていたものです。かつて「EC2ではインスタンスを停止するとデータが消えてしまう」といわれていたのはこのinstance store-backedの話ですね。

そんなinstance store-backedですが、AMIの作成についてもEBS-backedとは違いがあります。具体的にはec2-ami-toolsというツールを使い、ec2-bundle-volコマンドでAMIのバンドルを作成、ec2-upload-bundleというコマンドでAMIをS3にアップロードします。このec2-upload-bundleコマンド使用の際には、--bucketオプションで保存するS3バケットならびにパスを指定します。保存先のS3バケットやパスを意識しないCreateImageによるEBS-backedなAMI作成とくらべて、このinstance store-backedなAMIの作成のほうが、実際にS3保存している、という実感は高かったのかなと思います。

またinstance store-backedなAMIは具体的にS3内のオブジェクトとして確認が可能なようでした。「ようでした」、と断言を避けているのは、実は筆者がこのinstance store-backedなAMIを作成したことがないからですね……。(instance store-backedなインスタンスを使ったことはあるのですが。)「ami s3 保存」などのキーワードでGoogleすると以下のページなど、instance store-backedなAMIの作成に関するページがみつかりますので、これらから操作をイメージしています。

EBS-backedなAMIをS3にオブジェクトとして保存する

さてここからが本題です。再掲する以下ドキュメントにある通り、現在はS3を使った(EBS-backedな)AMIの保存ならびに復元方法が確立されています。

もう少し具体的に確認してみましょう。上記ドキュメントの冒頭には以下のように書かれています。

Amazon マシンイメージ (AMI) を Amazon S3 バケットに保存し、AMI を別の S3 バケットにコピーして、S3 バケットから復元できます。S3 バケットを使用して AMI を保存および復元することで、AMI をある AWS パーティションから別のパーティション (例えば、主要な商用パーティションから AWS GovCloud (US) パーティション) にコピーできます。AMI を S3 バケットに保存することで、AMI のアーカイブコピーを作成することもできます。

S3 を使用して AMI を保存および復元する - Amazon Elastic Compute Cloud

AMIのS3バケットへの保存が可能である旨、記載されています。そしてこのS3バケットはAWSが管理するもの(ユーザは確認できないもの)、という記載はありませんね。またこの(S3バケットに保存されているオブジェクトとしての)AMIを別のS3バケットへコピーできること、S3バケットからAMIを復元できることが記載されています。

また以下の通り、この「S3を使用してAMIを保存および復元する」ための3つAPIが紹介されています。

S3 を使用した AMI の保存および復元のサポート対象の API は、CreateStoreImageTaskDescribeStoreImageTasks、および CreateRestoreImageTask です。

S3 を使用して AMI を保存および復元する - Amazon Elastic Compute Cloud

なお、現在この「S3を使用してAMIを保存および復元する」操作はマネジメントコンソールでは対応しておらず、APIもしくはAWS CLIなどを使用する必要があります。また制限事項に記載がありますが、これらのAPIはEBS-backed AMIのみを対象としているとのことです。

実際にどのような手順でAMIをS3に保存、復元するかはのちほど確認するとして、この操作、APIについてはいつ頃から使えるようになったのか確認しておきましょう。

それらしきキーワードやCreateStoreImageTaskないしAWS CLIコマンド名create-store-image-taskなどで本DevelopersIOを検索しても、アップデート情報としてはでてきません。

("CreateStoreImageTask" OR "create-store-image-task" ) site:dev.classmethod.jp - Google 検索

外部サイトですがAWS API Changesで調べてみると、2021/04/06付でAPIが追加されていることが確認できました。

該当するドキュメントページについても確認してみましょう。Internet Archive Wayback Machineで確認してみると、2021/05/07が最も古いアーカイブとなっていました。

Wayback Machine

Store and restore an AMI using S3 - Amazon Elastic Compute Cloud - Wayback Machine 2021/05/07

この時期のAWS What's Newも確認してみましょう。「AWS GovCloud、AWS 中国、その他の AWS リージョン間で Amazon マシンイメージのコピーが可能に」という、一見すると「S3 を使用して AMI を保存および復元」という機能とは関係なさそうなタイトルですが、該当するアップデートとして以下がありました。(このタイトルについては、ユースケースとあわせてのちほど確認します。)

ということで、「S3を使用してAMIを保存および復元」する機能については、 2021/04/06に利用可能になっていた! ということになります。

S3を使用してAMIを保存および復元する機能のユースケースと使用するメリットを探る

「S3を使用してAMIを保存および復元する」機能について、ドキュメントの記載や利用可能になった時期などを確認してみました。ところで、そもそも内部的にはS3に保存されているAMIを、あえて明示的にS3にオブジェクトとして保存することの意義はどこにあるのでしょうか?ドキュメントにはこの答えとなる2つのユースケースについても記載されています。

あるAWSパーティションから別のAWSパーティションにAMIをコピーする

1つ目の「ある AWS パーティションから別の AWS パーティションに AMI をコピーする」から確認してみましょう。まず「 パーティション 」というキーワードが出てきますね。この パーティション ですが、IAMユーザガイドによるとARNの2番めに示されている要素で、AWSのリージョンのグループを示すもの、ということです。

  • arn:partition:service:region:account-id:resource-id

具体的にサポートされているパーティションとしては以下3種となります。

  • aws - AWS リージョン
  • aws-cn - 中国リージョン
  • aws-us-gov - AWS GovCloud (US) リージョン

私はふだん意識したことはなかったのですが(基本的にARNはarn:awsではじまるものだと思っていました)、中国リージョンやAWS GovCloudリージョンを使用する場合はこのパーティションという単位で別のリソースだったわけですね。そしてこの「パーティション」が別であると、通常のAMIのリージョン間コピーCopyImage)ができません。 パーティション間でのコピーを行うために準備されたのがこの「S3を使用してAMIを保存および復元する」機能、CreateStoreImageTaskなどからなる3つのAPI、というわけですね。

このユースケースを踏まえると、先ほどのAWS What's Newでのアップデートのタイトルについても納得です。

AMIのアーカイブコピーを作成する

続いて2つ目のユースケース、「AMI のアーカイブコピーを作成する」についても確認してみましょう。そのままズバリ、AMIのコピーをS3にオブジェクトとして保存する、というユースケースですね。このメリットとしては、 より安価なS3ストーレジクラスを利用して、AMI保存の費用コストの削減が可能 ということとなります。

AMI保存の料金について確認してみましょう。以下にポイントとなる容量単価についてまとめます。標準ストレージクラスを利用する場合、S3を利用することでAMI(EBSスナップショット)とくらべて半額の費用での保存が可能になります。またEBSスナップショットのアーカイブクラスを使うことで標準S3クラスよりも安価にはなりますが、S3でもアーカイブ向けのストレージクラスを使うことで、より安価に保存が可能です。(そもそもEBSスナップショットのアーカイブクラスはAMIに関連付けられているスナップショットをアーカイブすることはできないという制限事項があります。また、アーカイブ向けストレージクラスについては取り出す操作に費用がかかるなど容量単価以外の料金が発生することなどにご注意ください。)

  • 容量単価(東京リージョン、2023/06/22時点)
    • AMI(EBSスナップショット)
      • スタンダード: $0.05/GB/月
      • アーカイブ: $0.0125/GB/月
    • S3
      • S3 標準: $0.025/GB/月
      • S3 Glacier Deep Archive: $0.002/GB/月

異なるAWSパーティション(中国リージョンやAWS GovCloudリージョン)を利用しない前提の場合、この より安価なS3ストレージクラスでの保存が可能である 点が、S3を使用してAMIを保存および復元する機能の一番のメリットかと考えます。

またドキュメントなどでユースケースとしての案内はなく、私のほうで実際の検証も行っていないのですが、理論上はS3からオンプレ機器になどにオブジェクトを移動しAWSでのデータ保存料金を抑える、AWS以外をAMIのバックアップ場所として使う、ということも実現できるのかなと推測します。もちろんS3からのエクスポート、インポートなど手間が生じるなど、管理コストが発生するのでトータルでコストダウンになるのかはわかりません。どうしてもAWS以外でAMIを保存しておきたい、という場合には検討できる可能性があります。

EBS-backedなAMIをS3に保存・復元してみた

「S3を使用してAMIを保存および復元する」機能のユースケースやそのメリットについての確認ができたところで、実際にこの機能を使ってAMIをS3のオブジェクトとして保存、そこからの復元をしてみたいと思います。

EC2インスタンスの作成からAMIの取得

まずはベースとなるAMIからEC2インスタンスを起動します。EC2マネジメントコンソールの[Launch instances]ボタンからAmazon Linux 2023 AMIを選択しました。(ami-089d1a3bd554f6a4b/al2023-ami-2023.0.20230614.0-kernel-6.1-arm64))VPCなどの設定を行い[Launch instances]します。EBS Volumeについてはgp3のデフォルト状態で利用、暗号化などは設定していません。

EC2インスタンス起動後、動作確認用としてホームディレクトリにファイルを置いておきます。

[ec2-user@ip-10-82-21-14 ~]$ ls -l
total 0
[ec2-user@ip-10-82-21-14 ~]$ echo "Store and restore an AMI using S3." > ami-store-restore.txt
[ec2-user@ip-10-82-21-14 ~]$ ls -l
total 4
-rw-r--r--. 1 ec2-user ec2-user 35 Jun 22 06:52 ami-store-restore.txt
[ec2-user@ip-10-82-21-14 ~]$ cat ami-store-restore.txt
Store and restore an AMI using S3.

その後、このEC2インスタンスからAMIを作成します。

AMIが取得できました。StatusがPendingからAvailableに変わったら準備完了です。

AMIのS3への保存

このAMIをS3バケットに保存してきます。S3バケットはマネジメントコンソールのデフォルト設定で作成しました。AMIの保存前はオブジェクトのない、空の状態のS3バケットです。

「S3を使用してAMIを保存および復元する」操作はマネジメントコンソールでサポートされていないため、AWS CLIを用いて実行します。本エントリで検証に使用したAWS CLIのバージョンは下記となります。

% aws --version
aws-cli/2.11.21 Python/3.11.3 Darwin/21.6.0 exe/x86_64 prompt/off

AMIのS3バケットへの保存にはec2 create-store-image-taskコマンドを使用します。オプションでS3に保存するAMIのID、そして保存先となるS3バケットを指定します。コマンドが成功すると、S3上のAMIオブジェクトのKeyが返ります。

% aws ec2 create-store-image-task \
    --image-id ami-0f23xxxxxxxxxxxxx \
    --bucket ami-store-s3-bucket-xxxxxxxxxxxx
{
    "ObjectKey": "ami-0f23xxxxxxxxxxxxx.bin"
}

AMIのS3への保存は瞬時に行えるわけではなく、タスクに時間がかかります。この進行状況を確認するのがec2 describe-store-image-tasksコマンドです。

create-store-image-taskコマンド実行直後にdescribe-store-image-tasksコマンドを実行した結果が以下となります。オプションなしで実行できますが、その際には直近以外のタスクについても表示される点に留意しましょう。

% aws ec2 describe-store-image-tasks
{
    "StoreImageTaskResults": [
        {
            "AmiId": "ami-0f23xxxxxxxxxxxxx",
            "TaskStartTime": "2023-06-22T08:53:19.110000+00:00",
            "Bucket": "ami-store-s3-bucket-xxxxxxxxxxxx",
            "S3objectKey": "ami-0f23xxxxxxxxxxxxx.bin",
            "ProgressPercentage": 0,
            "StoreTaskState": "InProgress",
            "StoreTaskFailureReason": ""
        },
        {
            "AmiId": "ami-xxxxxxxxxxxxxxxxx",
            "TaskStartTime": "2023-06-19T11:39:58.618000+00:00",
            "Bucket": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "S3objectKey": "ami-xxxxxxxxxxxxxxxxx.bin",
            "ProgressPercentage": 100,
            "StoreTaskState": "Completed",
            "StoreTaskFailureReason": ""
        },
        {
            "AmiId": "ami-xxxxxxxxxxxxxxxxx",
            "TaskStartTime": "2023-06-19T11:37:25.370000+00:00",
            "Bucket": "xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx",
            "S3objectKey": "ami-xxxxxxxxxxxxxxxxx.bin",
            "ProgressPercentage": 100,
            "StoreTaskState": "Completed",
            "StoreTaskFailureReason": ""
        }
    ]
}

今回実行したAMI ID ami-0f23xxxxxxxxxxxxxに対するタスクが一番上に表示されていますね。"StoreTaskState": "InProgress"となっています。1分ほどして再度コマンドを実行すると"Completed"となっていました。なお--image-idsオプションでAMI IDを指定して該当AMI IDのタスクのみを表示させることが可能です。

% aws ec2 describe-store-image-tasks \
    --image-ids ami-0f23xxxxxxxxxxxxx
{
    "StoreImageTaskResults": [
        {
            "AmiId": "ami-0f23xxxxxxxxxxxxx",
            "TaskStartTime": "2023-06-22T08:53:19.110000+00:00",
            "Bucket": "ami-store-s3-bucket-xxxxxxxxxxxx",
            "S3objectKey": "ami-0f23xxxxxxxxxxxxx.bin",
            "ProgressPercentage": 100,
            "StoreTaskState": "Completed",
            "StoreTaskFailureReason": ""
        }
    ]
}

create-store-image-taskコマンド実行時に指定したS3バケットを確認してみましょう。以下のようにami-0f23xxxxxxxxxxxxx.binというオブジェクトが作成されていました。これがS3に保存したAMIとなるわけですね。

S3に保存されたAMIを復元

AMIをS3に保存することができたので、このS3オブジェクトからAMIを復元してみます。別パーティションでの復元は試すことができなかっため、今回はAMIをS3に保存したのとは別のAWSアカウント、そして別のリージョンで行ってみます。(S3への保存は東京リージョンで行ったため、復元はオレゴンリージョンを使用します。)

まずは別AWSアカウントでAMI復元に用いるS3バケットを作成します。S3バケットについても復元するリージョン(us-west-2)で作成します。

このS3バケットへのオブジェクトのコピーですが、手元のMacにいちどS3オブジェクトをダウンロードし、マネジメントコンソールからアップロードするかたちで行ってみます。ダウンロードもS3のマネジメントコンソール、[Download]ボタンで行いました。

AMIがローカルのラップトップにある、というのも新鮮ですね。(2年前からできていましたが……。)

復元用のAWSアカウント、us-west-2リージョンのS3バケットにアップロードしました。なおアップロードが完了した段階で、AMIをS3に保存したオブジェクトは削除しています。

それではS3バケットに保存されているS3オブジェクトからAMIを復元します。ec2 create-restore-image-taskコマンドを利用します。オプションでS3のバケット名ならびにオブジェクト名、そしてAMI Nameを入力します。コマンドが成功するとAMI IDが返ります。復元されたAMIは新しいAMI IDが割り振られる点に注意しましょう。

% aws ec2 create-restore-image-task \
    --object-key ami-0f23xxxxxxxxxxxxx.bin \
    --bucket ami-restore-s3-bucket-xxxxxxxxxxxx \
    --name ami-restore-amazon-machine-image \
    --region us-west-2
{
    "ImageId": "ami-0332xxxxxxxxxxxxx"
}

コマンド実行後、マネジメントコンソールでAMIの一覧を確認すると該当AMIが作成中であることが確認できました。EC2からのAMI取得と同様、AMI作成完了まで少し時間を要するかたちです。

AMIのステータスが利用可能になったら、通常と同じ手順でこのAMIからEC2インスタンスを起動してみます。[AMI からインスタンスを起動]ボタンで進みました。

[インスタンスを起動]します。無事に起動できました!

動作確認用のファイルも確認してみましょう。しっかり残っていますね。

[ec2-user@ip-172-31-48-189 ~]$ ls -l
total 4
-rw-r--r--. 1 ec2-user ec2-user 35 Jun 22 06:52 ami-store-restore.txt
[ec2-user@ip-172-31-48-189 ~]$ cat ami-store-restore.txt
Store and restore an AMI using S3.

まとめ

AMIをS3に明示的なオブジェクトとして保存、そこから復元できる機能について詳細を確認しつつ、実際に操作を行ってみました。永らくEBS-backedなAMIはS3に明示的なオブジェクトとして保存はできず、AWSの管理するS3バケットに保存されユーザは確認や管理ができないもの、と思っていたので、2021年4月からこの機能が使えていたことに大変驚いています。またいまだにEBSスナップショット単体ではS3への明示的なオブジェクトとしての保存・コピーはサポートされていない認識です。AMIとしてならS3に保存可能、というのも興味深いですよね。確認してきた通りユースケースとしては、AWS中国リージョンやGovCloudリージョンといった別のパーティションへのコピー、そしてより安価なS3ストレージクラスを利用したAMI保存の費用コストの削減ということになります。一般的には後者の費用コスト最適化の際に検討となるかなと思いますが、S3にアーカイブコピーを行うとなると管理コストは増大するのかなと思います。ドキュメント記載の制限事項にも注意しつつ、長期に渡って使うかどうかわからないけど一応残しておきたい、というようなAMIのみに使用は限定するなど、上手に活用したい機能だなと思いました。