render: interrupting with Ctrl+C (SIGINT/SIGTERM) leaks Function containers, the render container, and the network
维护者通常 3 天内回复
评估
调研方向
Read the deferred cleanup paths in xr/cmd.go and op/cmd.go, then inspect the signal handling in internal/terminal/spinner.go and the render command entry points. Reproduce the issue with the supplied hanging Function and Ctrl+C, and verify that the existing containers, render container, and temporary network are removed before the command exits.
由索引模型根据 Issue 内容生成。
描述
What happened?
Interrupting crossplane render with Ctrl+C while a render is in progress leaves every Function container it
started, the crossplane internal render engine container, and the temporary crossplane-render-* network
all still running. This happens with the default runtime-docker-cleanup policy (Remove), with or
without a TTY.
All cleanup in the render commands is defer-based
(xr/cmd.go L270-L281,
op/cmd.go L210-L221),
and nothing turns SIGINT/SIGTERM into context cancellation, so the process exits before any deferred
cleanup runs. The only signal handler in the CLI is the terminal spinner's
(internal/terminal/spinner.go L291-L300),
which calls os.Exit(130) — and that skips deferred cleanup too.
Expected: an interrupted render cleans up what it created before exiting.
How can we reproduce it?
Use a Function that accepts a connection but never responds, so the render blocks long enough to interrupt:
# tagged fnlc-hang:test
FROM alpine:3.20
ENTRYPOINT ["sh","-c","exec nc -lk -p 9443 -e cat","hang"]
xr.yaml:
apiVersion: example.org/v1
kind: XThing
metadata:
name: test-xr
spec:
coolField: hello
comp-hang.yaml:
apiVersion: apiextensions.crossplane.io/v1
kind: Composition
metadata:
name: xthings.example.org
spec:
compositeTypeRef: {apiVersion: example.org/v1, kind: XThing}
mode: Pipeline
pipeline:
- step: templating
functionRef: {name: function-go-templating}
input:
apiVersion: gotemplating.fn.crossplane.io/v1beta1
kind: GoTemplate
source: Inline
inline:
template: |
apiVersion: nop.crossplane.io/v1alpha1
kind: NopResource
metadata:
annotations: {gotemplating.fn.crossplane.io/composition-resource-name: nop}
spec: {forProvider: {}}
- step: hang
functionRef: {name: function-hang}
functions-hang.yaml (names set only to make leftovers easy to find):
apiVersion: pkg.crossplane.io/v1
kind: Function
metadata:
name: function-go-templating
annotations: {render.crossplane.io/runtime-docker-name: fnlc-sigint-gotmpl}
spec: {package: xpkg.crossplane.io/crossplane-contrib/function-go-templating:v0.11.0}
---
apiVersion: pkg.crossplane.io/v1
kind: Function
metadata:
name: function-hang
annotations:
render.crossplane.io/runtime-docker-name: fnlc-sigint-hang
render.crossplane.io/runtime-docker-image: fnlc-hang:test
render.crossplane.io/runtime-docker-pull-policy: Never
spec: {package: example.org/unused:v0.0.0}
Run it, press Ctrl+C after a few seconds, then look:
$ crossplane render xr.yaml comp-hang.yaml functions-hang.yaml
^C
$ echo $?
130
$ docker ps --filter name=fnlc-sigint --format '{{.Names}} {{.Status}}'
fnlc-sigint-hang Up 7 seconds
fnlc-sigint-gotmpl Up 8 seconds
$ docker network inspect crossplane-render-wxjbqjcj --format '{{range .Containers}}{{.Name}} {{end}}'
musing_lamport
$ docker inspect musing_lamport --format '{{.Config.Image}} {{.State.Status}} cmd={{json .Config.Cmd}}'
xpkg.crossplane.io/crossplane/crossplane:stable running cmd=["internal","render"]
(Transcript lightly abridged: the reproduction was scripted, sending SIGINT 6s after start. It gives the
same result under a pseudo-TTY, where the spinner's handler is the one that exits.)
Possible fix: wrap the command context in signal.NotifyContext(ctx, os.Interrupt, syscall.SIGTERM) so an
interrupt cancels in-flight work and lets the existing deferred cleanup run, and have the spinner cooperate
with that instead of calling os.Exit. Cleanup already runs on a detached context.Background(), so it
still works after cancellation. A second signal could force-exit immediately, as is conventional.
Some interruptions (kill -9, a crash, a CI job timeout) can never be handled in-process; #401 proposes
labels so leftovers from those can be found and swept.
What environment did it happen in?
- Crossplane CLI version: built from
main@29316fea54f2ede9d2c039d9c54f0c29cbad4b65 - Platform (e.g., linux/amd64): darwin/arm64, Docker Engine 29.5.3 (Rancher Desktop)
- Crossplane version (if applicable): render engine image
xpkg.crossplane.io/crossplane/crossplane:stable
- 主要语言
- Go
- 星标
- 19
- 派生
- 33
- 平均合并
- 3 天 10 小时
- 30 天内合并 PR
- 24
环境准备
- 没有 Dockerfile 或 Docker Compose 文件
- 有 Pull Request 模板
- 阅读贡献指南
从这里开始
- 先读完整个 Issue,再读项目的贡献指南。
- 在 Issue 下留言说明你要接手 —— 这能避免两个人做同样的事。
- Fork 仓库,在一个分支上完成修改。
- 提交 Pull Request,并在描述里引用这个 Issue 编号。
crossplane/cli 的其他 Issue
-
`credsStore` in docker config causes unit test failures可能已有人在做 @sujeito-operator 于 48 天前认领。 未关闭bug
难度 2/5 1-3 小时 新手友好度 84/100
crossplane/cli#282 ·
维护者通常 3 天内回复
-
enhancement
难度 4/5 3-5 天 新手友好度 42/100
crossplane/cli#410 ·
维护者通常 3 天内回复
-
render: label the Docker containers and networks render creates可能已有人在做 @jcogilvie 于 5 天前认领。 未关闭enhancement
难度 4/5 3-5 天 新手友好度 48/100
crossplane/cli#401 ·
维护者通常 3 天内回复
-
render: Function cleanup failures are invisible without --verbose可能已有人在做 @jcogilvie 于 5 天前认领。 未关闭bug
难度 3/5 1-2 天 新手友好度 70/100
crossplane/cli#399 ·
维护者通常 3 天内回复
-
render: docker engine discards the network-removal error, so crossplane-render-* networks leak silently可能已有人在做 @jcogilvie 于 5 天前认领。 未关闭bug
难度 4/5 3-5 天 新手友好度 48/100
crossplane/cli#398 ·
维护者通常 3 天内回复
相似的 Issue
-
[submenu] nil issue on ubuntu 26.04可能已有人在做 @egoist 今天认领。 未关闭
难度 2/5 1-3 小时 新手友好度 85/100
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 70/100
prime-radiant-inc/evener#3873 ·
维护者通常 1 天内回复
-
extract_llm_sweep / cache_aware_summarizer prefix ask 400s when thinking.budget_tokens exceeds PrefixAskMaxTokens可能已有人在做 @amiddavid 今天认领。 未关闭
难度 1/5 1 小时以内 新手友好度 85/100
rossoctl/context-guru#405 ·
维护者通常 1 天内回复
-
难度 2/5 1-3 小时 新手友好度 80/100
router-for-me/CLIProxyAPI#6423 ·
维护者通常 1 天内回复
-
bug
难度 2/5 1-3 小时 新手友好度 72/100
维护者通常 2 天内回复