Skip to content

fix(talos): replace etcd nightly defrag with hourly auto-compaction - #4290

Merged
Tanguille merged 1 commit into
mainfrom
feat/etcd-auto-compaction
Aug 2, 2026
Merged

fix(talos): replace etcd nightly defrag with hourly auto-compaction#4290
Tanguille merged 1 commit into
mainfrom
feat/etcd-auto-compaction

Conversation

@Tanguille

@Tanguille Tanguille commented Aug 1, 2026

Copy link
Copy Markdown
Owner

What

Replaces the nightly etcd-defrag CronJob with hourly etcd auto-compaction configured in Talos, matching bjw-s-labs/home-ops@904940dc8393.

Why

The previous weekly defrag cadence let fragmentation cross the 50% quota alert by day 4, forcing the daily ahrtr/etcd-defrag CronJob — a privileged + hostPID + hostNetwork pod mounting /system/secrets/etcd.

Auto-compaction fixes the root cause: compacting old revisions hourly keeps the DB from growing, so a defrag job is a no-op. It also removes a privileged pod from the cluster.

Changes

  • talos/patches/controller/cluster.yaml: add auto-compaction-mode: periodic + auto-compaction-retention: 1h to cluster.etcd.extraArgs
  • Remove kubernetes/apps/kube-system/etcd-defrag/ and its entry in kube-system/kustomization.yaml

Notes

  • One-time defrag recommended after apply: compaction stops DB growth but doesn't shrink an already-large file. Run talosctl etcd defrag per control-plane node once.
  • Deliberately not included from the upstream commit: the kustomize-controller --concurrent reduction targets single-node etcd I/O contention, not defrag — this cluster's 3-node HA etcd doesn't have that problem.

Validation

  • validate-pr.sh exit 0 (warnings are pre-existing repo-wide false positives)
  • talhelper genconfig succeeds; generated machine config contains the new etcd extraArgs

Summary by CodeRabbit

  • New Features

    • Enabled hourly automatic etcd compaction with a one-hour retention period.
  • Changes

    • Removed the scheduled etcd defragmentation workload and its deployment configuration.
    • Simplified system maintenance by replacing scheduled defragmentation with built-in automatic compaction.

Etcd was growing enough between weekly defrag runs to cross the 50% quota
alert by day 4, requiring a daily ahrtr/etcd-defrag CronJob (privileged +
hostPID + hostNetwork, mounting Talos etcd PKI).

Auto-compaction addresses the root cause: compacting old revisions hourly
keeps the DB from growing, so a defrag job is a no-op. Matches the approach
in bjw-s-labs/home-ops commit 904940dc8393.

Note: compaction does not shrink an already-large DB file; a one-time
talosctl etcd defrag per control-plane node is recommended after applying.
The kustomize-controller --concurrent reduction from that commit is not
included: it targets single-node etcd I/O contention, not defrag.
@deepsource-io

deepsource-io Bot commented Aug 1, 2026

Copy link
Copy Markdown
Contributor

DeepSource Code Review

We reviewed changes in f4e2694...4e161cd on this pull request. Below is the summary for the review, and you can see the individual issues we found as inline review comments.

See full review on DeepSource ↗

PR Report Card

Overall Grade   Security  

Reliability  

Complexity  

Hygiene  

Code Review Summary

Analyzer Status Updated (UTC) Details
JavaScript Aug 1, 2026 10:39p.m. Review ↗
Shell Aug 1, 2026 10:39p.m. Review ↗

Important

AI Review is run only on demand for your team. We're only showing results of static analysis review right now. To trigger AI Review, comment @deepsourcebot review on this thread.

@coderabbitai

coderabbitai Bot commented Aug 1, 2026

Copy link
Copy Markdown

Review Change Stack

📝 Walkthrough

Walkthrough

The PR removes the etcd-defrag Flux and HelmRelease resources from kube-system. It configures etcd for hourly automatic compaction with one-hour retention.

Changes

Etcd maintenance

