Skip to content

shim: make container teardown timeouts configurable - #2855

Open
Jonas Heinle (Kataglyphis) wants to merge 1 commit into
microsoft:mainfrom
Kataglyphis:feature/configurable-teardown-timeout
Open

shim: make container teardown timeouts configurable#2855
Jonas Heinle (Kataglyphis) wants to merge 1 commit into
microsoft:mainfrom
Kataglyphis:feature/configurable-teardown-timeout

Conversation

@Kataglyphis

@Kataglyphis Jonas Heinle (Kataglyphis) commented Aug 6, 2026

Copy link
Copy Markdown

Heavy container builds need more than 30s to tear down. This PR makes the limit configurable.

Problem

Tearing down a process isolated container is host-side work: the layer filter stack is detached and the container's registry hives are flushed back into its scratch. The cost scales with how much the container touched the filesystem. Most workloads finish in well under a second, source builds do not.

Measured on my host: 117s for a single OpenCV build container. HcsShutDownComputeSystem returned in milliseconds, the completion notification arrived 117s later.

The shim gives up at 30s and terminates the container while its scratch is still being written. The snapshot is then permanently damaged - every later finalize fails with

hcsshim::ExportLayer <path>: The system cannot find the path specified. (0x3)

and it survives fresh snapshots and host reboots, because the unflushed hive deltas live inside sandbox.vhdx.

All silo processes do exit, so this is not a container-side problem. I tried overriding WaitToKillServiceTimeout and a full pre-exit teardown of non-essential services - both lost the notification identically.

Change

Two environment variables, which the shim inherits from containerd, named after the existing CONTAINERD_SHIM_RUNHCS_V1_WAIT_DEBUGGER:

Variable Bounds
CONTAINERD_SHIM_RUNHCS_V1_TEARDOWN_TIMEOUT both waits in hcsTask.close, and the delete command
CONTAINERD_SHIM_RUNHCS_V1_TASK_CLOSE_TIMEOUT the wait in hcsTask.DeleteExec

DeleteExec waits on the channel close() closes, so raising only the first would not help. When the second is unset and the first was raised, it is derived to cover close()'s worst case. Defaults stay 30s, so behaviour is unchanged unless a host opts in.

The PR also logs how long a successful shutdown took - the number you need to size the timeout, and currently not observable.

Left alone on purpose: the SIGKILL timer (guards the hosting UVM), cmd/runhcs (separate binary, already allows 5 minutes) and cmd/containerd-shim-lcow-v2 (different shim, same pattern though).

Verification

Go 1.26.5, windows/amd64: build, gofmt, go vet, golangci-lint with the CI-pinned v2.11 and go test ./cmd/containerd-shim-runhcs-v1/ all clean.

Happy to adapt anything to your guidelines.

@Kataglyphis
Jonas Heinle (Kataglyphis) force-pushed the feature/configurable-teardown-timeout branch from 1cd2944 to 6830a70 Compare August 6, 2026 10:50
Jonas Heinle (Kataglyphis) added a commit to Kataglyphis/Kataglyphis-ContainerHub that referenced this pull request Aug 6, 2026
…ement

Filed microsoft/hcsshim#2855 as a draft from
Kataglyphis/hcsshim:feature/configurable-teardown-timeout.

Corrects a wrong claim in the README: hcsshim enforces a DCO check in addition
to the Microsoft CLA. The repo README advertises only the CLA, so the PR went up
with a failing DCO gate and needed an amend with -s. Both the requirement and
the fix are now written down, and the in-tree patch carries the Signed-off-by
trailer.

Still open: the issue from ISSUE.md is not filed, the comment on
Windows-Containers#547 is not posted, and the runtime measurement still comes
from the constants-in-place build rather than the submitted env-var build.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Kataglyphis

Copy link
Copy Markdown
Author

@microsoft-github-policy-service agree

@Kataglyphis
Jonas Heinle (Kataglyphis) marked this pull request as ready for review August 7, 2026 08:25
@Kataglyphis
Jonas Heinle (Kataglyphis) requested a review from a team as a code owner August 7, 2026 08:25
Jonas Heinle (Kataglyphis) added a commit to Kataglyphis/Kataglyphis-ContainerHub that referenced this pull request Aug 7, 2026
…ry room

