S3のライフサイクル設定とは、「作成から何日たったオブジェクトを削除する」「別のストレージクラスへ移す」といったルールをバケットに登録し、S3に自動で実行してもらう仕組みです。 AWS CLI では、ルールを書いた JSON ファイルを aws s3api put-bucket-lifecycle-configuration に渡すだけで設定できます。

この記事では、よく使う8種類のルールをそのまま貼れる JSON として並べ、put / get / delete の CLI と boto3、get の出力、put が全ルールの置き換えになる挙動、MalformedXML になる書き方と直し方を、実行結果つきでまとめました。

確認環境:Ubuntu 24.04、AWS CLI 1.46.1、Python 3.11.15、boto3 1.43.103、jq 1.7。AWS の API をローカルで再現するツール(moto 5.2.3)で実行しています。掲載するコマンドは、実際の AWS でそのまま使える形(エンドポイント指定なし)で書いています。

S3ライフサイクル設定の早見表

やりたいこと 使うキー JSON の要点
作成から N 日で自動削除 Expiration.Days "Expiration": {"Days": 90}
特定のフォルダだけ対象にする Filter.Prefix "Filter": {"Prefix": "logs/"}
タグが付いたものだけ対象にする Filter.Tag "Filter": {"Tag": {"Key": "retention", "Value": "temp"}}
大きいファイルだけ対象にする Filter.ObjectSizeGreaterThan バイト数で指定。ほかの条件と組むときは And で包む
ストレージクラスを段階的に移す Transitions {"Days": 30, "StorageClass": "STANDARD_IA"} を配列で並べる
旧バージョンを自動で消す NoncurrentVersionExpiration NoncurrentDays と NewerNoncurrentVersions
残った削除マーカーを消す Expiration.ExpiredObjectDeleteMarker "Expiration": {"ExpiredObjectDeleteMarker": true}
途中で止まったマルチパートを消す AbortIncompleteMultipartUpload {"DaysAfterInitiation": 7}
バケット全体を対象にする 空の Filter "Filter": {}
ルールを一時的に止める Status "Status": "Disabled"
操作 CLI boto3
設定する(全ルール置き換え) aws s3api put-bucket-lifecycle-configuration put_bucket_lifecycle_configuration
確認する aws s3api get-bucket-lifecycle-configuration get_bucket_lifecycle_configuration
すべて削除する aws s3api delete-bucket-lifecycle delete_bucket_lifecycle

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「S3ライフサイクル設定のJSON例集 自動削除・クラス移行CLI」

ルール1つの形(必ず書く4項目)

ライフサイクル設定は、Rules という配列にルールを並べた JSON です。ルール1つは次の4つでできています。

項目 役割 書き方
ID ルールの名前。一覧で見分けるために付ける 最大255文字。内容が分かる名前にする
Status 有効・無効 Enabled または Disabled
Filter 対象の絞り込み 全体なら {}。プレフィックス・タグ・サイズで絞る
アクション 何をするか Expiration、Transitions、NoncurrentVersionExpiration、AbortIncompleteMultipartUpload など

Filter は対象なしでも省略せず、空の {} を書きます。 省略するとエラーになります(後半の「エラーになる書き方」で実際の出力を載せます)。1つのバケットに登録できるルールは最大1,000個です。

コピペ用 JSON 例集

以降の JSON は、すべてファイルに保存して次のコマンドで設定できます。バケット名 example-logs-bucket とファイル名は置き換えてください。

aws s3api put-bucket-lifecycle-configuration \
  --bucket example-logs-bucket \
  --lifecycle-configuration file://lifecycle.json

成功すると何も表示されません(終了コード 0)。

例1:作成から90日で自動削除(バケット全体)

{
  "Rules": [
    {
      "ID": "expire-all-after-90-days",
      "Status": "Enabled",
      "Filter": {},
      "Expiration": { "Days": 90 }
    }
  ]
}

バージョニングを使っていないバケットでは、対象のオブジェクトがそのまま削除されます。バージョニングが有効なバケットでは、削除マーカーが付いて「見えなくなる」だけで、以前の版は残ります。容量を空けたいときは例6・例7を組み合わせます。

例2:プレフィックス限定(logs/ 以下だけ30日で削除)

{
  "Rules": [
    {
      "ID": "expire-logs-after-30-days",
      "Status": "Enabled",
      "Filter": { "Prefix": "logs/" },
      "Expiration": { "Days": 30 }
    }
  ]
}

Prefix はキーの先頭一致です。logs/ と末尾にスラッシュを付けると、logs-old/ のような似た名前を巻き込まずに済みます。逆に sales1999/、sales2000/ のように先頭が共通の複数フォルダをまとめたいときは、"Prefix": "sales" とスラッシュなしで書きます。

例3:タグで絞り込み(retention=temp を7日で削除)

{
  "Rules": [
    {
      "ID": "expire-temp-tag-after-7-days",
      "Status": "Enabled",
      "Filter": { "Tag": { "Key": "retention", "Value": "temp" } },
      "Expiration": { "Days": 7 }
    }
  ]
}

1つのルールに書けるプレフィックスは1つで、「このフォルダ以外」という除外指定もありません。複数のフォルダにまたがる対象や、除外したい対象があるときは、タグで目印を付けてタグで絞り込むのが公式ドキュメントで案内されている方法です。

例4:プレフィックス+タグ+サイズを組み合わせる(And)

{
  "Rules": [
    {
      "ID": "expire-large-exports-after-60-days",
      "Status": "Enabled",
      "Filter": {
        "And": {
          "Prefix": "exports/",
          "Tags": [ { "Key": "retention", "Value": "temp" } ],
          "ObjectSizeGreaterThan": 1048576
        }
      },
      "Expiration": { "Days": 60 }
    }
  ]
}

条件を2つ以上書くときは And で包みます。And の中ではタグが Tags(配列)になる点に注意してください。ObjectSizeGreaterThan と ObjectSizeLessThan はバイト単位で、指定した値ちょうどは含みません(1048576 と書くと 1 MiB を超えるものが対象)。サイズだけで絞るなら "Filter": { "ObjectSizeGreaterThan": 1048576 } と直接書けます。

例5:STANDARD_IA → GLACIER → DEEP_ARCHIVE の段階移行

{
  "Rules": [
    {
      "ID": "archive-step-by-step",
      "Status": "Enabled",
      "Filter": { "Prefix": "archive/" },
      "Transitions": [
        { "Days": 30,  "StorageClass": "STANDARD_IA" },
        { "Days": 90,  "StorageClass": "GLACIER" },
        { "Days": 180, "StorageClass": "DEEP_ARCHIVE" }
      ],
      "Expiration": { "Days": 730 }
    }
  ]
}

Days はどれもオブジェクトの作成日からの日数です(前の移行からの日数ではありません)。この例では、30日目に STANDARD_IA、90日目に GLACIER(S3 Glacier Flexible Retrieval)、180日目に DEEP_ARCHIVE へ移り、730日目に削除されます。削除が不要なら Expiration の行を外します。

例6:旧バージョンの削除(最新3世代を残し、30日たったものを消す)

{
  "Rules": [
    {
      "ID": "keep-3-noncurrent-versions",
      "Status": "Enabled",
      "Filter": {},
      "NoncurrentVersionExpiration": {
        "NoncurrentDays": 30,
        "NewerNoncurrentVersions": 3
      }
    }
  ]
}

バージョニングが有効なバケットで、上書きや削除によって「最新ではなくなった版」を整理するルールです。

キー 意味
NoncurrentDays 最新ではなくなってからの日数。次の版が作られた時点から数える
NewerNoncurrentVersions 残しておく旧バージョンの数(1〜100)

2つの条件を両方とも超えた版だけが削除されます。 上の例では、旧バージョンのうち新しい3つは日数に関係なく残り、4つ目以降が「最新でなくなって30日」を過ぎると消えます。世代数を気にしないなら NewerNoncurrentVersions の行を外します。

例7:期限切れ削除マーカーの整理

{
  "Rules": [
    {
      "ID": "clean-expired-delete-markers",
      "Status": "Enabled",
      "Filter": {},
      "Expiration": { "ExpiredObjectDeleteMarker": true }
    }
  ]
}

旧バージョンがすべて消えて、削除マーカーだけが残った状態を「期限切れ削除マーカー」と呼びます。このルールはそのマーカーを取り除きます。ExpiredObjectDeleteMarker は、同じルールの Days とは一緒に書けません。また、タグでの絞り込みとも組み合わせられません。

