What happened
When you run an Argo Workflow step with runtimeClassName: urunc and the main container is a urunc unikernel image, the workflow never finishes. The unikernel container can fail, or even succeed and terminate cleanly, and it doesn't matter: the workflow stays stuck in Running forever. No timeout, no error, nothing.
The cause is that urunc's CLI has no exec subcommand, and Argo's default executor needs to exec into a sidecar container to know a step is done.
Root cause
Argo's default (emissary) executor runs each step as a pod with three containers: init, wait, and main. Once main exits, the workflow-controller tells the wait sidecar to wrap up by running:
kubectl exec <pod> -c wait -- /var/run/argo/argoexec kill 15 1
That call goes through kubelet, then CRI's ExecSync, then the containerd shim, then <runtime> exec. RuntimeClass is set at the pod level, not per container, so once one container in the pod uses runtimeClassName: urunc, every container in that pod, including the plain-Linux wait sidecar that has nothing to do with unikernels, has its exec calls routed through urunc's shim too.
I checked main and it's not implemented:
$ grep -n Commands cmd/urunc/main.go
111: Commands: []*cli.Command{
112: createCommand, deleteCommand, killCommand, runCommand, psCommand, startCommand,
No execCommand. So the exec call just fails, and containerd/kubelet report it as a generic internal error rather than something callers can treat as "not supported."
Reproduction
Setup: kind v0.32.0, Kubernetes v1.36.1, containerd 2.3.1, urunc 0.7.0-96f992d (installed with the official urunc-deploy DaemonSet, RBAC, and RuntimeClass manifests), Argo Workflows v3.6.5.
Test 1: plain container, no unikernel annotations, runtimeClassName: urunc
This works fine. Argo's sidecar model and shared emptyDir volumes are fine under urunc as long as nothing needs to boot a VM.
$ kubectl -n argo get wf urunc-argo-plain-pcnlx
NAME STATUS AGE
urunc-argo-plain-pcnlx Succeeded 32s
Test 2: real unikernel image (nginx-qemu-unikraft-initrd) as main, runtimeClassName: urunc
main fails here because this test environment has no KVM, which is expected:
main:
State: Terminated
Reason: StartError
Message: failed to create containerd task: ... could not get host device
/dev/kvm: no such file or directory
But the workflow never ends. wait keeps running, the pod sits at 1/2, and workflow-controller keeps retrying cleanup and failing:
level=info msg="signaled container" container=wait error="Internal error occurred: error executing
command in container: failed to exec in container: failed to start exec \"...\":
OCI runtime exec failed: urunc did not terminate successfully: exit status 1"
level=info msg="queueing pod for cleanup after" action=killContainers after=30s ...
This repeats on a loop (10s, 20s, 30s then SIGKILL) with no change. I left it running and polled for 4+ minutes, no progress. It doesn't resolve on its own.
This matches #135
Issue #135 ("argo workflow never ends with kubernetes, urunc and unikraft") describes the exact same thing on a real, KVM-enabled cluster where the unikernel actually boots. Their journalctl logs show the actual urunc error behind it:
Mar 14 08:38:39 workernode5 urunc[1804235]: {"level":"error","msg":"No help topic for 'exec'\n", ...}
Mar 14 08:39:09 workernode5 urunc[1804248]: {"level":"error","msg":"No help topic for 'exec'\n", ...}
repeated for hours. Same 1/2 NotReady pod, same permanently-running workflow, even though in their case the unikernel finished cleanly (Terminated: Reason: Completed, Exit Code: 0). That's a strong signal this is the missing exec verb, not a KVM or boot problem.
Suggested fix
Add urunc exec, or at least a stub that returns a clean "not supported" error instead of the CLI's usage-help failure. Right now containerd/kubelet can't tell the difference between "urunc doesn't support this" and "urunc is broken," and Argo just retries forever instead of failing the step.
Possible workaround to check: Argo's k8sapi executor mode doesn't rely on exec-based signaling, it polls container status through the Kubernetes API instead, so it might not hit this at all. I haven't verified this myself since I don't have a KVM-capable cluster to test against.
Environment
Reproduced on kind + Docker Desktop on macOS. No /dev/kvm in this setup, so the KVM failure in Test 2 is expected and already documented elsewhere, not a new finding. The actual bug here, the exec hang, doesn't depend on KVM at all and is confirmed independently by #135 on a real cluster.
Ran into this while working through a replication task for the "Integration of urunc's sandbox execution with Argo Workflows" LFX Mentorship proposal, related to #573.
What happened
When you run an Argo Workflow step with
runtimeClassName: uruncand the main container is a urunc unikernel image, the workflow never finishes. The unikernel container can fail, or even succeed and terminate cleanly, and it doesn't matter: the workflow stays stuck inRunningforever. No timeout, no error, nothing.The cause is that
urunc's CLI has noexecsubcommand, and Argo's default executor needs toexecinto a sidecar container to know a step is done.Root cause
Argo's default (
emissary) executor runs each step as a pod with three containers:init,wait, andmain. Oncemainexits, the workflow-controller tells thewaitsidecar to wrap up by running:That call goes through kubelet, then CRI's
ExecSync, then the containerd shim, then<runtime> exec.RuntimeClassis set at the pod level, not per container, so once one container in the pod usesruntimeClassName: urunc, every container in that pod, including the plain-Linuxwaitsidecar that has nothing to do with unikernels, has itsexeccalls routed through urunc's shim too.I checked
mainand it's not implemented:No
execCommand. So the exec call just fails, and containerd/kubelet report it as a generic internal error rather than something callers can treat as "not supported."Reproduction
Setup:
kindv0.32.0, Kubernetes v1.36.1, containerd 2.3.1, urunc0.7.0-96f992d(installed with the officialurunc-deployDaemonSet, RBAC, and RuntimeClass manifests), Argo Workflows v3.6.5.Test 1: plain container, no unikernel annotations,
runtimeClassName: uruncThis works fine. Argo's sidecar model and shared
emptyDirvolumes are fine under urunc as long as nothing needs to boot a VM.Test 2: real unikernel image (
nginx-qemu-unikraft-initrd) asmain,runtimeClassName: uruncmainfails here because this test environment has no KVM, which is expected:But the workflow never ends.
waitkeeps running, the pod sits at1/2, andworkflow-controllerkeeps retrying cleanup and failing:This repeats on a loop (10s, 20s, 30s then SIGKILL) with no change. I left it running and polled for 4+ minutes, no progress. It doesn't resolve on its own.
This matches #135
Issue #135 ("argo workflow never ends with kubernetes, urunc and unikraft") describes the exact same thing on a real, KVM-enabled cluster where the unikernel actually boots. Their journalctl logs show the actual urunc error behind it:
repeated for hours. Same
1/2 NotReadypod, same permanently-running workflow, even though in their case the unikernel finished cleanly (Terminated: Reason: Completed, Exit Code: 0). That's a strong signal this is the missingexecverb, not a KVM or boot problem.Suggested fix
Add
urunc exec, or at least a stub that returns a clean "not supported" error instead of the CLI's usage-help failure. Right now containerd/kubelet can't tell the difference between "urunc doesn't support this" and "urunc is broken," and Argo just retries forever instead of failing the step.Possible workaround to check: Argo's
k8sapiexecutor mode doesn't rely on exec-based signaling, it polls container status through the Kubernetes API instead, so it might not hit this at all. I haven't verified this myself since I don't have a KVM-capable cluster to test against.Environment
Reproduced on
kind+ Docker Desktop on macOS. No/dev/kvmin this setup, so the KVM failure in Test 2 is expected and already documented elsewhere, not a new finding. The actual bug here, the exec hang, doesn't depend on KVM at all and is confirmed independently by #135 on a real cluster.Ran into this while working through a replication task for the "Integration of urunc's sandbox execution with Argo Workflows" LFX Mentorship proposal, related to #573.