kai-server: k3s-server process sustains ~4.6 cores with no identified cause #839
Labels
No labels
burndown-2026-06
burndown-2026-08
autonomy
async-consult
autonomy
epic
autonomy
headless
autonomy
live-collab
coherence-core
priority
P0
priority
P1
priority
P2
priority
P3
priority
P4
qa-fixture
role/advocate
role/director
role/exec
role/frontend
role/gamedev
role/human
role/platform
role/qa
role/science
role/sysadmin
state
ambient
No milestone
No project
No assignees
1 participant
Notifications
Due date
No due date set.
Dependencies
No dependencies set
Reference
coilyco-flight-deck/infrastructure#839
Loading…
Reference in a new issue
No description provided.
Delete branch "%!s()"
Deleting a branch is permanent. Although the deleted branch may continue to exist for a short time before it actually gets removed, it CANNOT be undone in most cases. Continue?
Summary
The
k3s-serverprocess on kai-server holds roughly 4.6 of 28 logical cores continuously. Together with the Eco game server it accounts for essentially the entire node CPU load. I could not establish why, and I could not establish whether it is new.Evidence
Two samples a few minutes apart, taken 2026-08-15 around 16:38-16:40Z:
This is consistent with the node totals rather than a sampling artifact.
get_cpu_inforeported 17.6% of 28 cores (about 4.9 cores) and the kubelet summary reportedusageNanoCores: 6277100654(about 6.3 cores). k3s plus Eco accounts for nearly all of it.Hypotheses ruled out
someavg300 is 0.81% andfullis 0.00%, so nothing is actually starved for CPU.Hypothesis not tested
Kine/sqlite datastore write amplification is the obvious remaining candidate, given the node also showed a sustained write burst. I could not check it:
/var/lib/rancher/k3s/server/db/state.dbis outside the node-stats-mcp readable-root allowlist. Filed separately against node-stats-mcp.Missing baseline
There is no history to compare against. kai-server does not export hostmetrics to SigNoz, so there is no record of whether 4.6 cores is a recent change or the steady state for this node. Also filed separately.
Next steps
Acceptance
Either the 4.6 cores is explained and accepted as normal for this node, or the driver is identified and reduced.
Negative result: removing the atlas crashloop changed nothing
Recording this so the next person does not re-test it.
Between the original samples and now, the
forgejo-runner-deploy-atlasStatefulSet was deleted (#835, PR #843), its ~5-minute restart cycle stopped, and the FluxappsKustomization went fromReady=Falsewith a permanently retrying health check toReady=True. Three wedged namespaces also finalized in the same window.k3s-serveris unchanged:EcoServer is also flat at 133.5% and 5.05 GB.
giteadrifted from 13.7% down to 10.2%, consistent with the external crawl volume tapering rather than with anything that changed here.What this rules out
ProgressingWithRetryloopTerminatingsince 2026-08-06None of those were the driver. The 4.6 cores are something else, and they are steady rather than incident-linked.
The untested hypothesis from the original report still stands as the leading candidate: kine/sqlite datastore write amplification, blocked on the allowlist gap in
coilyco-flight-deck/node-stats-mcp#23. The missing hostmetrics baseline in #841 remains the other thing that would settle whether 4.6 cores is a regression at all or simply what this node has always drawn.The premise of this issue is wrong. k3s-server is not running hot.
I measured with the wrong instrument. Correcting with the authoritative one.
process_cpu_seconds_totalis a monotonic counter the kernel maintains and k3s exposes on its metrics endpoint. Sampled as a delta over a real 79 second window:2.06 cores, not 4.6.
And the same counter answers the baseline question I claimed was unanswerable without #841. Total CPU consumed divided by process uptime:
Current draw is below this process's own long-run average. There is no anomaly and there never was one. Nothing needs explaining.
What I did wrong
I used the
cpu_percentfield fromget_k3s_process_attribution, which is psutil-derived and sampled, and it reported 448% and 465.5% on two reads. I treated two agreeing reads as confirmation. Two agreeing reads from the same biased instrument confirm nothing, and I should have gone to the counter instead of sampling harder. The/metricsendpoint was reachable through the guarded surface the whole time.The "hypotheses ruled out" section above is still sound as far as it goes, and the later negative result about atlas removal is still true, but all of it was chasing a number that was roughly 2x too high.
Closing this, with one real finding carried forward
The one thing worth keeping is something I found while checking: every datastore operation is averaging around 190ms, which is genuinely wrong for a local backend and is unrelated to CPU. Filed separately rather than left buried under a wrong headline.
Also noted while here, neither alarming on its own:
go_goroutinesis 10,055 and the apiserver is serving 100 concurrent configmap watches plus 37 on secrets.