charts/redpanda: opt-in chroot tuning init container for host tuners#1522
charts/redpanda: opt-in chroot tuning init container for host tuners#1522david-yu wants to merge 1 commit into
Conversation
Cross-cloud validation: GKE + AKSTested the PR (HEAD GKE — Ubuntu 24.04 / kernel 6.8.0-1049-gke /
|
| Tuner | EKS m8gd.metal-24xl (AL2023 ARM, kernel 6.1.168) | GKE Ubuntu 24.04 (kernel 6.8) | AKS Ubuntu 22.04 (kernel 5.15) |
|---|---|---|---|
disk_irq |
❌ pre-existing kernel-level issue: /proc/irq/0/smp_affinity: no such file or directory |
✅ APPLIED | ✅ APPLIED |
disk_scheduler |
✅ APPLIED | ✅ APPLIED | ✅ APPLIED |
disk_nomerges |
✅ APPLIED | ✅ APPLIED | ✅ APPLIED |
net |
✅ APPLIED | ✅ APPLIED | ✅ APPLIED |
3 of 4 work on every cloud; disk_irq only fails on AL2023 ARM (the AWS metal SKU). That failure is exposed by the chroot path but caused by AL2023 ARM not having a writeable smp_affinity for IRQ 0 — not a chart problem (tracked separately for rpk to skip un-pinnable IRQs rather than error).
Minor non-blocker
Both GKE and AKS show fstrim errors with fork/exec /usr/bin/which: no such file or directory. That's rpk's tuner using which to detect fstrim's presence and Ubuntu's minimal container image not having it. Doesn't affect any of the four host-mode tuners and fstrim is ENABLED=false anyway. Worth a follow-up rpk fix but not a PR 1522 issue.
Setup notes (for reproducibility)
- Image:
pr1522-b876709cbuilt and pushed to ephemeral registries (GAR for GKE pull, ACR for AKS pull). Both arches (linux/amd64, linux/arm64) in the same manifest. - CR: minimal — single replica, no TLS, no NodePort, no anti-affinity (single-node test).
- Namespace label:
pod-security.kubernetes.io/enforce: privileged(required by chart's tuning init container; same astune_aio_events: truein PR pre-change behavior). - Clusters/ACR/GAR torn down post-test.
|
This PR is stale because it has been open 5 days with no activity. Remove stale label or comment or this will be closed in 5 days. |
|
This PR is stale because it has been open 5 days with no activity. Remove stale label or comment or this will be closed in 5 days. |
|
This PR is stale because it has been open 5 days with no activity. Remove stale label or comment or this will be closed in 5 days. |
|
This PR is stale because it has been open 5 days with no activity. Remove stale label or comment or this will be closed in 5 days. |
|
This PR is stale because it has been open 5 days with no activity. Remove stale label or comment or this will be closed in 5 days. |
|
This PR is stale because it has been open 5 days with no activity. Remove stale label or comment or this will be closed in 5 days. |
|
This PR is stale because it has been open 5 days with no activity. Remove stale label or comment or this will be closed in 5 days. |
b876709 to
dd32bd9
Compare
✅ Snyk checks have passed. No issues have been found so far.
💻 Catch issues earlier using the plugins for VS Code, JetBrains IDEs, Visual Studio, and Eclipse. |
|
Note for reviewers / whoever cuts the next release (found while validating this PR on GKE/AKS/EKS, unrelated to the tuner change itself): main's chart currently renders the sidecar args When the next operator release is cut, the Interim workaround for anyone hitting it today: 🤖 Generated with Claude Code |
a7ae4e6 to
2332e55
Compare
Adds tuning.apply_host_tuners (default false). When enabled, the tuning init container builds a chroot to the host filesystem and runs `rpk redpanda tune all` inside the host's network namespace, so tuners that need host /sys, /proc, NICs, and block devices actually apply. Plumbed through the v1alpha2 Redpanda and StretchCluster CRDs. Turning the flag on default-enables the seven tuners the chroot path exists to fix: tune_disk_irq, tune_disk_scheduler, tune_disk_nomerges, tune_network, tune_fstrim, tune_disk_write_cache, and tune_cpu. The last three are safe everywhere: rpk exempts disk_write_cache from its enabled-but-unsupported exit(1) outside GCP, fstrim gets the host systemd D-Bus and /etc/systemd/system it needs from the chroot's bind mounts, and cpu no-ops without cpufreq sysfs while doing real governor work on metal instance types. Chroot mechanics hardened by end-to-end runs on GKE (COS), AKS (Ubuntu), and EKS (AL2023): - Bind-mount /bin and /sbin and invoke /bin/bash: COS is not usr-merged (no /usr/bin/bash), so the chroot previously failed outright there and host tuning silently no-oped. - Ship a which(1) shim in /opt/redpanda/bin (first on PATH inside the chroot): rpk's fstrim tuner shells out to which, broken on AKS's minimal Ubuntu image; the PATH export also guarantees the hwloc-*-redpanda binaries resolve for the cpu/disk_irq/net tuners. - HostToContainer (not Bidirectional) mount propagation: the chroot'd rpk runs in the container's own mount namespace and needs no container-to-host propagation, and Bidirectional leaked one stacked host mount of the datadir PVC per pod incarnation. Validated: GKE COS applies all 8 enabled tuners including the GCP-only disk_write_cache (rpk installs redpanda-fstrim.timer on the host); AKS and EKS apply 7/8 with disk_write_cache correctly skipped as GCP-only. Opt-in only; the default tuning container is unchanged. Requires the same security posture as tune_aio_events (privileged, hostPath) and one pod per node. Closes K8S-101. Productionizes the chroot pattern from CORE-13685. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
2332e55 to
f42c913
Compare
Summary
Adds
tuning.apply_host_tuners(defaultfalse). When enabled, the tuning init container builds a chroot to the host filesystem and runsrpk redpanda tune allinside the host's network namespace — the tuners that previously failed inside the pod sandbox actually apply.UX:
apply_host_tuners: trueis the one switch users need. The chart now default-enablestune_disk_irq,tune_disk_scheduler,tune_disk_nomerges,tune_network,tune_fstrim,tune_disk_write_cache, andtune_cpuin the renderedrpkconfig when the flag is on, so the tuners the chroot path exists to fix actually run without the user having to mirror them by hand inconfig.rpk.tune_*. The three additions are safe everywhere: rpk exemptsdisk_write_cachefrom its enabled-but-unsupportedexit 1outside GCP (tune.go:167-174), fstrim gets exactly the environment it needs from the chroot (host systemd D-Bus via/run/systemd/private, unit files landing in the host's real/etc/systemd/system), and the cpu tuner is an applied no-op on VMs without cpufreq sysfs while doing real governor work on metal.Closes K8S-101. Productionizes the chroot pattern from CORE-13685 (Stephan Dollberg's experiment).
Why
The default tuning container runs
rpk redpanda tune allinside the pod's own namespaces. That works for sysctl-based tuners (aio_events, swappiness, THP) but the disk and net tuners can't see host/sys/block,/proc/sys/net, or host NICs, so they error with:…and rpk exits non-zero, crashlooping the init container for any user who sets these flags.
What changes
charts/redpanda/values.goTuning.ApplyHostTunersbool, defaultfalse. Whentrue,Tuning.Translate()also setstune_disk_irq/tune_disk_scheduler/tune_disk_nomerges/tune_network/tune_fstrim/tune_disk_write_cache/tune_cputotruein the renderedrpksection so the chroot path actually has tuners to run. Docs cover SCC / PSA requirements, the one-pod-per-node constraint, and the first-arg-wins merge semantics.charts/redpanda/statefulset.gostatefulSetInitContainerTuningOnHostpath that produces the chroot-mode init container.StatefulSetVolumesappends the host bind volumes only when the feature is enabled.charts/redpanda/testdata/template-cases.txtartuning-host-modecase + golden. Golden updated to include the four default-enabled flags..changes/unreleased/charts-redpanda-Added-20260512-host-tuners.yaml_statefulset.go.tpl,_values.go.tpl,values.schema.json,values_partial.gen.go, golden txtar.User-facing config (operator v2)
The chart is plumbed through
clusterSpecon the v1alpha2 Redpanda CR. One flag, no follow-on:That alone fires the four host-mode tuners. The chart's RPK config merge is first-arg-wins, so a per-tuner override in
config.rpk.tune_*loses to the chart's value — by design. Users who want a specific tuner off should leaveapply_host_tunersempty and wire host tuning via their own DaemonSet.How the chroot path works
Five workarounds layered in:
data_directoryinjection. The chart-renderedredpanda.yamlomitsredpanda.data_directory(the broker doesn't need it). rpk's disk tuners do, and rpk refuses to combine--dirswith--config. The scriptcp+seds a working copy into/var/tmp(because/tmpis not bind-mounted from the host) and points rpk at it.systemctlcan't traverse a chroot, so the script usesbusctlagainst the host's systemd to restart irqbalance after rpk rewrites IRQ affinity. Falls back topkill irqbalancefor non-systemd hosts.|| true ; exit 0so a single unsupported tuner (e.g. AWS lacksdisk_write_cache) doesn't crashloop the init container — the failure mode today./bin/bash, with/binand/sbinbind-mounted. GKE's Container-Optimized OS is not usr-merged — bash lives at/bin/bashand/usr/bin/bashdoes not exist — so the original/usr-only mount set left the chroot with no shell at all and host tuning silently no-oped on GKE (masked by the exit-code tolerance). On usr-merged hosts (Ubuntu, AL2023)/binand/sbinare symlinks into/usr, so the extra mounts resolve to the same content.whichshim in/opt/redpanda/bin(bind-mounted into the chroot, first onPATH). rpk's fstrim tuner shells out towhich, and AKS's minimal Ubuntu node image ships a broken/usr/bin/which(dangling alternatives symlink), which made fstrim report unsupported. ThePATHexport also guarantees thehwloc-*-redpandabinaries needed by thecpu/disk_irq/nettuners resolve regardless of host image.Host bind mounts are intentionally per-directory (
/bin /sbin /sys /proc /etc /usr /lib /lib64 /dev /var /run) rather than whole-/. Mounting/into/hostcreates mount-loops with/opt/redpanda; CORE-13685 found this the hard way. Propagation isHostToContainer, notBidirectional: the chroot'd rpk runs in the tuning container's own mount namespace and needs no container→host propagation — andBidirectionalpropagated the datadir PVC mount (which sits under the host-var subtree at/host/var/lib/redpanda/data) back onto the host's real/var/lib/redpanda/data, where it outlived the pod, stacking one leaked host mount per pod incarnation (observed live on GKE).Validation
Run 1 — EKS 1.33 / Amazon Linux 2023 / kernel 6.12, Redpanda 26.1.6, single replica
Before (no chroot patch — current behavior):
Init container CrashLoopBackOff (rpk exits non-zero).
After (
apply_host_tuners: true):Init exits 0, Redpanda broker comes up cleanly, admin API responds.
Run 2 — EKS 1.31 / AL2023 / kernel 6.1.168 ARM (Graviton4 m8gd.metal-24xl), Redpanda v25.3.4, 3 replicas
End-to-end run including OMB producer/consumer smoke test (details + artifacts). With
apply_host_tuners: trueas the only tuning knob on the CR, freshly-rolled broker pods showed:Three of four host-mode tuners
APPLIED=true ENABLED=true.disk_irqENABLED but failing on a pre-existing AL2023 kernel issue (open /proc/irq/0/smp_affinity: no such file or directory— rpk should skip IRQs without a writeablesmp_affinityrather than fail; tracked separately). The init container does NOT crashloop on this failure — the exit-code tolerance keeps the broker booting.OMB ran clean for 5 min @ 20 MB/s, 0 publish errors, p99 publish 26 ms.
Runs 3–5 — GKE (COS), AKS (Ubuntu), and EKS (AL2023), single replica, chart installed directly from this branch
Fresh clusters built for this PR (terraform + evidence in the internal
operator-tunersworkspace). Both runs usedtuning: {tune_aio_events: true, apply_host_tuners: true}as the only tuning config.GKE — Container-Optimized OS, e2-standard-4, K8s v1.35.5-gke, pd-balanced. These runs first exposed that the chroot was completely broken on COS (no
/usr/bin/bash; see workaround 4) — after the fix, all 8 default-enabled tuners apply, including the two that can only ever work on GCP hosts:Host-level verification: the data-dir PD's
queue/write_cacheflipped towrite through, andredpanda-fstrim.timerisactiveon the node (COS ships no distro fstrim.timer, so rpk installed its own through the chroot — exactly its designed behavior).AKS — Ubuntu, Standard_D4s_v5, K8s v1.35.5, managed-csi. 7 of 8 apply;
disk_write_cachecorrectly reportsSUPPORTED=false("only supported in GCP") and is skipped without failing the run (rpk's carve-out):fstrim on AKS also required the
whichshim (workaround 5).EKS — Amazon Linux 2023, m6id.xlarge with the data dir on local NVMe instance store, K8s v1.33.13-eks. Same shape as AKS — 7 of 8 apply,
disk_write_cachecorrectly skipped as GCP-only.fstrimstarts the distrofstrim.timer(verified active on the host),disk_schedulerverified[none]on the NVMe device, anddisk_irqapplies cleanly on m6id (the Run-2 IRQ0 failure was specific to metal ARM kernels).All three clusters passed a produce/consume smoke test with a healthy broker.
Lifecycle of host tuning state
What happens when you flip
apply_host_tuners(ortune_aio_events) back tofalse, and what about reboot?On the next pod replacement, the chart re-renders the StatefulSet:
tune_aio_eventsapply_host_tunersfalsetruefalsetruetrueSo turning the flag off and rolling pods does remove the chroot path and the host bind mounts. It does not, however, un-tune the host. The chart has no "untune" step — every kernel-level write the tuners made stays in place until something else reverses it.
fs.aio-max-nr/proc/sys/fs/aio-max-nrdisk_irqworks)/proc/irq/N/smp_affinityscheduler/nomerges/sys/block/nvmeXn1/queue/*net.core.rps_sock_flow_entries/sys/class/net/ethN/queues/tx-N/xps_cpusredpanda_node_tuner_state.yaml/var/run/(tmpfs)Practical consequences:
/var/run/redpanda_node_tuner_state.yamlis on tmpfs, so it's gone at every reboot and rpk re-runs all tuners on first pod start after boot (rather than skipping based on stale state). That's the right behavior for transient kernel state, but worth knowing if you're trying to reason about "did the tuner actually run this boot?"If you need to revert the host kernel state without a reboot (e.g. you turned the flag off mid-shift and want the change to take effect immediately), you have to either reboot the node or write a one-shot DaemonSet that resets the specific sysfs/sysctl values. The chart deliberately does not ship that — host de-tuning is a destructive operation on shared kernel state and shouldn't be silently performed when a user flips a chart value.
Security posture
Opt-in only. The default tuning container is unchanged. Enabling
apply_host_tunersrequires the same trust level astune_aio_eventsalready does — privileged container, root user, hostPath volumes.For secure k8s installations:
hostPathvolumes andprivileged: true. The built-inprivilegedSCC works. A custom SCC can be authored if narrower scope is required — the chart only mounts standard Linux directories (/bin /sbin /sys /proc /etc /usr /lib /lib64 /dev /var /run) plus the tuner state file at/var/run/redpanda_node_tuner_state.yaml.pod-security.kubernetes.io/enforce: privileged(this is also required today fortune_aio_events).Out of scope (deliberate)
rpk.tune_*flag as a first-class chart value. Today the chart exposestune_aio_events,tune_clocksource,tune_ballast_fileat the top level, andapply_host_tunersrolls up the seven host-mode flags. The rest are reachable viaconfig.rpk.tune_*if a user explicitly wants them on.--node-tuner-state-pathplumbing on the redpanda main container. The state file persists across pod restarts on the same node (so re-runs are no-op) but the broker doesn't need to read it; the broker comes up fine without it. Can be added later if dedicated-mode reporting wants it.disk_irqfailure on AL2023 ARM kernels (e.g.m8gd.metal-24xl) is a core/rpk-side issue, not a chart issue. The chroot path exposes IRQ 0's missingsmp_affinityto rpk, which then fails the whole tuner. Tracked separately — needsrpkto skip un-pinnable IRQs rather than error.Test plan
task lint— passestask generate— no diff after runninggo test ./charts/redpanda/ -run TestTemplate— passes (newtuning-host-modegolden case includes the 4 default-enabled flags)helm templatewithapply_host_tuners=truerenders the expected init container + volumes + the 4 host-modetune_*: trueflagshelm templatewith default values is byte-identical to pre-PR outputdisk_write_cache+fstrimvia host-installed timer (Run 3)disk_write_cachecorrectly skipped as GCP-only (Run 4)HostToContainerchange (verified across pod rolls on GKE)