例8:不完全マルチパートアップロードの中止

{
  "Rules": [
    {
      "ID": "abort-incomplete-multipart-after-7-days",
      "Status": "Enabled",
      "Filter": {},
      "AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 7 }
    }
  ]
}

大きなファイルのアップロードが途中で止まると、送信済みのパートが一覧に出ないままバケットに残り、容量として数えられます。このルールは、開始から7日たっても完了していないアップロードを中止してパートを片付けます。こちらもタグでの絞り込みとは組み合わせられません。

例9:複数ルールをまとめた完成形

1回の put でバケットの設定全体が置き換わるため、実際に使うときは必要なルールをすべて1つのファイルにまとめます。

{
  "Rules": [
    {
      "ID": "expire-logs-after-30-days",
      "Status": "Enabled",
      "Filter": { "Prefix": "logs/" },
      "Expiration": { "Days": 30 }
    },
    {
      "ID": "archive-step-by-step",
      "Status": "Enabled",
      "Filter": { "Prefix": "archive/" },
      "Transitions": [
        { "Days": 30,  "StorageClass": "STANDARD_IA" },
        { "Days": 90,  "StorageClass": "GLACIER" },
        { "Days": 180, "StorageClass": "DEEP_ARCHIVE" }
      ]
    },
    {
      "ID": "version-cleanup",
      "Status": "Enabled",
      "Filter": {},
      "NoncurrentVersionExpiration": { "NoncurrentDays": 30, "NewerNoncurrentVersions": 3 },
      "Expiration": { "ExpiredObjectDeleteMarker": true },
      "AbortIncompleteMultipartUpload": { "DaysAfterInitiation": 7 }
    }
  ]
}

3つ目のルールのように、旧バージョンの削除・削除マーカーの整理・マルチパートの中止は、1つのルールにまとめて書けます。

put・get・delete を CLI で実行する

設定を確認する(get の出力)

例5を put したあとに get すると、次のように返ります。

aws s3api get-bucket-lifecycle-configuration --bucket example-logs-bucket
{
    "TransitionDefaultMinimumObjectSize": "all_storage_classes_128K",
    "Rules": [
        {
            "Expiration": {
                "Days": 730
            },
            "ID": "archive-step-by-step",
            "Filter": {
                "Prefix": "archive/"
            },
            "Status": "Enabled",
            "Transitions": [
                {
                    "Days": 30,
                    "StorageClass": "STANDARD_IA"
                },
                {
                    "Days": 90,
                    "StorageClass": "GLACIER"
                },
                {
                    "Days": 180,
                    "StorageClass": "DEEP_ARCHIVE"
                }
            ]
        }
    ]
}

先頭の TransitionDefaultMinimumObjectSize は、移行の対象にする最小サイズの既定値です。all_storage_classes_128K は「128 KB 未満のオブジェクトは、どのストレージクラスへも既定では移行しない」という意味です。

ルールが増えてきたら、--query で必要な列だけを表にすると見やすくなります。例9を put したあとの出力です。

aws s3api get-bucket-lifecycle-configuration --bucket example-logs-bucket \
  --query 'Rules[].{ID:ID,Status:Status,Prefix:Filter.Prefix}' --output table
------------------------------------------------------
|           GetBucketLifecycleConfiguration          |
+----------------------------+-----------+-----------+
|             ID             |  Prefix   |  Status   |
+----------------------------+-----------+-----------+
|  expire-logs-after-30-days |  logs/    |  Enabled  |
|  archive-step-by-step      |  archive/ |  Enabled  |
|  version-cleanup           |  None     |  Enabled  |
+----------------------------+-----------+-----------+

put は「追加」ではなく「全ルールの置き換え」

例2(logs/ の削除)を put したあと、続けて例8(マルチパート中止)を put してみます。

aws s3api put-bucket-lifecycle-configuration --bucket example-logs-bucket \
  --lifecycle-configuration file://02-prefix.json
aws s3api get-bucket-lifecycle-configuration --bucket example-logs-bucket --query 'Rules[].ID'

aws s3api put-bucket-lifecycle-configuration --bucket example-logs-bucket \
  --lifecycle-configuration file://08-multipart.json
aws s3api get-bucket-lifecycle-configuration --bucket example-logs-bucket --query 'Rules[].ID'
[
    "expire-logs-after-30-days"
]
[
    "abort-incomplete-multipart-after-7-days"
]

