Skip to main content
RunBook Academy

CephXLIV · Object Storage FoundationsObject Storage Foundations

Lifecycle rules: automated expiration and transition

Advanced⏱ ~18 minawsradosgw-admin

What you'll learn

  • Write lifecycle rules for expiration and transition
  • Configure and monitor lifecycle processing
  • Predict when rules take effect
  • Diagnose rules that are not being applied

Prerequisites

None — start here.

Verified against Ceph Tentacle 20.2.x · Ceph Squid 19.2.x (supported previous) · cephadm matches the verified Ceph release · podman 4.x · csi-rbd and csi-cephfs current · RBD / CephFS / RGW current (matches Ceph release) · Linux kernel 5.15+ (5.10 minimum) · Ubuntu 24.04 LTS (Ceph host baseline) · Debian 12 (Bookworm) (Ceph host baseline) · Rocky Linux / RHEL / AlmaLinux 9.x (Ceph host baseline) · Proxmox VE 9.x (cross-course integration) · Kubernetes 1.31+ (cross-course integration) · 2026-08-18

Not yet marked complete on this device.

Why this matters in production

Deleting a billion expired objects by listing and issuing deletes is a job that runs for weeks. Lifecycle rules are how retention policy is implemented at scale, and they are processed by the gateway on a schedule rather than at the moment of expiry — which is the detail that generates most of the confusion.

Rules

{
  "Rules": [
    {
      "ID": "expire-logs",
      "Status": "Enabled",
      "Filter": {"Prefix": "logs/"},
      "Expiration": {"Days": 90}
    },
    {
      "ID": "archive-then-expire",
      "Status": "Enabled",
      "Filter": {"Prefix": "data/"},
      "Transitions": [{"Days": 30, "StorageClass": "COLD"}],
      "Expiration": {"Days": 2555}
    },
    {
      "ID": "clean-multipart",
      "Status": "Enabled",
      "Filter": {"Prefix": ""},
      "AbortIncompleteMultipartUpload": {"DaysAfterInitiation": 7}
    }
  ]
}
aws s3api put-bucket-lifecycle-configuration --bucket data \
    --lifecycle-configuration file://lifecycle.json
aws s3api get-bucket-lifecycle-configuration --bucket data

The third rule is one people forget: abandoned multipart uploads consume capacity indefinitely and appear in no listing.

Transitions and storage classes

radosgw-admin zonegroup placement add \
    --rgw-zonegroup=default --placement-id=default-placement \
    --storage-class=COLD
radosgw-admin zone placement add \
    --rgw-zone=default --placement-id=default-placement \
    --storage-class=COLD --data-pool=cold-ec-pool

A transition moves objects to a different pool — typically replicated to erasure coded, or flash to spinning disk — within the same bucket and the same key. Clients see no difference except potentially in retrieval latency.

When rules run

ceph config get client.rgw rgw_lifecycle_work_time     # "00:00-06:00" default
ceph config get client.rgw rgw_lc_max_worker
ceph config get client.rgw rgw_lc_debug_interval       # testing only

radosgw-admin lc list
radosgw-admin lc get --bucket=data
radosgw-admin lc process

Processing runs during the configured window, and a bucket is visited on a cycle. An object whose expiry passed at 09:00 is removed during the next processing window, not at 09:00 — so “expired” objects remain visible and billable for up to a day.

Diagnosing rules that are not applied

radosgw-admin lc list
# shows per-bucket status: UNINITIAL, PROCESSING, COMPLETE

radosgw-admin lc get --bucket=data
SymptomCause
Status stays UNINITIALprocessing has not reached this bucket
Rule present but nothing expiresprefix does not match the keys
Only some objects expirefilter is narrower than intended
Nothing at all processeswork time window, or no gateway running lifecycle

Prefix mismatch is the most common: a rule on logs/ does not match keys beginning /logs/ or Logs/.

Quiz

Knowledge check · 4 questions

  1. Q1. An object's lifecycle expiration threshold passes at 09:00. When is it removed?

  2. Q2. Capacity held by abandoned multipart uploads shows up only as a gap between bucket stats and the object listing.

  3. Q3. Diagnose a lifecycle rule that is not expiring anything.

    A lifecycle rule with a 30-day expiration on prefix `temp/` has been in place for two months, and objects under that prefix from three months ago are still present. `radosgw-admin lc list` shows the bucket as COMPLETE.

  4. Q4. Why is lifecycle processing batched into a window rather than driven by per-object timers?

Passing score: 75%. Answers are checked in this browser.

Production discipline

Put an AbortIncompleteMultipartUpload rule on every bucket; the leak it closes is invisible in listings and is found by accident otherwise. Verify lifecycle prefixes against actual keys character by character — mismatched case or a leading slash is the most common reason a correct-looking rule does nothing.

Cross-course references

  • Kubernetes: TTL controllers for finished Jobs implement the same batched-expiry model
  • Linux: tmpwatch and logrotate schedules follow the identical periodic-sweep approach