Layer / File(s) Summary
Compaction and defragmentation configuration
kubernetes/apps/kube-system/etcd-defrag/app/helmrelease.yaml, kubernetes/apps/kube-system/etcd-defrag/app/kustomization.yaml, kubernetes/apps/kube-system/etcd-defrag/ks.yaml, kubernetes/apps/kube-system/kustomization.yaml, talos/patches/controller/cluster.yaml
The etcd-defrag HelmRelease, Kustomization, and Flux resource are deleted. The kube-system Kustomization no longer references them. etcd is configured for hourly automatic compaction with one-hour retention.

Estimated code review effort: 2 (Simple) | ~10 minutes

Possibly related PRs

🚥 Pre-merge checks | ✅ 5
✅ Passed checks (5 passed)
Check name Status Explanation
Description Check ✅ Passed Check skipped - CodeRabbit’s high-level summary is enabled.
Title check ✅ Passed The title clearly summarizes the main change: replacing the nightly etcd defrag CronJob with hourly auto-compaction in Talos.
Docstring Coverage ✅ Passed No functions found in the changed files to evaluate docstring coverage. Skipping docstring coverage check.
Linked Issues check ✅ Passed Check skipped because no linked issues were found for this pull request.
Out of Scope Changes check ✅ Passed Check skipped because no linked issues were found for this pull request.
✨ Finishing Touches
🧪 Generate unit tests (beta)
  • Create PR with unit tests
  • Commit unit tests in branch feat/etcd-auto-compaction

Comment @coderabbitai help to get the list of available commands.

@tanguille-cluster

Copy link
Copy Markdown
@@ (root level) @@
# v1/ServiceAccount/kube-system/etcd-defrag
! - one document removed:
- apiVersion: v1
- kind: ServiceAccount
- metadata:
-   name: etcd-defrag
-   namespace: kube-system
-   labels:
-     app.kubernetes.io/instance: etcd-defrag
-     app.kubernetes.io/managed-by: Helm
-     app.kubernetes.io/name: etcd-defrag
-     helm.toolkit.fluxcd.io/name: etcd-defrag
-     helm.toolkit.fluxcd.io/namespace: kube-system

@@ (root level) @@
# batch/v1/CronJob/kube-system/etcd-defrag
! - one document removed:
- apiVersion: batch/v1
- kind: CronJob
- metadata:
-   name: etcd-defrag
-   namespace: kube-system
-   labels:
-     app.kubernetes.io/controller: etcd-defrag
-     app.kubernetes.io/instance: etcd-defrag
-     app.kubernetes.io/managed-by: Helm
-     app.kubernetes.io/name: etcd-defrag
-     helm.toolkit.fluxcd.io/name: etcd-defrag
-     helm.toolkit.fluxcd.io/namespace: kube-system
- spec:
-   concurrencyPolicy: Forbid
-   failedJobsHistoryLimit: 1
-   jobTemplate:
-     spec:
-       backoffLimit: 1
-       template:
-         metadata:
-           labels:
-             app.kubernetes.io/controller: etcd-defrag
-             app.kubernetes.io/instance: etcd-defrag
-             app.kubernetes.io/name: etcd-defrag
-         spec:
-           automountServiceAccountToken: false
-           containers:
-           - name: app
-             image: "ghcr.io/ahrtr/etcd-defrag:v0.42.0@sha256:5138a12eda39067dabcf1d420d66f54f29f1e9297109a6b36574e010b45d58cc"
-             args:
-             - "--endpoints=https://127.0.0.1:2379"
-             - "--cluster"
-             - "--cacert=/certs/ca.crt"
-             - "--cert=/certs/server.crt"
-             - "--key=/certs/server.key"
-             - "--defrag-rule=dbQuotaUsage > 0.5 || dbSizeFree > 50*1024*1024"
-             - "--move-leader"
-             - "--wait-between-defrags=30s"
-             - "--etcd-storage-quota-bytes=2147483648"
-             - "--auto-disalarm"
-             - "--disalarm-threshold=0.8"
-             securityContext:
-               privileged: true
-             resources:
-               limits:
-                 cpu: 100m
-                 memory: 128Mi
-               requests:
-                 cpu: 25m
-                 memory: 128Mi
-             volumeMounts:
-             - name: certs
-               mountPath: /certs
-               readOnly: true
-             - name: tmpfs
-               mountPath: /tmp
-               subPath: tmp
-           dnsPolicy: ClusterFirstWithHostNet
-           enableServiceLinks: false
-           hostIPC: false
-           hostNetwork: true
-           hostPID: true
-           nodeSelector:
-             node-role.kubernetes.io/control-plane: 
-           restartPolicy: Never
-           securityContext:
-             runAsGroup: 0
-             runAsNonRoot: false
-             runAsUser: 0
-           serviceAccountName: etcd-defrag
-           tolerations:
-           - key: node-role.kubernetes.io/control-plane
-             effect: NoSchedule
-             operator: Exists
-           volumes:
-           - name: certs
-             hostPath:
-               path: /system/secrets/etcd
-           - name: tmpfs
-             emptyDir: {}
-   schedule: "0 3 * * *"
-   startingDeadlineSeconds: 30
-   successfulJobsHistoryLimit: 1
-   suspend: false
-   timeZone: Europe/Brussels

