【AWS】S3のバージョニングを超絶わかりやすく解説する

## はじめに
S3のバージョニングについて理解が浅いと感じたため、内容をちゃんと理解したいと思い備忘として書き留めます。
正直申し上げますと、AWS公式の情報を見ればご丁寧に説明されていますので、公式の情報で十分という方はそちらをご覧になった方が良いかと思います。
https://docs.aws.amazon.com/ja_jp/AmazonS3/latest/userguide/versioning-workflows.html

## バージョニングのステータス
S3のバージョニングのステータスには以下3つの状態があります。
- 有効
- 無効
- 停止


## 有効の場合
わかりやすく図解します。
バージョニングを有効にするとオブジェクトに対してバージョンIDが付与されます。
バージョニングが有効にされる前にオブジェクトが格納されていた場合には`null`値となります。
バージョニングを有効化後、既にS3に格納されている`test.txt`と同じ名称のオブジェクトを`Put`すると以前のtest.txtは以前のバージョンとされ、`Put`された`test.txt`が現行バージョンとしてバージョンID: 101が付与されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/719d09cd-f9f8-bac6-c14f-3d8318c74e09.png)

さらに、同じ名称のオブジェクトを`Put`するとバージョンIDが更新され、バージョンID 102が現行バージョンとなり、101は以前のバージョンのオブジェクトとして管理されます。
つまり、同じ名称のオブジェクトを`Put`してもオブジェクトは上書きされず、バージョン管理されバケットに残ります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/40e0082a-220a-2408-a65f-07699444043a.png)

実際に動きを見てみましょう。

バージョニングを有効化すると、バケットのオブジェクトタブに[バージョンの表示]という表記がされるようになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/5f6c8540-0429-4fbf-9afb-fc79a9fbd82e.png)

現状、`null`のバージョンIDが付与されたオブジェクトが格納されています。
全く同じ`test.txt`を`Put`してみます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/5d8af39a-e4f4-4672-815e-7f19b0ca93d9.png)

全く同じ`test.txt`を`Put`した結果が以下です。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/88445cab-aae2-4a13-a8bd-0fbb2f81dbd1.png)
もともと存在していたバージョンID: `null`の`test.txt`と現行のバージョンのバージョンIDが付与された`test.txt`がオブジェクトが存在します。

さらにもう一度`test.txt`を`Put`してみます。
さらに以前のバージョンに`null`と`KpZsu6m4QNS8Cr.iSEbCRHukXnTwAkje`が移動し、現行のバージョンIDに`KlczlM9kUhWDAYLmigKxaQpLlXCxJZgg`というIDが付与されました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/0e4b6536-d179-45e0-b6ca-e9ceb6ef83f9.png)

これが図解した実際のバージョニングの動きになります。

### 有効にした場合のメリット
誤って対象オブジェクトを削除してしまった場合に、以前バージョンのオブジェクトを取得できることがバージョニングを有効化にしてるメリットです。
オブジェクトを削除してしまった場合、どのような動きになるかというと、`削除マーカー`と呼ばれる削除フラグが付きます。いわゆる論理削除ですね。


### 削除マーカーとは
バージョニングが有効化されたオブジェクトでオブジェクトの削除を実行すると、見た目上はオブジェクトが削除されたように見えますが、現行のバージョンIDのオブジェクトは実際には削除されません。
先ほどお話した`削除マーカー`のフラグが付与され、現行のバージョンが以前のバージョンに移動し、`削除マーカー`のついたオブジェクトが現行のバージョンとなります。

図解します。
現行バージョンであるバージョンID: 102のオブジェクトを削除します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/11abfee0-43d3-4b93-af0a-18b93b7f82cd.png)

バージョンID: 102は以前のバージョンに移動し、新たにバージョンID: 103のバージョンIDが付与された、かつ`削除マーカー`フラグのついたオブジェクトが現行のバージョンとなります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/b87f9f2a-f44a-49b8-8414-e69042d5c2ed.png)


実際にどういう動きをするか見てみましょう。

現行バージョンのオブジェクトを削除してみます。
オブジェクトの削除を実行すると[指定したオブジェクトを削除すると、`削除マーカー`が追加されます。]といういメッセージが表示され、対象オブジェクトに対して`削除マーカー`を付与する動きになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/beb9292d-a9d5-49d4-bace-d1097d080b12.png)

テキストフィールドに[削除]と入力し、[オブジェクトの削除]をしてみます。

オブジェクトが削除されると、[バージョンの表示]を無効にしている状態だと、あたかもオブジェクトがなくなっているように見えますが、[バージョンの表示]を有効にすると、`削除マーカー`のフラグが立ち、現行のバージョンとして存在することになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/5e36739b-78b7-4d2e-b974-015e1d0300d8.png)


![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/ea2e919e-0ef1-442a-82af-8afa98bd596a.png)

オブジェクトのバージョン情報を確認すると、`削除マーカー`フラグのついたオブジェクトが現行のバージョンとなっていることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/47d409e5-fceb-403a-9d69-401bf9dc4a3e.png)

