Skip to content

ateom-gvisor: terminate a workload whose runsc containers are already gone - #30

Merged
teemow merged 2 commits into
giantswarmfrom
fork/ateom-terminate-gone-containers
Sep 13, 2026
Merged

teemow merged 2 commits into
giantswarmfrom
fork/ateom-terminate-gone-containers

Conversation

@teemow

@teemow teemow commented Sep 13, 2026

Copy link
Copy Markdown
Member

Carried patch for the line (giantswarm/giantswarm#37773, sub-issue of the kagent API v2 epic giantswarm/giantswarm#37705). Rebase-merge, one commit per patch; the second commit is the FORK.md ledger row.

Problem

TerminateWorkload checks each runsc container's state before deleting it. runsc state is fatal on a container runsc does not know (loading container: file does not exist, exit 128), so once a container is gone the terminate can never succeed. On gazelle (2026-09-13, Substrate 0.0.27-gs.8, worker image 0.0.27-gs.7) two crashed golden actors of superseded AgentTemplate revisions sat in DELETING with their worker assignment intact — kubectl ate get workers showed 2 of 4 workers ASSIGNED(1/1) — while the kagent controller logged failed to collect runtime revision … runsc state: exit status 128 every minute per template.

How the container gets lost: the golden boot crashes → the Run failure cleanup detaches the bundle's rootfs overlay (its runsc delete -force pause was killed by the 30 s cleanup budget) → the first terminate's runsc delete -force pause destroys the container state and then fails on the filestore file that lived on the detached overlay (destroying container: failed to delete filestore file … no such file or directory, exit 128) → every retry fails at runsc state pause.

Change

cleanupContainers lists the containers runsc knows under the actor's state root (runsc list -quiet; a root without state lists nothing) and checks and deletes only those; a container that is gone is logged and skipped. A runsc delete that fails once its container is gone (the filestore case) counts as done, so a crashed boot is torn down in the first attempt. Application containers first, the pause container last, as before.

Tests

TestCleanupContainers with a runsc stand-in (every container gone / application container gone, pause present / every container present / delete fails after removing the container / delete fails with the container still there / listing fails) and TestListArgs, in cmd/ateom-gvisor.

Lab proof (agentlab, 2026-09-13)

An AgentTemplate whose one skill carries a top-level version: (giantswarm/agent-skills@cb1fb768, the same crash as gazelle's vera) crash-loops its golden boot; the template is then changed. On 0.0.27-gs.7 the superseded revision was never collected in 56 minutes — the same Abortedrunsc delete: exit status 128runsc state: exit status 128 sequence, actor DELETING, worker ASSIGNED. On this branch's first dev build (skip only) the sweep after the failed first attempt logged runsc container is already gone, nothing to clean up, Actor terminated, and the worker went FREE; the delete tolerance in the final commit removes that first failed attempt.

Upstream

No upstream issue or pull request on this path (kagent-dev/substrate and agent-substrate/substrate searched 2026-09-13); agent-substrate#1518 is the sibling symptom for a runsc restore failure. The upstream-facing branch is upstream/ateom-terminate-gone-containers on the mirror main; listed in giantswarm/giantswarm#37742 (row 43).

@teemow
teemow requested a review from a team as a code owner September 13, 2026 19:38
teemow added a commit that referenced this pull request Sep 13, 2026
…are already gone (#30, 65867b3; giantswarm/giantswarm#37773, #37742 row 43)

Signed-off-by: Timo Derstappen <teemow@gmail.com>
… gone

TerminateWorkload cleans up the sandbox's runsc containers by checking each
one's state and then deleting it. `runsc state` is fatal on a container runsc
does not know (`loading container: file does not exist`, exit status 128), so
once a container was gone the terminate could never succeed: every retry
failed at the state check, atelet never reset the actor's directories, ateapi
never released the worker, and the actor stayed DELETING with its worker
assigned until the worker pod was replaced.

A container gets into that state on the ordinary path. When a golden boot
crashes, the Run failure cleanup detaches the bundle's rootfs overlay; the
first terminate then runs `runsc delete -force` on the stopped sandbox, which
destroys the container's state and fails afterwards on the filestore file
that lived on the detached overlay (`destroying container: failed to delete
filestore file ... no such file or directory`). The delete workflow retries,
and from the second attempt on `runsc state pause` fails for good. Observed on
a four-worker pool where two crashed golden actors of superseded templates
pinned two workers, the control plane retrying the delete every minute.

List the containers runsc knows under the actor's state root first
(`runsc list -quiet`; a root without container state lists nothing) and check
and delete only those, application containers first and the pause container
last. A container that is already gone is logged and skipped: it is already
cleaned up, and the terminate goes on to release everything else. A delete
that fails once its container is gone -- the filestore case above -- has
done its job and is logged instead of failing the terminate, so a crashed
boot is torn down in the first attempt.

Tests: cleanupContainers with a runsc stand-in -- every container gone, the
application container gone with the sandbox present, every container
present, a delete that fails after removing its container, a delete that
fails with the container still there, and a failing list (cmd/ateom-gvisor).

Signed-off-by: Timo Derstappen <teemow@gmail.com>
…are already gone (#30, c3e452c; giantswarm/giantswarm#37773, #37742 row 43)

Signed-off-by: Timo Derstappen <teemow@gmail.com>
@teemow
teemow force-pushed the fork/ateom-terminate-gone-containers branch from 0a45ac6 to 4455582 Compare September 13, 2026 20:53
@teemow
teemow merged commit 36d00f8 into giantswarm Sep 13, 2026
14 checks passed
@teemow
teemow deleted the fork/ateom-terminate-gone-containers branch September 13, 2026 21:13
teemow added a commit to giantswarm/kagent-upstream that referenced this pull request Sep 13, 2026
… gVisor worker's terminate collects a crashed golden actor (giantswarm/giantswarm#37773) (#32)

SUBSTRATE_VERSION 0.0.27-gs.7 -> 0.0.27-gs.9: v0.0.27-gs.9 = gs.8 + giantswarm/substrate#30, the worker (ateom-gvisor) whose TerminateWorkload skips runsc containers that are already gone and accepts a runsc delete that fails after removing its container. Before it a superseded AgentTemplate revision whose golden boot had crashed was never collected and its golden actor pinned one worker of the pool for good (gazelle 2026-09-13, two of four workers). The published chart stamps substrateWorkerPool.workerImage with the new worker; the platform's WorkerPool rolls once. FORK.md's pin row follows.

Signed-off-by: Timo Derstappen <teemow@gmail.com>
teemow added a commit that referenced this pull request Sep 14, 2026
…are already gone (#30, c3e452c; giantswarm/giantswarm#37773, #37742 row 43)

Signed-off-by: Timo Derstappen <teemow@gmail.com>
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant