S3でファイルを削除したはずなのに、課金が減らない、バージョン一覧を見ると何か残っている。バージョニングを有効にしたバケットでよく起きるこの現象の正体が「削除マーカー」です。
この記事では、バージョニング有効なバケットに同じファイルを2回上書き保存してから削除し、内部に何が残るのかを実際に検証しました。
なお、検証はAWS APIのモックライブラリ「moto」(バージョン5.2.5)の上で行っています。削除マーカーの仕様は公式ドキュメントで定められたもので、実AWSでも同じです。
検証環境
- Python + boto3 1.43.123
- moto 5.2.5(AWS APIのモック)
- リージョン設定:ap-northeast-1
- バージョニングを有効化したバケットに、同じキー
a.txtを2回保存(内容は v1、v2)してから削除
検証コードと実行結果
import boto3
s3 = boto3.client("s3", region_name="ap-northeast-1")
s3.create_bucket(
Bucket="ver-bucket",
CreateBucketConfiguration={"LocationConstraint": "ap-northeast-1"},
)
s3.put_bucket_versioning(
Bucket="ver-bucket",
VersioningConfiguration={"Status": "Enabled"},
)
s3.put_object(Bucket="ver-bucket", Key="a.txt", Body=b"v1")
s3.put_object(Bucket="ver-bucket", Key="a.txt", Body=b"v2")
s3.delete_object(Bucket="ver-bucket", Key="a.txt") # バージョンIDなしの削除
lst = s3.list_objects_v2(Bucket="ver-bucket")
print("削除後の一覧:", len(lst.get("Contents", [])))
vers = s3.list_object_versions(Bucket="ver-bucket")
print("残っているバージョン:", len(vers.get("Versions", [])))
print("削除マーカー:", len(vers.get("DeleteMarkers", [])))
実行結果はこうなりました。
削除後の一覧: 0
残っているバージョン: 2
削除マーカー: 1
通常の一覧では0件、つまり「消えた」ように見えます。しかし内部には、v1とv2の2つのバージョンがそのまま残り、さらに削除マーカーが1件追加されていました。加えて検証では、旧バージョンのIDを指定して get_object すると、削除前の内容(v2)を取得できることも確認しています。
何が起きているのか
バージョニングが有効なバケットでは、バージョンIDを指定しない削除は「実体を消す操作」ではありません。「最新バージョンの位置に、削除マーカーという目印を立てる」操作です。
- 一覧や通常の取得では、最新が削除マーカーなので「存在しない」ものとして扱われる(取得すると404になる)
- 過去のバージョンは課金対象のまま残り続ける
- 復旧したいときは、削除マーカー自体を削除すれば、直前のバージョンが最新に戻る
- 完全に消したいときは、バージョンIDを指定して各バージョンと削除マーカーを明示的に削除する必要がある
「削除したのに容量が減らない」場合、まず疑うべきはこの仕組みです。
実務で使うときの注意点
- 過去バージョンを残す期間は、ライフサイクルルール(NoncurrentVersionExpiration)で自動的に期限を切るのが定番です。放置すると容量課金が静かに増え続けます
- 削除マーカーだけが残った状態(期限切れ削除マーカー)も、ライフサイクルの
ExpiredObjectDeleteMarkerで自動掃除できます - バケットを丸ごと消すときは、全バージョンと削除マーカーを消してからでないとバケット削除ができません
- 検証で使った
list_object_versionsは、棚卸しのときに「見えない実体」を数える手段として使えます
まとめ
- バージョニング有効時の削除は実体削除ではなく、削除マーカーの追加です
- 今回の検証では、削除後に一覧0件でも2バージョン+1マーカーが残ることを確認しました
- 容量をきちんと管理するには、ライフサイクルルールでの自動整理が欠かせません
参考リンク
- Amazon S3 ユーザーガイド「バージョニングを有効にしたバケットからオブジェクトのバージョンを削除する」: http://docs.aws.amazon.com/AmazonS3/latest/userguide/DeletingObjectVersions.html
- Boto3「S3.Client.head_object」(削除マーカー時の応答の説明): https://docs.aws.amazon.com/boto3/latest/reference/services/s3/client/head_object.html