apple / apple/containerization
`LinuxPod`: add stdin/stdout/stderr attach to an already-running process (PTY re-attach)
- Dominant language
- Swift
- Stars
- 8.9k
- Forks
- 359
- Avg merge
- 2d 20h
- Merged PRs (30d)
- 13
Description
## Problem
The Containerization framework provides `LinuxPod.execInContainer(_:processID:configure:)`
to spawn a **new** process inside a running container, but exposes no mechanism
to re-attach an interactive PTY (stdin + stdout + stderr) to the **primary
process** that was started with `startContainer()`. Once the initial stdout/stderr
streams are consumed at start time, there is no way to reconnect.
This means the Kubernetes CRI `Attach` RPC — which connects a client's terminal
to the container's **existing** entrypoint process — cannot be implemented on
the pod-shared path.
## Use case
`kubectl attach -it ` expects the CRI runtime to open a bidirectional
byte stream to the container's primary process. On the pod-shared path
(`podvmd`), the CRI runtime dispatches a JSON-RPC `pod.attach` call to the
daemon. The daemon must then re-attach to the process that was started at
container boot.
Without this primitive, the only option is to `exec` a new shell, which is
semantically different (new PID, new process group, does not share the
entrypoint's stdin history or signal handling).
## Reproducer
In our `podvmd` daemon (`tools/podvmd/Sources/podvmd/PodRegistry.swift`,
line ~449):
```swift
// MARK: - pod.attach
//
// Apple Containerization framework (as of 0.12.x) does not expose a
// re-attach primitive for the primary container process.
func attach(_ params: PodAttachParams) async throws -> PodAttachResult {
_ = try podEntry(params.handle)
throw PodVMError(
.methodNotFound,
"pod.attach not supported by Apple Containerization framework on this host"
)
}
```
The Go CRI layer (`darwin-cri`) calls this method and receives JSON-RPC error
code `-32601` (method not found), which it maps to gRPC `codes.Unimplemented`:
```
Attach: pod-shared path: pod.attach returned method_not_found
(-32601: pod.attach not supported by Apple Containerization
framework on this host)
```
A `kubectl attach -it` against a pod-shared pod produces:
```
error: unable to upgrade connection: container attach not supported
```
## Proposed API shape
Option A — method on `LinuxPod`:
```swift
/// Attach stdin/stdout/stderr to an already-running container process.
/// Returns when the client disconnects or the process exits.
func attach(
containerID: String,
processID: String?, // nil = primary process
stdin: (any ReaderStream)?,
stdout: (any Writer)?,
stderr: (any Writer)?,
tty: Bool
) async throws
```
Option B — method on `LinuxProcess`:
```swift
/// Re-open the stdio streams for an existing process.
func openTTY() async throws -> (stdin: FileHandle, stdout: FileHandle)
```
Either shape would unblock the CRI `Attach` path.
## Workarounds we've tried
1. **Exec a new `/bin/sh`** — not semantically equivalent; creates a new
process rather than attaching to the existing one.
2. **Capture stdout/stderr at start time into files, then tail** — provides
read-only output but no stdin, and misses data written before the tail
starts.
3. **Hold the initial `Writer` references open** — works for log streaming
but does not provide a way to inject stdin after the fact, and the
`Writer` protocol is unidirectional.
Contributor guide
Assessment
This issue has not been assessed yet.