2回目の put のあと、1回目のルールは残っていません。 既存のルールを残したままルールを足すには、今の設定を get で取り出し、新しいルールと合わせてから put し直します。jq を使うと次の3行で済みます。

# 1) 今の設定から Rules だけを取り出して保存
aws s3api get-bucket-lifecycle-configuration --bucket example-logs-bucket \
  --query '{Rules: Rules}' > current.json

# 2) 追加したいルールのファイルと結合
jq -s '{Rules: (.[0].Rules + .[1].Rules)}' current.json 08-multipart.json > merged.json

# 3) まとめて put
aws s3api put-bucket-lifecycle-configuration --bucket example-logs-bucket \
  --lifecycle-configuration file://merged.json
aws s3api get-bucket-lifecycle-configuration --bucket example-logs-bucket --query 'Rules[].ID'
[
    "expire-logs-after-30-days",
    "abort-incomplete-multipart-after-7-days"
]

--query '{Rules: Rules}' としているのは、get の出力に含まれる TransitionDefaultMinimumObjectSize を外して、put にそのまま渡せる形にするためです。

ルールを一時的に止める

削除せずに止めておきたいときは、Status を Disabled に書き換えて put します。

{
  "Rules": [
    {
      "ID": "expire-logs-after-30-days",
      "Status": "Disabled",
      "Filter": { "Prefix": "logs/" },
      "Expiration": { "Days": 30 }
    }
  ]
}
aws s3api get-bucket-lifecycle-configuration --bucket example-logs-bucket \
  --query 'Rules[].[ID,Status]' --output text
expire-logs-after-30-days   Disabled

設定をすべて削除する

aws s3api delete-bucket-lifecycle --bucket example-logs-bucket
aws s3api get-bucket-lifecycle-configuration --bucket example-logs-bucket
An error occurred (NoSuchLifecycleConfiguration) when calling the GetBucketLifecycleConfiguration operation: The lifecycle configuration does not exist

削除のコマンド名は delete-bucket-lifecycle です(末尾に -configuration は付きません)。削除後、または一度も設定していないバケットに get をすると NoSuchLifecycleConfiguration が返ります。これは「ルールが1つもない」という状態を表す応答です。ルールを1つだけ消したいときは、delete ではなく、残したいルールだけを書いた JSON を put します。

boto3 で設定・確認・削除する

boto3 でも「put は全体の置き換え」という性質は同じです。次のスクリプトは、同じ ID のルールは差し替え、無ければ追加する関数 upsert_rule を用意して、既存のルールを残したまま更新します。

import boto3
from botocore.exceptions import ClientError

s3 = boto3.client("s3", region_name="ap-northeast-1")
BUCKET = "example-logs-bucket"


def get_rules(bucket):
    """今のルール一覧を返す。設定が無ければ空のリスト"""
    try:
        return s3.get_bucket_lifecycle_configuration(Bucket=bucket)["Rules"]
    except ClientError as e:
        if e.response["Error"]["Code"] == "NoSuchLifecycleConfiguration":
            return []
        raise


def upsert_rule(bucket, new_rule):
    """同じ ID のルールは差し替え、無ければ追加して、全体を put し直す"""
    rules = [r for r in get_rules(bucket) if r["ID"] != new_rule["ID"]]
    rules.append(new_rule)
    s3.put_bucket_lifecycle_configuration(
        Bucket=bucket, LifecycleConfiguration={"Rules": rules}
    )
    return [r["ID"] for r in rules]


print("開始時:", [r["ID"] for r in get_rules(BUCKET)])

print("1回目:", upsert_rule(BUCKET, {
    "ID": "expire-logs-after-30-days",
    "Status": "Enabled",
    "Filter": {"Prefix": "logs/"},
    "Expiration": {"Days": 30},
}))

print("2回目:", upsert_rule(BUCKET, {
    "ID": "abort-incomplete-multipart-after-7-days",
    "Status": "Enabled",
    "Filter": {},
    "AbortIncompleteMultipartUpload": {"DaysAfterInitiation": 7},
}))