@tanguille-cluster

Copy link
Copy Markdown
@@ (root level) @@
# kustomize.toolkit.fluxcd.io/v1/Kustomization/kube-system/etcd-defrag
! - one document removed:
- apiVersion: kustomize.toolkit.fluxcd.io/v1
- kind: Kustomization
- metadata:
-   name: etcd-defrag
-   namespace: kube-system
-   labels:
-     kustomize.toolkit.fluxcd.io/name: cluster-apps
-     kustomize.toolkit.fluxcd.io/namespace: flux-system
- spec:
-   decryption:
-     provider: sops
-     secretRef:
-       name: sops-age
-   deletionPolicy: WaitForTermination
-   interval: 1h
-   patches:
-   - patch: |
-       apiVersion: helm.toolkit.fluxcd.io/v2
-       kind: HelmRelease
-       metadata:
-         name: _
-       spec:
-         install:
-           crds: CreateReplace
-         rollback:
-           cleanupOnFail: true
-         upgrade:
-           cleanupOnFail: true
-           crds: CreateReplace
-           strategy:
-             name: RemediateOnFailure
-           remediation:
-             remediateLastFailure: true
-             retries: 2
-     target:
-       kind: HelmRelease
-       group: helm.toolkit.fluxcd.io
-   path: ./kubernetes/apps/kube-system/etcd-defrag/app
-   postBuild:
-     substituteFrom:
-     - name: cluster-settings
-       kind: ConfigMap
-       optional: false
-     - name: cluster-secrets
-       kind: Secret
-       optional: false
-   prune: true
-   retryInterval: 2m
-   sourceRef:
-     name: flux-system
-     kind: GitRepository
-     namespace: flux-system
-   targetNamespace: kube-system
-   timeout: 5m
-   wait: false

