Skip to content

runc-shim: don't hold the service lock across runc create#13483

Merged
AkihiroSuda merged 1 commit into
containerd:mainfrom
AkihiroSuda:fix-lima-5030
Jun 1, 2026
Merged

runc-shim: don't hold the service lock across runc create#13483
AkihiroSuda merged 1 commit into
containerd:mainfrom
AkihiroSuda:fix-lima-5030

Conversation

@AkihiroSuda

@AkihiroSuda AkihiroSuda commented May 27, 2026

Copy link
Copy Markdown
Member

The task service guards its containers map with s.mu, and getContainer() takes it on behalf of effectively every task RPC (State, Connect, Stats, Wait, Pause, Kill, ...). Create() held s.mu for its whole duration, including runc.NewContainer(), which runs the actual runc create.

runc create can be slow on a loaded host. While it runs, any concurrent task RPC blocks on s.mu. The tasks service applies a 2s timeout to State (io.containerd.timeout.task.state), so a concurrent State waits on s.mu, exceeds the deadline, and the ttrpc call is abandoned -- the late shim reply then shows up as:

ttrpc: received message on inactive stream stream=3

Since deadline errors are now surfaced to clients, this is treated as a fatal failure and the just-created container is torn down right after start (observed on Lima/vz: nginx -> Exited (1)).

Move runc.NewContainer() out of the s.mu critical section, mirroring the runtime v1 shim lock optimization. s.mu is taken only once the container exists, to guard the map and the remaining (fast) setup, so a slow create no longer blocks concurrent State and other lookups. preStart/handleStarted/cleanup only use s.lifecycleMu, so early-exit handling is unchanged.

See:

The regression is caused by f078cebbd


+ limactl shell default nerdctl ps -a
time="2026-05-27T02:56:35Z" level=warning msg="treating lima version \"0c93a37\" from \"/Users/runner/.lima/default/lima-version\" as very latest release"
CONTAINER ID    IMAGE                                              COMMAND                   CREATED           STATUS                      PORTS                     NAMES
3f67f52a5931    ghcr.io/stargz-containers/nginx:1.19-alpine-org    "/docker-entrypoint.…"    10 seconds ago    Exited (1) 5 seconds ago    127.0.0.1:8080->80/tcp    nginx
+ limactl shell default nerdctl logs nginx
time="2026-05-27T02:56:36Z" level=warning msg="treating lima version \"0c93a37\" from \"/Users/runner/.lima/default/lima-version\" as very latest release"
+ [[ -z '' ]]
+ limactl shell default journalctl --user -u containerd
[...]
May 27 02:55:49 lima-default containerd-rootless.sh[1173]: time="2026-05-27T02:55:49.956586096Z" level=info msg="containerd successfully booted in 7.782954s"
May 27 02:56:25 lima-default containerd-rootless.sh[1173]: time="2026-05-27T02:56:25.445537685Z" level=info msg="connecting to shim 3f67f52a59314ed6fc4e1048b0e2c826ab26df575cec4cbf38619beb754dbebd" address="unix:///run/containerd/s/56dfcbff8ef161f104b965a6f02b0158fca28ed1beba7df4c255935edf3a9122" namespace=default protocol=ttrpc version=3
May 27 02:56:29 lima-default containerd-rootless.sh[1173]: time="2026-05-27T02:56:29.753250886Z" level=error msg="ttrpc: received message on inactive stream" stream=3

Note: used Claude

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 reduces lock contention in the runc v2 shim task service by avoiding holding the global service.mu (which guards the containers map) while executing runc create during Create(). This prevents unrelated task RPCs (e.g., State, Stats, Connect) from blocking behind a potentially slow container creation and timing out.

Changes:

  • Move runc.NewContainer() (which runs runc create) outside of the s.mu critical section in Create().
  • Add an explanatory comment documenting why s.mu should not be held across runc create.

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

Comment thread cmd/containerd-shim-runc-v2/task/service.go
@AkihiroSuda AkihiroSuda added the cherry-pick/2.3.x Change to be cherry picked to release/2.3 label May 27, 2026
@AkihiroSuda

Copy link
Copy Markdown
Member Author

@AkihiroSuda
AkihiroSuda marked this pull request as ready for review May 27, 2026 05:22
Copilot AI review requested due to automatic review settings May 27, 2026 05:22
@AkihiroSuda

Copy link
Copy Markdown
Member Author

/cherry-pick release/2.3

@k8s-infra-cherrypick-robot

Copy link
Copy Markdown

@AkihiroSuda: once the present PR merges, I will cherry-pick it on top of release/2.3 in a new PR and assign it to you.

Details

In response to this:

/cherry-pick release/2.3

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.

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 cmd/containerd-shim-runc-v2/task/service.go Outdated
@ningmingxiao

Copy link
Copy Markdown
Contributor

can you show the code container is torn down in nerdctl ? @AkihiroSuda

@AkihiroSuda

Copy link
Copy Markdown
Member Author

can you show the code container is torn down in nerdctl ? @AkihiroSuda

See:

@ningmingxiao

ningmingxiao commented May 27, 2026

