Skip to content

Add defer in event of mid-function failures in RunPodSandbox to avoid mount leaks#13399

Merged
samuelkarp merged 1 commit into
containerd:mainfrom
lauralorenz:13355-nri-hook-leak
Jun 9, 2026
Merged

Add defer in event of mid-function failures in RunPodSandbox to avoid mount leaks#13399
samuelkarp merged 1 commit into
containerd:mainfrom
lauralorenz:13355-nri-hook-leak

Conversation

@lauralorenz

@lauralorenz lauralorenz commented May 13, 2026

Copy link
Copy Markdown
Contributor

Add a defer with StopSandbox ShutdownSandbox in it before we start the RunPodSandbox hooks so if there is a failure in one of them, the mounts are still cleaned up. This rollback defer is active for any failures between the StartSandbox it directly follows and the successful addition of the sandbox to the sandbox store.

Before this PR / bad

lauralorenz@lauralorenz:cri-tools$ make critest
# containerd is running locally from main with root /var/lib/containerd-critest and state /var/lib/containerd-critest/state
lauralorenz@lauralorenz:cri-tools$ sudo ./build/bin/linux/$(go env GOARCH)/critest     --runtime-endpoint=unix:///run/containerd/containerd.sock --nri-socket=/var/run/nri/nri.sock    --ginkgo.vv     --ginkgo.focus="should propagate RunPodSandbox plugin error, clean up resources, and allow immediate retry"
lauralorenz@lauralorenz:cri-tools$ sudo rm -rf /var/lib/containerd-critest/state
rm: cannot remove '/var/lib/containerd-critest/state/io.containerd.runtime.v2.task/k8s.io/9e98e9d62868198e2bf07260e25b79a6dc9ed12eec7ddff8183b4f9df681b440/rootfs': Device or resource busy
rm: cannot remove '/var/lib/containerd-critest/state/io.containerd.grpc.v1.cri/sandboxes/9e98e9d62868198e2bf07260e25b79a6dc9ed12eec7ddff8183b4f9df681b440/shm': Device or resource busy

After this PR / good

# containerd is running locally from this PR with same root/state dirs as above
lauralorenz@lauralorenz:cri-tools$ sudo ./build/bin/linux/$(go env GOARCH)/critest     --runtime-endpoint=unix:///run/containerd/containerd.sock --nri-socket=/var/run/nri/nri.sock    --ginkgo.vv     --ginkgo.focus="should propagate RunPodSandbox plugin error, clean up resources, and allow immediate retry"
lauralorenz@lauralorenz:cri-tools$ sudo rm -rf /var/lib/containerd-critest/state
lauralorenz@lauralorenz:cri-tools$ 

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

This PR adds rollback cleanup after a sandbox has been started so failed RunPodSandbox execution does not leave sandbox resources running.

Changes:

  • Adds a deferred post-start rollback that attempts to stop the sandbox when RunPodSandbox returns an error.
Comments suppressed due to low confidence (2)

internal/cri/server/sandbox_run.go:321

  • This logs the outer err instead of the derr returned by StopSandbox, so the rollback failure can be reported with the wrong error (or no error at all after later short-variable returns). That makes diagnosing failed cleanup unreliable.
				log.G(ctx).WithError(err).Errorf("failed to stop sandbox %q on rollback", id)

