Container image garbage collection and unexpected disk usage on Talos Linux nodes
0 reputation · 31 May 2023, 14:53 UTC
0 reputation · 31 May 2023, 14:53 UTC
Goal: Identify why Talos Linux nodes exhibit steady disk consumption over time despite no apparent workload growth, focusing on the containerd image garbage collection behavior.
Constraints: Talos Linux uses an immutable root filesystem, so logs and temporary data are ephemeral; the containerd GC policy is disabled by default, leaving image cleanup to manual intervention and causing inconsistent disk usage across clusters. The decision to enable GC involves trade‑offs between storage reclamation and potential impact on node upgrade or rollback procedures.
Benefits. Enabling containerd garbage collection and kubelet image GC provides predictable reclamation of unused layers in /var/lib/containerd on the writable partition. It reduces steady growth from dangling snapshots and unreferenced images left by frequent pulls, rollouts and CI workloads. With thresholds tuned to node disk size, it prevents disk pressure evictions and avoids manual pruning.
Risks. Talos uses an immutable root filesystem. Images and container state live under /var/lib/containerd on the writable partition. Aggressive GC can remove layers that are not currently referenced by running pods but are needed for fast restart, node upgrade, or rollback. Removing images referenced by system pods or Talos-managed workloads can cause pod failures and node instability. Changes to containerd or kubelet settings in Talos require a machine config patch and a controlled reboot, which impacts node availability.
Node upgrades in Talos are driven by machine config changes and the Talos control plane. The ability to roll back a node to a previous machine configuration does not depend on keeping old container images on disk, it depends on the machine config history and the ability to pull required images after reboot.
Enabling GC does not break the Talos upgrade or rollback mechanism itself. The risk is operational: if GC removes an image that a workload needs immediately after a reboot or rollback, the node will need to pull the image from the registry before pods become Ready. That increases startup time and creates a dependency on registry availability and network. Conservative GC settings that keep recently used images and rely on kubelet image GC thresholds limit this risk.
Monitor node disk usage on the writable partition, not the immutable root. Track /var/lib/containerd size and growth rate over days. Correlate with containerd image counts and sizes, and with kubelet eviction events and image GC events.
Alert on sustained growth of /var/lib/containerd despite GC being enabled, and on image pull failures after reboots.
Steady growth is commonly caused by accumulation of unused image layers and dangling snapshots after frequent pulls, rollouts, or CI workloads. Containerd GC is conservative by default and kubelet image GC only activates when disk usage crosses configured eviction thresholds, so /var can grow substantially before automatic pruning occurs. The brief notes containerd GC policy is disabled by default in this environment, leaving cleanup to manual intervention and causing inconsistent disk usage across clusters. This is plausible but requires current verification against the applied machine config for your Talos version.
df -h
du -sh /var/lib/containerd/* | sort -h
ctr -n k8s.io images list
ctr -n k8s.io images ls --size
Correlate with running pods: crictl ps -a and image references.talosctl machineconfig show
Check containerd config and kubelet config sections for imageGarbageCollectionPolicy, imageGCHighThresholdPercent, imageGCLowThresholdPercent, and eviction hard thresholds.ctr -n k8s.io garbage collect --force
Do not force-remove images referenced by running pods.One missing diagnostic detail that changes the recommendation: the current Talos version and the applied machine config values for containerd garbage collection and kubelet imageGcPolicy/eviction thresholds. Without those, threshold tuning and the decision to enable containerd GC cannot be safely scoped.
Use comments to ask for clarification. Post a solution as an answer.
4,000 reputation · 31 May 2023, 20:30 UTC
The discussion conflates two different mechanisms. containerd's internal garbage collector only removes unreferenced blobs — it never deletes an image that still has a reference, so it is not what reclaims space from old workload images. Actual image reclamation comes from the kubelet's image GC, driven by imageGCHighThresholdPercent and imageGCLowThresholdPercent, which on Talos you set via machine.kubelet.extraConfig (exact keys vary by Talos/Kubernetes version — verify against yours).
Beyond filesystem metrics, watch node_filesystem_avail_bytes for the data partition alongside image pull latency after rollout events. The scenario that bites people is a rollback or reschedule onto a node whose cache was pruned: pods sit in ImagePullBackOff or pull slowly. In air-gapped clusters this can be unrecoverable during a registry outage, so a conservative high threshold (or a pinned image pre-pull for rollback targets) is worth considering before enabling aggressive GC.