@@ (root level) @@
# helm.toolkit.fluxcd.io/v2/HelmRelease/kube-system/etcd-defrag
! - one document removed:
- apiVersion: helm.toolkit.fluxcd.io/v2
- kind: HelmRelease
- metadata:
-   name: etcd-defrag
-   namespace: kube-system
-   labels:
-     kustomize.toolkit.fluxcd.io/name: etcd-defrag
-     kustomize.toolkit.fluxcd.io/namespace: kube-system
- spec:
-   chartRef:
-     name: app-template
-     kind: OCIRepository
-   install:
-     crds: CreateReplace
-   interval: 30m
-   rollback:
-     cleanupOnFail: true
-   upgrade:
-     cleanupOnFail: true
-     crds: CreateReplace
-     remediation:
-       remediateLastFailure: true
-       retries: 2
-     strategy:
-       name: RemediateOnFailure
-   values:
-     controllers:
-       etcd-defrag:
-         type: cronjob
-         cronjob:
-           backoffLimit: 1
-           schedule: "0 3 * * *"
-           timeZone: Europe/Brussels
-         containers:
-           app:
-             resources:
-               limits:
-                 cpu: 100m
-                 memory: 128Mi
-               requests:
-                 cpu: 25m
-                 memory: 128Mi
-             args:
-             - "--endpoints=https://127.0.0.1:2379"
-             - "--cluster"
-             - "--cacert=/certs/ca.crt"
-             - "--cert=/certs/server.crt"
-             - "--key=/certs/server.key"
-             - "--defrag-rule=dbQuotaUsage > 0.5 || dbSizeFree > 50*1024*1024"
-             - "--move-leader"
-             - "--wait-between-defrags=30s"
-             - "--etcd-storage-quota-bytes=2147483648"
-             - "--auto-disalarm"
-             - "--disalarm-threshold=0.8"
-             image:
-               repository: ghcr.io/ahrtr/etcd-defrag
-               tag: "v0.42.0@sha256:5138a12eda39067dabcf1d420d66f54f29f1e9297109a6b36574e010b45d58cc"
-             securityContext:
-               privileged: true
-     defaultPodOptions:
-       hostNetwork: true
-       hostPID: true
-       nodeSelector:
-         node-role.kubernetes.io/control-plane: 
-       securityContext:
-         runAsGroup: 0
-         runAsNonRoot: false
-         runAsUser: 0
-       tolerations:
-       - key: node-role.kubernetes.io/control-plane
-         effect: NoSchedule
-         operator: Exists
-     persistence:
-       certs:
-         type: hostPath
-         hostPath: /system/secrets/etcd
-         globalMounts:
-         - path: /certs
-           readOnly: true
-       tmpfs:
-         type: emptyDir
-         advancedMounts:
-           etcd-defrag:
-             app:
-             - path: /tmp
-               subPath: tmp

@coderabbitai coderabbitai Bot left a comment

Copy link
Copy Markdown

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

🧹 Nitpick comments (1)
talos/patches/controller/cluster.yaml (1)

17-21: 🩺 Stability & Availability | 🔵 Trivial | ⚡ Quick win

Do not treat compaction as a complete replacement for defragmentation.

These settings limit MVCC revision history. They do not return fragmented backend space to the host filesystem; etcd treats defragmentation as a separate, per-member operation. (etcd.io)

Because this PR removes recurring etcd-defrag, verify that one-time defragmentation plus compaction keeps each control-plane member below its storage quota. Monitor the version-appropriate physical and in-use database size metrics and NOSPACE alarms. Update the comment if it intends to describe logical history growth only. (etcd.io)

🤖 Prompt for AI Agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

In `@talos/patches/controller/cluster.yaml` around lines 17 - 21, Update the
comment near auto-compaction-mode and auto-compaction-retention to describe only
MVCC revision-history compaction, not defragmentation or filesystem-space
reclamation. Ensure the change does not imply compaction replaces the removed
recurring etcd-defrag operation.
🤖 Prompt for all review comments with AI agents
Verify each finding against current code. Fix only still-valid issues, skip the
rest with a brief reason, keep changes minimal, and validate.

Nitpick comments:
In `@talos/patches/controller/cluster.yaml`:
- Around line 17-21: Update the comment near auto-compaction-mode and
auto-compaction-retention to describe only MVCC revision-history compaction, not
defragmentation or filesystem-space reclamation. Ensure the change does not
imply compaction replaces the removed recurring etcd-defrag operation.

ℹ️ Review info
⚙️ Run configuration

Configuration used: Organization UI

Review profile: CHILL

Plan: Pro Plus

Run ID: d1423e5a-4cda-4508-85d1-14658e916854

📥 Commits

Reviewing files that changed from the base of the PR and between f4e2694 and 4e161cd.

📒 Files selected for processing (5)
  • kubernetes/apps/kube-system/etcd-defrag/app/helmrelease.yaml
  • kubernetes/apps/kube-system/etcd-defrag/app/kustomization.yaml
  • kubernetes/apps/kube-system/etcd-defrag/ks.yaml
  • kubernetes/apps/kube-system/kustomization.yaml
  • talos/patches/controller/cluster.yaml
🔗 Linked repositories identified

CodeRabbit considers these linked repositories for cross-repo context during reviews:

  • Tanguille/LLMKube (auto-detected)
  • Tanguille/toolhive (auto-detected)
  • Tanguille/pr-reviewer-action (auto-detected)
  • Tanguille/2x-R9700-RDNA4-GFX1201-sglang-inference (auto-detected)