internal/cri/server/sandbox_run.go:320

  • Stopping the sandbox is not enough for this rollback path: after this defer runs, the existing cleanup deletes the CRI/core sandbox metadata and releases the lease, so there is no later RemovePodSandbox path to call ShutdownSandbox. For sandbox controllers where Stop only stops the instance and Shutdown deletes the shim/sandbox resources, this can still leave an orphaned stopped sandbox/shim even though the metadata has been removed.
			if derr := c.sandboxService.StopSandbox(deferCtx, sandbox.Sandboxer, id); derr != nil {

💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.

Comment thread internal/cri/server/sandbox_run.go Outdated
Comment thread internal/cri/server/sandbox_run.go Outdated
Comment thread internal/cri/server/sandbox_run.go Outdated
Comment on lines +315 to +316
// Stop the sandbox on any upcoming NRI hook failures.
defer func() {

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

I have a gemini written test for this in another branch that is fine, but its very specific to this rollback and I think the NRI tests from the NRI branch in cri-tools tests this more meaningfully, even if its more coarsely. Overall the many rollback variants for this function (e.g. sandbox rollsback but networking doesn't; sandbox doesn't and networking sees the bad cleanupErr and so it doesn't; etc etc) don't have direct unit test coverage. Anyways that's all to say I'm looking for an IRL person to advise on this.

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Discussion offline:

  • Could use failpoint integration system to trigger NRI plugin failure(s) and then test if we had a mount leak/rollback properly.
  • Can check what mounts there are or read /proc/mount (before/after check is the easiest option)
  • Not a super pressing need to have unit tests for this/all of the defer unrolls, as the integration test above is a better behavior check

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

Discussed IRL with @samuelkarp not to add these suggested unit tests against this behavior in this PR

@lauralorenz
lauralorenz force-pushed the 13355-nri-hook-leak branch from 50fc5d8 to a8df1bb Compare May 14, 2026 22:19
@lauralorenz
lauralorenz force-pushed the 13355-nri-hook-leak branch from 644fd21 to e9caa79 Compare May 14, 2026 22:51
@lauralorenz lauralorenz changed the title [WIP] Add defer to stopSandbox to avoid leaks Add defer for StopSandbox in event of mid-function failures in RunPodSandbox to avoid mount leaks May 14, 2026
@lauralorenz
lauralorenz marked this pull request as ready for review May 14, 2026 22:53
Copilot AI review requested due to automatic review settings May 14, 2026 22:53

Copilot AI left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

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

Pull request overview

Copilot reviewed 1 out of 1 changed files in this pull request and generated 1 comment.

Comment thread internal/cri/server/sandbox_run.go Outdated
Comment on lines +315 to +321
// Stop the sandbox if we fail before adding it to store.
rollbackSandbox := true
defer func() {
if retErr != nil && rollbackSandbox {
deferCtx, deferCancel := util.DeferContext()
defer deferCancel()
cleanupErr = c.sandboxService.StopSandbox(deferCtx, sandbox.Sandboxer, id)

Copy link
Copy Markdown
Contributor Author

Choose a reason for hiding this comment

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

sandboxService.StopSandbox alone will call cleanupSandboxFiles (like this one) which I think is why that solves the problem as described in #13355; I replaced it wholesale for sandboxService.ShutdownSandbox which will both stop the sandbox container and clean up its entire root and state directories as well.

@lauralorenz
lauralorenz force-pushed the 13355-nri-hook-leak branch from e9caa79 to c30f478 Compare May 15, 2026 22:33
@lauralorenz lauralorenz changed the title Add defer for StopSandbox in event of mid-function failures in RunPodSandbox to avoid mount leaks Add defer in event of mid-function failures in RunPodSandbox to avoid mount leaks May 15, 2026
@lauralorenz

Copy link
Copy Markdown
Contributor Author

/retest

@k8s-ci-robot

Copy link
Copy Markdown

@lauralorenz: Cannot trigger testing until a trusted user reviews the PR and leaves an /ok-to-test message.

Details

In response to this:

/retest

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

Between starting the sandbox and adding it to the
sandbox store, there are opportunities for failures
including in any NRI RunPodSandbox prehooks. This defer
is added to that period so if they fail, this function
will try to clean it up itself. If the sandbox is
already added to the persistent store, it will not attempt
to stop the sandbox as it can now be recognized by other
components from the CRI store. ShutdownSandbox is used
instead of StopSandbox as it both stops it and cleans up
all its directories.

Signed-off-by: lauralorenz <[email protected]>
@lauralorenz

Copy link
Copy Markdown
Contributor Author

The failing CI checks are mostly Vagrant integration (there is one kubernetes node e2e one fwiw), vary on OS/platform, vary by which test is failing, and there is one successful run of this workflow against this branch, so I'm inclined to consider these flakes. I'm sending an empty amend to kick it

Screenshot 2026-05-28 at 2 38 07 PM

5/13

# [Vagrant integration (fedora/43-cloud-base, systemd, runc)](https://github.com/containerd/containerd/actions/runs/25944603119/job/76270183034#logs)
    default: --- FAIL: TestCRIImagePullTimeout (0.00s)
    default:     --- PASS: TestCRIImagePullTimeout/NoDataTransferredWithTransferService (10.01s)
    default:     --- PASS: TestCRIImagePullTimeout/HoldingContentOpenWriterWithLocalPull (26.80s)
    default:     --- FAIL: TestCRIImagePullTimeout/SlowCommitWriterWithLocalPull (27.50s)
    default:     --- PASS: TestCRIImagePullTimeout/SlowCommitWriterWithTransferService (52.18s)
    default:     --- FAIL: TestCRIImagePullTimeout/NoDataTransferredWithLocalPull (20.01s)
    default:     --- PASS: TestCRIImagePullTimeout/HoldingContentOpenWriterWithTransferService (32.15s)
    default: FAIL

5/14
1

# One set passed

2

# [Vagrant integration (almalinux/9, cgroupfs, runc)](https://github.com/containerd/containerd/actions/runs/25890184596/job/76091757260#logs)
    default: --- FAIL: TestFailFastWhenConnectShim (0.00s)
    default:     --- PASS: TestFailFastWhenConnectShim/abstract-unix-socket-v2 (0.00s)
    default:     --- FAIL: TestFailFastWhenConnectShim/normal-unix-socket-v2 (0.00s)

3

[Vagrant integration (almalinux/9, cgroupfs, runc)](https://github.com/containerd/containerd/actions/runs/25890220571/job/76091829481#logs)
    default: --- FAIL: TestFailFastWhenConnectShim (0.00s)
    default:     --- PASS: TestFailFastWhenConnectShim/abstract-unix-socket-v2 (0.00s)
    default:     --- FAIL: TestFailFastWhenConnectShim/normal-unix-socket-v2 (0.00s)
[Vagrant integration (almalinux/9, systemd, runc)](https://github.com/containerd/containerd/actions/runs/25890220571/job/76091829467#logs)
    default: --- FAIL: TestContainerExecLargeOutputWithTTY (4.32s)

5/15

[Vagrant integration (fedora/43-cloud-base, systemd, runc)](https://github.com/containerd/containerd/actions/runs/25944603119/job/76270183034#logs)
    default: --- FAIL: TestCRIImagePullTimeout (0.00s)
    default:     --- PASS: TestCRIImagePullTimeout/NoDataTransferredWithTransferService (10.01s)
    default:     --- PASS: TestCRIImagePullTimeout/HoldingContentOpenWriterWithLocalPull (26.80s)
    default:     --- FAIL: TestCRIImagePullTimeout/SlowCommitWriterWithLocalPull (27.50s)
    default:     --- PASS: TestCRIImagePullTimeout/SlowCommitWriterWithTransferService (52.18s)
    default:     --- FAIL: TestCRIImagePullTimeout/NoDataTransferredWithLocalPull (20.01s)
    default:     --- PASS: TestCRIImagePullTimeout/HoldingContentOpenWriterWithTransferService (32.15s)
    default: FAIL

@lauralorenz
lauralorenz force-pushed the 13355-nri-hook-leak branch from c30f478 to 2b2b80f Compare May 28, 2026 21:52
@samuelkarp

Copy link
Copy Markdown
Member

/ok-to-test

@lauralorenz

Copy link
Copy Markdown
Contributor Author

/retest

@github-project-automation github-project-automation Bot moved this from Needs Triage to Review In Progress in Pull Request Review Jun 9, 2026
@samuelkarp
samuelkarp added this pull request to the merge queue Jun 9, 2026
Merged via the queue into containerd:main with commit ade39c7 Jun 9, 2026
88 of 90 checks passed
@github-project-automation github-project-automation Bot moved this from Review In Progress to Done in Pull Request Review Jun 9, 2026
@samuelkarp samuelkarp added cherry-pick/2.2.x Change to be cherry picked to release/2.2 branch cherry-pick/2.3.x Change to be cherry picked to release/2.3 labels Jun 22, 2026
@samuelkarp

Copy link
Copy Markdown
Member

/cherrypick release/2.3
/cherrypick release/2.2

@k8s-infra-cherrypick-robot

Copy link
Copy Markdown

@samuelkarp: new pull request created: #13644

Details

In response to this:

/cherrypick release/2.3
/cherrypick release/2.2

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@k8s-infra-cherrypick-robot

Copy link
Copy Markdown

@samuelkarp: new pull request created: #13645

Details

In response to this:

/cherrypick release/2.3
/cherrypick release/2.2

Instructions for interacting with me using PR comments are available here. If you have questions or suggestions related to my behavior, please file an issue against the kubernetes-sigs/prow repository.

@samuelkarp samuelkarp added cherry-picked/2.2.x PR commits are cherry-picked into release/2.2 branch cherry-picked/2.3.x PR commits are cherry picked into release/2.3 branch and removed cherry-pick/2.2.x Change to be cherry picked to release/2.2 branch cherry-pick/2.3.x Change to be cherry picked to release/2.3 labels Jul 1, 2026
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cherry-picked/2.2.x PR commits are cherry-picked into release/2.2 branch cherry-picked/2.3.x PR commits are cherry picked into release/2.3 branch ok-to-test size/S

Projects

Development

Successfully merging this pull request may close these issues.

containerd fatal on restart When NRI plugin fails on RunPodSandbox, containerd leaks resources

6 participants