Copy link
Copy Markdown
Contributor

I add some sleep

func (s *service) Create(ctx context.Context, r *taskAPI.CreateTaskRequest) (_ *taskAPI.CreateTaskResponse, err error) {
	s.mu.Lock()
	defer s.mu.Unlock()
	s.lifecycleMu.Lock()
	handleStarted, cleanup := s.preStart(nil)
	s.lifecycleMu.Unlock()
	defer cleanup()

	container, err := runc.NewContainer(ctx, s.platform, r)
	if err != nil {
		return nil, err
	}
	time.Sleep(time.Second * 3)

nerdctl run -d busybox sleep 1000 but I can't see container will be killed
only see

time="2026-05-27T16:48:10.057569440+08:00" level=error msg="ttrpc: received message on inactive stream" stream=3

@AkihiroSuda

@AkihiroSuda

Copy link
Copy Markdown
Member Author

So far, the issue is only seen in Lima's CI:

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 no new comments.

The task service guards its containers map with s.mu, and getContainer()
takes it on behalf of effectively every task RPC (State, Connect, Stats,
Wait, Pause, Kill, ...). Create() held s.mu for its whole duration,
including runc.NewContainer(), which runs the actual `runc create`.

`runc create` can be slow on a loaded host. While it runs, any concurrent
task RPC blocks on s.mu. The tasks service applies a 2s timeout to State
(io.containerd.timeout.task.state), so a concurrent State waits on s.mu,
exceeds the deadline, and the ttrpc call is abandoned -- the late shim
reply then shows up as:

    ttrpc: received message on inactive stream stream=3

Since deadline errors are now surfaced to clients, this is treated as a
fatal failure and the just-created container is torn down right after
start (observed on Lima/vz: nginx -> Exited (1)).

Move runc.NewContainer() out of the s.mu critical section, mirroring the
runtime v1 shim lock optimization. s.mu is taken only once the container
exists, to guard the map and the remaining (fast) setup, so a slow create
no longer blocks concurrent State and other lookups.
preStart/handleStarted/cleanup only use s.lifecycleMu, so early-exit
handling is unchanged.

See lima-vm/lima#5030.

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Signed-off-by: Akihiro Suda <[email protected]>
@AkihiroSuda
AkihiroSuda requested a review from a team May 29, 2026 15:57
@github-project-automation github-project-automation Bot moved this from Needs Triage to Review In Progress in Pull Request Review Jun 1, 2026
@AkihiroSuda
AkihiroSuda added this pull request to the merge queue Jun 1, 2026
@AkihiroSuda

Copy link
Copy Markdown
Member Author

/cherry-pick release/2.3

@k8s-infra-cherrypick-robot

Copy link
Copy Markdown

@AkihiroSuda: once the present PR merges, I will cherry-pick it on top of release/2.3 in a new PR and assign it to you.

Details

In response to this:

/cherry-pick release/2.3

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.

@github-merge-queue
github-merge-queue Bot removed this pull request from the merge queue due to failed status checks Jun 1, 2026
@AkihiroSuda
AkihiroSuda added this pull request to the merge queue Jun 1, 2026

@mikebrow mikebrow left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

concern over possible unforeseen timing changes

handleStarted, cleanup := s.preStart(nil)
s.lifecycleMu.Unlock()
defer cleanup()

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

perhaps a mux for each r.ID, to hold lock for each, across the newcontainer + task create event + cgroup oom monitor + started tasks?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

Not sure. s.send doesn't seem to alter the struct s

@mikebrow mikebrow Jun 1, 2026

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

kk

FYI @fuweid ... might "enhance" the parallelism of sidecar/init/containers pls be on the lookout

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

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

The lock behaviour was there for 7 years. To be honest, it's not easy-review one.
BTW, @AkihiroSuda could you please remove the AI-co-author next time? I would like to update project-check to check this. I am not saying we can't use AI. just want the sign-off one is real person. Thanks

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

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

BTW, @AkihiroSuda could you please remove the AI-co-author next time? I would like to update project-check to check this. I am not saying we can't use AI. just want the sign-off one is real person. Thanks

I'm not sure. The sign-off was added by myself, not by AI.
(IIUC, Co-Authored-by does not count as a sign-off)

Co-Authored-By: Claude Opus 4.7 (1M context) <[email protected]>
Signed-off-by: Akihiro Suda <[email protected]>

We should have a solid policy anyway.
Could you open an issue or a PR against https://github.com/containerd/project/blob/main/CONTRIBUTING.md#sign-your-work ?

Merged via the queue into containerd:main with commit c8802b6 Jun 1, 2026
50 checks passed
@github-project-automation github-project-automation Bot moved this from Review In Progress to Done in Pull Request Review Jun 1, 2026
@k8s-infra-cherrypick-robot

Copy link
Copy Markdown

@AkihiroSuda: new pull request created: #13512

Details

In response to this:

/cherry-pick release/2.3

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.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

cherry-pick/2.3.x Change to be cherry picked to release/2.3 easy-to-review Easy to review size/XS

Projects

Archived in project

Development

Successfully merging this pull request may close these issues.

9 participants