# 同じ ID をもう一度渡すと、日数だけが差し替わる
print("3回目:", upsert_rule(BUCKET, {
    "ID": "expire-logs-after-30-days",
    "Status": "Enabled",
    "Filter": {"Prefix": "logs/"},
    "Expiration": {"Days": 45},
}))

for r in get_rules(BUCKET):
    print(r["ID"], r["Status"], r.get("Filter"), r.get("Expiration"))

# エラーになる例:Prefix と Filter の併記
try:
    s3.put_bucket_lifecycle_configuration(
        Bucket=BUCKET,
        LifecycleConfiguration={"Rules": [{
            "ID": "both", "Status": "Enabled",
            "Prefix": "logs/", "Filter": {"Prefix": "logs/"},
            "Expiration": {"Days": 30},
        }]},
    )
except ClientError as e:
    print("ClientError:", e.response["Error"]["Code"], "/", e.response["Error"]["Message"])

s3.delete_bucket_lifecycle(Bucket=BUCKET)
print("削除後:", [r["ID"] for r in get_rules(BUCKET)])

実行結果です。

開始時: []
1回目: ['expire-logs-after-30-days']
2回目: ['expire-logs-after-30-days', 'abort-incomplete-multipart-after-7-days']
3回目: ['abort-incomplete-multipart-after-7-days', 'expire-logs-after-30-days']
abort-incomplete-multipart-after-7-days Enabled {} None
expire-logs-after-30-days Enabled {'Prefix': 'logs/'} {'Days': 45}
ClientError: MalformedXML / The XML you provided was not well-formed or did not validate against our published schema
削除後: []

設定が無いときの NoSuchLifecycleConfiguration を空リストとして受けておくと、初回でも2回目以降でも同じ関数で扱えます。

ストレージクラス別の移行先と最小保存期間の早見表

Transitions の StorageClass に書ける値と、公式ドキュメントに載っている移行先・最小保存期間をまとめます。移行は「アクセス頻度が低いクラスへ向かう一方向」で、表の上から下へ進みます。

StorageClass の値 クラス名 ライフサイクルで移行できる先 最小保存期間
(移行元のみ)STANDARD S3 Standard 下のすべて なし
STANDARD_IA S3 Standard-IA INTELLIGENT_TIERING、ONEZONE_IA、GLACIER_IR、GLACIER、DEEP_ARCHIVE 30日
INTELLIGENT_TIERING S3 Intelligent-Tiering ONEZONE_IA、GLACIER_IR、GLACIER、DEEP_ARCHIVE(階層により異なる) なし
ONEZONE_IA S3 One Zone-IA GLACIER、DEEP_ARCHIVE 30日
GLACIER_IR S3 Glacier Instant Retrieval GLACIER、DEEP_ARCHIVE 90日
GLACIER S3 Glacier Flexible Retrieval DEEP_ARCHIVE 90日
DEEP_ARCHIVE S3 Glacier Deep Archive (これ以上の移行先なし) 180日

日数を決めるときに押さえておきたい点は次のとおりです。

項目 内容
最小保存期間 その期間より早く削除・移行すると、残りの日数分が請求される。移行の間隔は最小保存期間以上あける(例5の 30 → 90 → 180 はこの条件を満たす並び)
128 KB 未満のオブジェクト 既定では移行されない。小さいものも移したい場合は ObjectSizeGreaterThan などサイズのフィルターを明示する
GLACIER / DEEP_ARCHIVE の追加分 1オブジェクトにつき 40 KB(8 KB は Standard の料金、32 KB は移行先の料金)が加わる。小さなファイルが大量にある場合は、まとめてから移すと効率がよい
移行リクエスト 1オブジェクトの移行ごとに1リクエストとして数えられる
実行のタイミング 日数は翌日の午前0時(UTC)に切り上げて判定される。処理は非同期で、条件を満たしてから反映まで間があく

タイミングの例として、公式ドキュメントでは「1月15日 10:30(UTC)に作成し、3日後に削除するルール」の場合、期限は1月19日 00:00(UTC)と説明されています。日本時間では午前9時が区切りです。

同じ日に複数のアクションが当てはまったときの優先順位も決まっています。

重なったアクション 優先されるもの
完全な削除 と 移行 完全な削除
移行 と 削除マーカーの作成 移行
GLACIER への移行 と STANDARD_IA / ONEZONE_IA への移行 GLACIER への移行

エラーになる書き方と直し方(実際の出力)

