apple / apple/containerization

[Request]: ListProcesses RPC on vminitd to enumerate guest processes (enables `docker top` / `container top`)

Open
#811 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

### Feature or enhancement request details

**Problem**

There is currently no way to enumerate the processes running inside a container without executing a binary in the guest. `SandboxContext` exposes full per-process lifecycle control (`CreateProcess`, `StartProcess`, `KillProcess`, `WaitProcess`) and cgroup-level `ContainerStatistics`, but nothing that lists what is actually running.

Every comparable runtime exposes this: containerd's task service has `ListPids`, and `runc ps` exists for the same reason. The gap is felt concretely by Docker-API bridges over Apple's container stack (e.g. [socktainer](https://github.com/socktainer/socktainer), used by [Whalebridge](https://github.com/cap10morgan/whalebridge)): `docker top` cannot be implemented correctly. The only available workaround is exec'ing `ps` inside the container, which:

- fails outright for images that don't ship `ps` or a shell (distroless, scratch + static binary — increasingly the norm for production images), and
- perturbs the very thing it measures (each invocation creates a process in the container).

A native RPC would also give `container` itself a natural user-facing feature (`container top` or `container ps`-style process inspection), independent of the Docker-bridge use case.

**Proposed shape**

A read-only RPC on `SandboxContext`, implemented in vminitd by walking the guest's `/proc` (vminitd already reads guest kernel state for `ContainerStatistics`, so this fits its existing role):

```proto
rpc ListProcesses(ListProcessesRequest) returns (ListProcessesResponse);

message ListProcessesRequest {
string container_id = 1;
}

message ListProcessesResponse {
repeated ProcessInfo processes = 1;
}

message ProcessInfo {
int32 pid = 1;
int32 ppid = 2;
uint32 uid = 3;
string command = 4; // /proc//cmdline, argv joined; fallback to comm
uint64 start_time_ticks = 5; // field 22 of /proc//stat
uint64 utime_ticks = 6;
uint64 stime_ticks = 7;
uint64 rss_bytes = 8;
}
```

Structured fields (rather than pre-rendered `ps` text) let each consumer format for its own surface — Docker's `/containers/{id}/top` response, a CLI table, etc. Scoping by the container's cgroup (`/sys/fs/cgroup/.../cgroup.procs` as the pid source, then per-pid `/proc` reads) keeps the result correct when multiple containers share a sandbox.

**Compatibility note**

Since vminitd ships inside the init filesystem image, host and guest versions can skew; callers would need to treat `UNIMPLEMENTED` from an older guest as "not supported" and degrade gracefully. Happy to follow whatever convention the project already uses for protocol additions.

I'm open to contributing the implementation (vminitd + proto here, plus the plumbing/CLI surface in apple/container as a follow-up) if maintainers are receptive to the direction — flagging the design here first for feedback.

### Code of Conduct

- [x] I agree to follow this project's Code of Conduct

Contributor guide

Open the contributing guide

Research direction

Start by reading the SandboxContext and ContainerStatistics entry points, then inspect vminitd's existing guest kernel-state handling and the project's conventions for protocol additions. Done means maintainers agree on the RPC and compatibility behavior, the proto and vminitd implementation are complete, and process results are correctly scoped to the container cgroup.

Written by the indexing model from the issue text.

Assessment

Tech stack
linux, swift
Domain
api, operating-systems
Issue type
Feature
Difficulty
5/5
Estimated time
Over a week
Activity status
Quiet
Clarity
Mostly clear
Newbie friendliness
35/100

Get new issues in your inbox

A short digest of beginner-friendly GitHub issues.