Open-Source Wikis

/

containerd

/

Systems

/

Garbage collection

containerd/containerd

Garbage collection

A reference-graph garbage collector that runs over the metadata store, marks reachable objects, and deletes the rest. Implemented in plugins/gc/, with the reference walker in core/metadata/gc.go and the leveled scheduler interfaces in core/gc/.

Purpose

  • Reclaim unused content blobs and unused snapshots (the only things big enough to matter).
  • Honor leases so in-progress operations aren't pruned out from under themselves.
  • Run periodically and on-demand when an ImageDelete/Remove returns.

Reference graph

Each object in the metadata store has a set of references to other objects:

  • An image references its root descriptor digest, which transitively references manifests, configs, and layers in the content store.
  • A container references its image digest and its working snapshot.
  • A lease references arbitrary objects (digests and snapshots) — leases are anti-GC handles.
  • A sandbox references its sandbox image.
  • A snapshot references its parent snapshot.

core/metadata/gc.go's references function walks the bbolt buckets and emits gc.Node records for each reference. The GC scheduler builds a graph and marks reachable nodes.

Plugin model

plugins/gc/ registers a GCPlugin that exposes a Schedule interface. The metadata store calls Schedule after operations that might create garbage; the scheduler coalesces requests so a flurry of deletes triggers at most one GC pass.

The scheduler's runtime parameters (pause_threshold, deletion_threshold, mutation_threshold, schedule_delay, start_delay) are configurable in [plugins."io.containerd.gc.v1.scheduler"].

Lease handling

A lease is created by client.LeasesService().Create(ctx, lease.WithExpiration(...)) and resources are added with lease.WithResource. While a lease references an object, GC won't delete it.

The transfer pipeline creates a lease at the start of a pull and releases it once the image is committed; this way a long pull doesn't have its blobs pruned because no Image record exists yet.

Run sequence

graph TD
    Trigger[delete container / image / lease]
    Schedule[scheduler.Schedule]
    Wait[debounce / coalesce]
    Mark[Walk metadata, mark reachable]
    Sweep[Delete unreached blobs and snapshots]
    Done

    Trigger --> Schedule
    Schedule --> Wait
    Wait --> Mark
    Mark --> Sweep
    Sweep --> Done

The mark phase reads the bbolt metadata using a View transaction (a consistent snapshot) and iterates through every namespace. The sweep phase invokes the content store's Delete and the snapshotter's Remove for each unreachable id.

Failure modes and gotchas

  • Forgot to add a reference: any time you add a new object type that holds digests or snapshot keys, you must extend core/metadata/gc.go's references function. Otherwise GC will delete the very thing you just stored.
  • No lease around a long pull: blobs land in the content store, GC runs, blobs vanish. Always lease.
  • Cross-namespace references: there are none. Each namespace has its own GC scope.

Manual triggers

  • ctr content gc (and the underlying gRPC Content.GC) requests a GC pass.
  • The scheduler runs a periodic GC at startup-delay then on-demand.

Entry points for modification

  • New object type with references: extend core/metadata/gc.go's references function. Add tests in core/metadata/gc_test.go.
  • Tune scheduler defaults: edit plugins/gc/scheduler.go.
  • Visualize the reference graph: the metadata store has a Walk(ctx, fn) per type; collect into a graphviz file for debugging.

Built by Factory AutoWiki from public repository content. It is a generated preview for codebase exploration, not source-maintained documentation.

Garbage collection – containerd wiki | Factory