ライフサイクルの JSON でつまずく箇所は、CLI が送信前に止めるものと、S3 が MalformedXML で返すものの2種類に分かれます。

MalformedXML:Prefix と Filter の併記

{"Rules":[{"ID":"a","Status":"Enabled","Prefix":"logs/","Filter":{"Prefix":"logs/"},"Expiration":{"Days":30}}]}
An error occurred (MalformedXML) when calling the PutBucketLifecycleConfiguration operation: The XML you provided was not well-formed or did not validate against our published schema

JSON で渡しているのに「XML」と表示されるのは、CLI が JSON を XML に変換して S3 に送っているためです。ルール直下の Prefix は以前の書式で、Filter と同時には書けません。プレフィックスは Filter の中に書く形に統一します。

MalformedXML は「どの行が原因か」を示さないため、次の表と見比べて原因を探します。いずれも実際に put して同じエラー文になることを確かめた書き方です。

エラーになる書き方 直し方
ルール直下の Prefix と Filter を両方書く Prefix を Filter の中へ移し、直下のものを消す
Filter も Prefix も書かない バケット全体なら "Filter": {} を書く
"Filter": {"Prefix": "logs/", "Tag": {…}} と条件を2つ並べる "Filter": {"And": {"Prefix": "logs/", "Tags": [{…}]}} と And で包む
"Expiration": {"Days": 30, "ExpiredObjectDeleteMarker": true} 日数での削除と削除マーカーの整理を別々のルールに分ける

CLI が送信前に止めるエラー

キー名の打ち間違いや型の違いは、S3 に届く前に CLI(botocore)が見つけて、場所を教えてくれます。

{"Rules":[{"ID":"a","Status":"Enabled","Filter":{},"Expiration":{"Days":"30"}}]}
Parameter validation failed:
Invalid type for parameter LifecycleConfiguration.Rules[0].Expiration.Days, value: 30, type: <class 'str'>, valid types: <class 'int'>

日数は引用符なしの数値で書きます。

{"Rules":[{"ID":"a","Status":"Enabled","Filter":{},"Expiration":{"Day":30}}]}
Parameter validation failed:
Unknown parameter in LifecycleConfiguration.Rules[0].Expiration: "Day", must be one of: Date, Days, ExpiredObjectDeleteMarker

使えるキー名が一覧で出るので、つづりを直します。

{"Rules":[{"ID":"a","Status":"Enabled","Filter":{},"Expiration":{"Days":30},}]}
Error parsing parameter '--lifecycle-configuration': Invalid JSON: Expecting property name enclosed in double quotes: line 1 column 77 (char 76)

最後の要素のあとに残ったカンマが原因です。jq . lifecycle.json を先に通しておくと、JSON の書式の誤りを put の前に見つけられます。

エラー文と原因の対応表

エラー文 原因 対応
MalformedXML ルールの組み立てが書式に合っていない 上の表の4つを順に確認する
Parameter validation failed: Invalid type … 数値を文字列で書いたなど型の違い エラー文が示す場所の型を直す
Parameter validation failed: Unknown parameter … キー名のつづり違い must be one of に並ぶ名前から選ぶ
Error parsing parameter … Invalid JSON カンマや引用符など JSON の書式 jq . で確認して直す
NoSuchLifecycleConfiguration get したバケットにルールが1つもない 設定前・削除後の正常な応答。put すれば解消
NoSuchBucket バケット名の誤り aws s3 ls でバケット名を確認する

設定したのに動かないと感じたときの確認表

ルールが put できていても、期待どおりに減らないことがあります。公式ドキュメントのトラブルシューティングに載っている主な理由です。

状況 理由 対応
期限を過ぎたのにまだ見える 削除・移行は非同期で、反映まで間があく 時間をおいて確認する。料金の扱いは条件を満たした時点で切り替わる
バージョニング有効のバケットでオブジェクト数が増えた Expiration は最新版に削除マーカーを付けるだけで、マーカーも1件と数えられる 例6(旧バージョン削除)と例7(マーカー整理)を足す
旧バージョンが消えない Expiration.Days は最新版だけが対象 NoncurrentVersionExpiration を追加する
小さいファイルが移行されない 128 KB 未満は既定で移行の対象外 サイズのフィルターを明示する
バケットポリシーで削除を拒否しているのに消えた ライフサイクルは通常の削除 API を通らないため、ポリシーの Deny では止まらない ルールを編集・無効化・削除する
消えたオブジェクトを戻したい ライフサイクルによる削除は取り消せない 事前にバージョニングを有効にしておくと、旧バージョンから戻せる

