CephXLIV · Object Storage FoundationsObject Storage Foundations
Lifecycle rules: automated expiration and transition
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
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
| Symptom | Cause |
|---|---|
| Status stays UNINITIAL | processing has not reached this bucket |
| Rule present but nothing expires | prefix does not match the keys |
| Only some objects expire | filter is narrower than intended |
| Nothing at all processes | work 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
Q1. An object's lifecycle expiration threshold passes at 09:00. When is it removed?
Q2. Capacity held by abandoned multipart uploads shows up only as a gap between bucket stats and the object listing.
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.
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