では、論理削除してしまったオブジェクトはどのようにして復元するのでしょうか？

### 復元方法
やり方は簡単です。
方法は2つあります。
- `削除マーカー`のオブジェクトを完全に削除して以前のバージョンを現行のバージョンにする(この場合、以前のバージョンの最新のバージョンのものが復元されます)
- 復元したいバージョンIDのオブジェクトをダウンロードして、新たに`Put`する (この方法だと特定のバージョンIDを指定して復元することが可能)


### `削除マーカー`のオブジェクトを完全に削除して以前のバージョンを現行バージョンにする
`削除マーカー`のオブジェクトを完全に削除すると、以前のバージョンの最新バージョンが繰り上がることになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/f0695038-1cb2-413f-b736-27e5f32faecb.png)

実際に`削除マーカー`のオブジェクトを削除してみます。
オブジェクトを[完全に削除]するかどうかを聞かれるので、テキストフィールドに[完全に削除]を入力すると、文字通り完全に削除されます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/566ec771-20cf-4664-b64f-a311cb0f2eb8.png)

想定通り、以前のバージョンとして存在していた最新のバージョンが現行バージョンとして君臨することになりました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/699b79bc-c225-4cb9-afff-de841b7d7761.png)

[バージョンの表示]を無効化状態にすると、オブジェクトが復活しています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/196f20d5-1dc2-47c3-81f6-c19294f6221b.png)

### 復元したいバージョンIDのオブジェクトをダウンロードして、新たに`Put`する

この場合、特定のバージョンIDのオブジェクトを新たに`Put`することで特定のオブジェクトを復元することができます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/35df960d-8dfd-43f3-b7ed-97319aff98d0.png)

ただし、動きとしては、バージョンID: 102をダウンロードして新に`Put`した場合、新たに`Put`されたオブジェクトに最新のバージョンIDが付与され、`削除マーカー`フラグのついたオブジェクトは以前のバージョンに移動することになります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/1ff40ca4-778d-4243-a167-376afab00429.png)


実際に以前のバージョンをダウンロードして、`Put`してみましょう。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/95fbcf35-d984-40c5-9b93-8d070620e561.png)

`Put`した結果は以下です。
[バージョンの表示]を無効化状態で表示すると、オブジェクトが復元されています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/4ce10571-e17d-4b9d-bb4c-7158a82f9c63.png)

新たに最新のバージョンIDが付与されたオブジェクトが現行のバージョンとなり、`削除マーカー`についたオブジェクトは以前のバージョンになっていることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/2fdfcbfa-2ed7-4c23-b0ba-65f41538251d.png)

ここまででバージョニングの有効状態がどういう動きをするか？削除した場合はどうなるのか？復元方法、などが理解できたかと思います。

## 無効/停止の場合
バージョニングの無効と停止の動きを見てみましょう。
私は最初、停止なら無効状態と同じでは？と思っていましたが、若干挙動に違いがありましたのでここで整理したいと思います。

AWS公式にもある通り、バージョニングが有効ではない場合、オブジェクトのバージョンIDは`null`に設定します。
無効状態のバケットに対してオブジェクトを`Put`すると、特定のバージョンIDは付与されません。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/207303dc-01e4-4a16-9e19-b31813f79863.png)

よって、同じ名称のオブジェクトを`Put`すれば上書きされますし、削除すればそのまま[完全に削除]されます。
当然`削除マーカー`も付与されません。


では停止状態はどうでしょうか？
先ほどの有効化していたバケットのバージョニングを停止にします。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/9f1eb127-8032-4902-bf55-591e72ac7440.png)

停止状態でオブジェクトを`Put`してみます。
現行のオブジェクトが存在します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/c44413cc-7a35-47db-9fc0-28e49ec304f5.png)

[バージョンの表示]を有効にし、オブジェクトを確認すると、バージョンID: `null`が付与されたオブジェクトが存在します。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/234b4839-cf24-4861-b82a-2f7b7466d42e.png)

このオブジェクトを削除してみましょう。
[完全に削除しますか？]のメッセージが表示され、[完全に削除]するのですが…
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/5952008c-6e06-4d1c-9961-06861d3814d2.png)

実際は完全に削除されず、`削除マーカー`が付与され、バージョンID: `null`のバージョンが実際には残っています。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/a7e20417-0c4b-4fb8-b11f-82bfe72f4a41.png)

ここが無効と停止の大きな違いになるかと思います。
停止状態のバケットは見た目上はオブジェクトが存在しないように見えるのですが、実際には`削除マーカー`フラグのオブジェクトが存在しており、バケットを削除しようとすると、以下のように[バケットが空ではありません]というメッセージが表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/379725/a4d35ca9-e98f-4b96-824c-02504192b6c4.png)

無効と停止ではここに違いがあるため、料金の違いも出てくるため注意が必要となります。

## まとめ
バケットのバージョニングの各ステータスについて解説しました。
それぞれの状態の動作にはそれぞれ違いがあるということが分かったかと思います。
細かい設定内容の違いですが、動作確認してみると意外に奥が深いことがわかりますね。