AWSのS3にバージョニング機能があるので、試しにいろいろ使ってみました。
S3バケットのバージョニングとは
AWSのドキュメントには以下のように書いてあります。
Amazon S3 のバージョニングとは、同じバケット内でオブジェクトの複数のバリアントを保持する手段のことです。S3 のバージョニング機能を使用すると、バケットに保存されたすべてのオブジェクトのすべてのバージョンを、保存、取得、復元することができます。バージョニングを使用すれば、意図しないユーザーアクションからもアプリケーション障害からも、より簡単に復旧できます。バケットのバージョニングを有効にすると、Amazon S3 が同じオブジェクトに対する複数の書き込みリクエストを同時に受信した場合に、すべてのオブジェクトが保存されます。
バージョニングを有効にしたバケットは、オブジェクトを誤って削除したり上書きしたりしても、復元が簡単に行えます。例えば、オブジェクトを削除した場合、Amazon S3 は、オブジェクトを完全に削除する代わりに削除マーカーを挿入します。その削除マーカーが、最新のオブジェクトバージョンになります。オブジェクトを上書きすると、バケット内の新しいオブジェクトバージョンになります。いつでも以前のバージョンを復元できます。詳細については、「バージョニングが有効なバケットからのオブジェクトバージョンの削除」を参照してください。
実際に使ってみる
では、早速使ってみたいと思います。
バージョニングの有効化
S3ベケットでバージョニングを有効にする必要があります。
バケット作成時にバージョニングを有効にします。
または、作成されたバケットをあとから変更することもできます。
バケットのプロパティから編集ができます。
アップロードする
以下のようなテキストファイルを用意してみました。
$ cat test.txt
hello world
このファイルをアップロードするためには、AWSのマネジメントコンソール上にファイルをドラッグ・アンド・ドロップするだけ。
このとき、新規ファイルをアップロードしただけなので、バージョンは1つになっていることが確認できます。
中身を書き換えてアップロードする
中身を書き換えました。
$ cat test.txt
World Hello!
差分はこういう感じです。
- hello world + World Hello!
もう一度ドラッグ・アンド・ドロップします。
ファイル自体は1つに見えますが、バージョンを確認すると以下のように2つ存在することが確認できます。
文字数を変えているので、ファイルサイズも変わっていることが確認できますね。
オブジェクトバージョン(VersionId)を取得する
Amazon S3コンソール上ではバージョンを確認することができましたが、実際に利用する場合は、プログラムからバージョン情報を取得できると良いですよね。
まずは、AWS CLIを利用して取得してみます。
こちらのサイトに書いてあるs3apiのlist-object-versionsを利用してみます。
いろいろと文字を置き換えていますが、以下のような感じで実行し、情報を取得することができました。
$ aws s3api list-object-versions --bucket my-bucket --prefix test { "Versions": [ { "LastModified": "2022-01-05T07:53:19.000Z", "VersionId": "HeAtEla5LLV2yPXtVpo4L7YPywbXdD.Q", "ETag": "\"XXXXXXXXXXXXXXXXX\"", "StorageClass": "STANDARD", "Key": "test.txt", "Owner": { "DisplayName": "XXXXXXXXXXXXXXXXX", "ID": "XXXXXXXXXXXXXXXXX" }, "IsLatest": true, "Size": 13 }, { "LastModified": "2022-01-05T07:49:12.000Z", "VersionId": "pDsmB9yx7XihsrPQNy8gpXvgRzv8VEbw", "ETag": "\"XXXXXXXXXXXXXXXXX\"", "StorageClass": "STANDARD", "Key": "test.txt", "Owner": { "DisplayName": "XXXXXXXXXXXXXXXXX", "ID": "XXXXXXXXXXXXXXXXX" }, "IsLatest": false, "Size": 12 } ] }
実行してみて思ったこと。
- 対象ファイルのバージョンを取得する方法として、ファイルの絞り込みは
prefix
を使わないといけないのかな。 isLatest
がtrue
のものが最新のもの
なので、もしS3に配置しているファイルのVersionIdが知りたい場合はこの方法だとよくなさそう?似たようなファイルがたくさんあったり、大量のバージョンで管理されている場合だとレスポンスが巨大になったりページネーションを利用しないといけないのでちょっとめんどくさそう。うまくprefixなどで対象ファイルを絞る必要がありそうですね。
PHPでlistObjectVersions()を用いて取得する例
PHPのソースコードだとどのように書くかも試したいと思います。
今回はaws/aws-sdk-php
を用いて操作したいと思います。
<?php $s3_client->listObjectVersions([ 'Bucket' => 'my-bucket', 'Prefix' => 'test', ])->get('Versions')
S3ClientクラスのlistObjectVersions()
を利用することで、バケットのオブジェクトを取得でき、その中のVersions
に配列で含まれます。
cliのコマンドに似た名前のメソッド名だったりレスポンスなのでわかりやすいかと思います。
オブジェクト配置時にVersionIdを取得する
配置されたものに対してVersionIdを取得する方法はなんとなくわかり、ただ用途によってはちょっと使いにくそうなことも感じました。
では、次に、S3にオブジェクトを配置するときにVersionId
を取得する方法を試したいと思います。
$ aws s3api put-object --bucket my-bucket --key test.txt --body test.txt { "ETag": "\"XXXXXXXXXXXXXXXXX\"", "VersionId": "jWu9C3PE9k3K_ZzHXleNud4hShj87Tdn" }
put-object
をする時のレスポンスボディにVersionId
が返ってきます。
S3コンソールを確認すると、レスポンスボディに含まれるVersionId
が現行バージョンとして存在することが確認できます。
配置するときにVersionId
が取得できるので、例えば配置の度にどこかDBなどにVersionIdを記録しておけば、あとからlist-object-versionsを利用して取得する必要はなさそうですね。
PHPでputObject()したときのVersionIdの取得例
putObject()
の戻り値から確認することができます。
<?php $result = $s3_client->putObject([ 'Bucket' => 'my-bucket', 'Key' => 'test', 'Body' => $body, 'ContentType' => 'text/plain; charset="UTF-8"', ]);
$result
にputした結果の情報がいろいろ含まれるのですが、その中のVersionId
という項目で格納されます。
$version_id = $result->get('VersionId');
そのため、このようにget()
を呼ぶことでVersionId
が取得できます。
VersionIdを指定してS3からオブジェクトを取得
まず、現状アップロードされているのをまとめておきます。
VersionId | test.txtの中身 |
---|---|
pDsmB9yx7XihsrPQNy8gpXvgRzv8VEbw | hello world |
HeAtEla5LLV2yPXtVpo4L7YPywbXdD.Q | World Hello! |
jWu9C3PE9k3K_ZzHXleNud4hShj87Tdn(現行バージョン) | World Hello! |
なので、まずはそのまま取得しようとすると、現行バージョンのものが取得できます。
$ curl https://url/test.txt
World Hello!
「hello world」を取得する場合は、versionIdをリクエストパラメータに追加してリクエストします。
$ curl https://url/test.txt?versionId=pDsmB9yx7XihsrPQNy8gpXvgRzv8VEbw hello world
このとき、Access Denied
になる場合は、アクセス許可のバケットポリシー等を確認してみましょう。自分の場合は、S3のバケットをパブリックにアクセス可能にするときにGetObject
しか設定しなかったのですが、バージョンを指定して取得する場合はGetObjectVersion
を指定しないといけないようです。
バージョン固有のオペレーションでは、IAM ID にバージョン固有のアクションに対するアクセス権限があることを確認します。例えば、オブジェクトの特定のバージョンをコピーするには、s3:GetObject に加えて s3:GetObjectVersion に対するアクセス権限が必要です。
最後に
このように、S3に配置するファイルのバージョン管理ができ、各バージョンにアクセスするためのversionId
を取得することもできました。
これをうまく利用すれば、ゲームのアセットデータやマスタデータのバージョン管理の手助けになりそうですね。