バケットを空にしたいときは、「最新版の削除+旧バージョンの完全削除」と「期限切れ削除マーカーの削除+不完全マルチパートの削除」の2組のルールを設定する方法が案内されています。

よくある質問

Q. ルールを1つだけ追加したいのですが、put すると既存のルールはどうなりますか? A. put したファイルの内容でバケットの設定全体が置き換わります。get で今のルールを取り出し、新しいルールと合わせて put してください。この記事の jq を使った3行、または boto3 の upsert_rule がそのまま使えます。

Q. Days に指定した日数ちょうどに削除されますか? A. 期限は翌日の午前0時(UTC、日本時間の午前9時)に切り上げられ、そこから非同期で処理されます。日数ちょうどの時刻に消える前提にはせず、余裕を持たせて設計します。

Q. バージョニングが有効なバケットで容量を減らすには、どのルールが必要ですか? A. Expiration.Days だけでは削除マーカーが付くだけで、以前の版は残ります。NoncurrentVersionExpiration(旧バージョンの削除)と ExpiredObjectDeleteMarker(残ったマーカーの整理)を合わせて設定します。例9の3つ目のルールが完成形です。

Q. JSON で書いているのに MalformedXML と出るのはなぜですか? A. CLI や boto3 が JSON を XML に変換して送信しており、S3 側のエラー名がそのまま表示されるためです。Prefix と Filter の併記、Filter の書き忘れ、And なしの複数条件、Days と ExpiredObjectDeleteMarker の同居を確認してください。

まとめ

  • ライフサイクル設定は Rules 配列に ID・Status・Filter・アクションを並べた JSON を put-bucket-lifecycle-configuration に渡して登録する
  • put は全ルールの置き換え。ルールを足すときは get → 結合 → put の順で行う
  • バケット全体が対象でも "Filter": {} を省略しない。条件が2つ以上なら And で包む
  • 段階移行の Days は作成日からの日数。最小保存期間(IA 30日、GLACIER 90日、DEEP_ARCHIVE 180日)以上の間隔をあける
  • バージョニング有効のバケットは NoncurrentVersionExpiration と ExpiredObjectDeleteMarker を合わせて設定すると容量が減る
  • MalformedXML は場所を示さないので、Prefix と Filter の併記など4つの書き方を順に確認する
  • 削除・移行は翌日0時(UTC)に切り上げ、非同期で実行される

参考・出典

本記事の内容は、ご自由にお使いください。
ご利用の際は、出典として本ページへのリンクを記載いただけますようお願いします。

(記載例)出典:株式会社RJC「S3ライフサイクル設定のJSON例集 自動削除・クラス移行CLI」

株式会社RJC ― SI事業・SES事業・AI駆動開発。RJCは一緒に成長を楽しめる会社です。

WE ARE HIRING

RJCで一緒に開発しながら、
成長を楽しみませんか?

RJCは、Web・モバイル・AIを活用した開発プロジェクトで、テックリードやPM・PMOも活躍するシステム開発会社です。会社を知る、待遇を確かめる、話を聞いてみる。気になるところ見てみてください!

  • 127日年間休日
  • 12時間平均残業時間
  • 毎日ガチャ遊びココロも大切にする福利厚生。アマギフなどの賞品ラインナップ!

ほかにも、チケットレストラン、書籍読み放題、2年ごとの慰労報奨(休暇 or 金一封)、11期連続の黒字決算。

ABOUT RJC RJCがどんな会社か知る 考え方、研修、働き方、福利厚生、社員の前職まで。RJCのことが丸わかり! RJC丸わかりページへ JOB DESCRIPTION 仕事内容・待遇を見てみる 仕事内容、給与・待遇、選考の流れ。経験者も未経験も!応募前に知りたいこと、まとめました! 募集要項を見る ENTRY エントリーする エントリーは1〜2分・履歴書不要です。まずは話を聞いてみたい、という方でも歓迎です! エントリーフォームへ

RJCで一緒に開発しながら、 成長を楽しみませんか?