Both drivers now gate on the two conditions that cost hours when discovered
late. Both were manual checklist items in docs/windows-host-setup.md D3, and
both bit within the last 24 hours.

Assert-DiskHeadroom (both lanes): refuses below 40 GB free. Under ~25 GB
hcsshim stops failing honestly -- on 2026-08-06 a full chain ran 2.5 h and
died with "ninja is not recognized" at 4.8 GB free, and the poisoned
snapshots it left (0xb7, 0x20) cost two more runs to sidestep. -MinFreeGb
tunes the floor, -SkipHostChecks overrides deliberately.

Assert-ShimPatch (BuildKit lane only -- the classic lane's run+commit path
uses Hyper-V isolation, where the teardown-timeout defect does not apply):
the patched runhcs shim is a LOCAL patch pending microsoft/hcsshim#2855, and
any Stevedore/containerd update silently restores the stock binary. The
symptom is ExportLayer 0x3 at the first heavy media finalize, hours in,
after the compile is already paid for. Detection is by size because the shim
logs its effective timeout at Debug, which never reaches containerd's log --
so a KNOWN-STOCK size fails hard while an unrecognised size only warns,
since that list will rot as hcsshim moves and refusing to build on a newer
patched shim would be worse than the risk.

Invoke-BkStage takes -MaxAttempts (default 3, unchanged) and the media merge
stage passes 5. It fans in three branch images, does far more mount work
than any other stage, and is the only one measured burning its whole budget:
two `failed to mount {windows-layer}` failures on 2026-08-06, green only on
the third and last attempt. Retries are cheap -- completed RUN vertices stay
cached, only the failed finalize re-runs.

Verified: lint 104 files 0/0; Invoke-Tests.ps1 287/287; both gates exercised
on this host through their happy, throw and -Force paths; both drivers bind
the new parameters.

NOT changed, deliberately: the VS bootstrapper fallback. setup-vs.ps1 already
tries the major-pinned aka.ms channel then falls back to aka.ms/vs/stable
with a warning and a wider retry budget, which is exactly what happened on
2026-08-06 -- the design handled it. Worth knowing though that the major-18
alias fails consistently, so the VS major pin is currently decorative and
every base build gets `stable`.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
@Kataglyphis

Copy link
Copy Markdown
Author

Can i provide further information to this PR?

@Kataglyphis
Jonas Heinle (Kataglyphis) force-pushed the feature/configurable-teardown-timeout branch from 701fbc4 to e2b180f Compare August 27, 2026 23:09
The shim hardcodes 30s for container shutdown, for terminate, for the
DeleteExec resource cleanup and for the delete command's wait.

Teardown of a process isolated container is host-side work: detaching the
layer filter stack and flushing the registry hives into the scratch. It
scales with how much the container wrote. We measured 117s for one OpenCV
build container on Windows 11 26200 with ltsc2025 base images.

When 30s expires mid-flush the container is terminated while its scratch is
still being written, and every later finalize of that snapshot fails with
hcsshim::ExportLayer 0x3. The damage survives fresh snapshots and host
reboots. All silo processes do exit, so no in-container mitigation helps:
overriding WaitToKillServiceTimeout and a full pre-exit teardown of
non-essential services both lost the notification the same way.

Make the limits configurable via the environment the shim inherits from
containerd, named after CONTAINERD_SHIM_RUNHCS_V1_WAIT_DEBUGGER:

  CONTAINERD_SHIM_RUNHCS_V1_TEARDOWN_TIMEOUT     hcsTask.close, delete
  CONTAINERD_SHIM_RUNHCS_V1_TASK_CLOSE_TIMEOUT   hcsTask.DeleteExec

DeleteExec waits on the channel close closes, so the second is derived from
the first when it is not set. Defaults stay 30s. Also log how long a
successful shutdown took, which is the number needed to size the timeout.

Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Signed-off-by: Jonas Heinle <jonasheinle@googlemail.com>
@Kataglyphis
Jonas Heinle (Kataglyphis) force-pushed the feature/configurable-teardown-timeout branch from e2b180f to 1925142 Compare August 27, 2026 23:19
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