apple / apple/containerization

`LinuxPod`: add stdin/stdout/stderr attach to an already-running process (PTY re-attach)

Open
#735 1 comment 0 reactions 0 assignees View on GitHub
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

Open the contributing guide

Assessment

This issue has not been assessed yet.

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.