💤 Files with no reviewable changes (4)
  • kubernetes/apps/kube-system/kustomization.yaml
  • kubernetes/apps/kube-system/etcd-defrag/app/kustomization.yaml
  • kubernetes/apps/kube-system/etcd-defrag/app/helmrelease.yaml
  • kubernetes/apps/kube-system/etcd-defrag/ks.yaml

@github-actions

github-actions Bot commented Aug 1, 2026

Copy link
Copy Markdown

AI Automated Review

Analysis engine: qwen-3.6-fast@http://litellm.ai.svc.cluster.local/v1 (openai)

Recommendation: Approve

This PR correctly replaces a privileged, host-networked etcd defragmentation CronJob with native Talos etcd auto-compaction. The change addresses the root cause of database growth rather than just reclaiming space periodically, and significantly reduces the cluster's privilege surface by removing a pod that required privileged: true, hostPID, and hostNetwork.

Change-by-Change Findings

  1. Removed kubernetes/apps/kube-system/etcd-defrag/ directory: The HelmRelease, Kustomization, and Flux Kustomization for the ahrtr/etcd-defrag CronJob are fully removed. This eliminates a privileged workload accessing /system/secrets/etcd.
  2. Modified kubernetes/apps/kube-system/kustomization.yaml: Correctly removes the reference to ./etcd-defrag/ks.yaml. The remaining resource list is consistent with the deletion.
  3. Modified talos/patches/controller/cluster.yaml: Adds auto-compaction-mode: periodic and auto-compaction-retention: 1h under cluster.etcd.extraArgs. These are valid etcd flags supported by Talos Linux via the extraArgs field. Hourly compaction prevents revision bloat from accumulating, making manual defragmentation largely unnecessary unless disk space reclamation is explicitly needed.

Standards Compliance

  • Conventional Commit: Title fix(talos): replace etcd nightly defrag with hourly auto-compaction follows the convention.
  • Safety: Removes a privileged pod, improving security posture. No secrets or age keys are committed.
  • Structure: Changes follow the repo structure (talos/patches/ for Talos config, kubernetes/apps/ for manifests).
  • Validation: PR body confirms validate-pr.sh passed and talhelper genconfig succeeds.

Must Check Items

  • Validate manifest against target cluster version: The etcd extraArgs (auto-compaction-mode, auto-compaction-retention) are standard etcd flags supported across all recent etcd versions (3.4+) used by Talos. No version-specific incompatibilities identified.
  • Check for resource quota / limit changes: No new resources are added; an existing workload is removed. No quota impact.

Unknowns or Needs Verification

  • One-time Defrag Requirement: The PR notes recommend running talosctl etcd defrag manually after apply to reclaim already-wasted space. This is expected behavior when switching from defrag-only to compaction-first strategies. Ensure this step is documented in runbooks if not already present, though it is outside the scope of this PR diff.
  • Talos Version Compatibility: While extraArgs is a stable Talos feature, confirm the target Talos version supports these specific etcd flags without deprecation warnings. Standard etcd flags have been supported for years.

No blocker or major issues found. The change is clean, well-justified, and improves cluster security.

@Tanguille
Tanguille merged commit 1bcd443 into main Aug 2, 2026
15 checks passed
@Tanguille
Tanguille deleted the feat/etcd-auto-compaction branch August 2, 2026 10:45
Tanguille added a commit that referenced this pull request Aug 21, 2026
* fix(etcd): restore the defrag CronJob at a weekly cadence

#4290 replaced the daily defrag with hourly auto-compaction and noted a
one-time `talosctl etcd defrag` per node was still needed; that never ran.

Compaction is doing its job -- in-use held at 137-160MB across the last 20
days -- but it cannot shrink the file, so free space ramped ~8MB/day and the
db grew 185MB -> 341MB, tripping etcdDatabaseHighFragmentationRatio (57%) on
all three members. Only defrag reclaims that.

Weekly rather than the daily cadence it ran at before, since compaction now
holds the keyspace flat and the rule only has the fragmentation ramp to clear.
Image bumped v0.42.0 -> v0.43.0.

* style(etcd-defrag): trim the cadence comment to measured facts
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant