# How container-apiserver Coordinates XPC Helpers for Images, Networking, and Runtime

> Discover how container-apiserver coordinates XPC helpers for images, networking, and runtime. Learn about its plugin architecture for secure and stable container operations.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: internals
- Published: 2026-06-21

---

**The `container-apiserver` acts as the central XPC server that loads specialized helper binaries as plugins—`container-core-images` for OCI image operations, `container-network-vmnet` for VM networking, and `container-runtime-linux` for container execution—routing client requests to the appropriate helper while maintaining isolated process boundaries for security and stability.**

The `container-apiserver` serves as the launch agent orchestrating the container stack on macOS in the [apple/container](https://github.com/apple/container) repository. When initiated via `container system start`, it establishes an XPC server identified as `com.apple.container.apiserver` and registers routes that delegate to specific helper processes. This architecture isolates privileged operations across distinct binaries while presenting a unified API surface to clients.

## Architecture Overview

In `Sources/APIServer/APIServer+Start.swift`, the apiserver initializes an `XPCServer` with the identifier `com.apple.container.apiserver` and registers routes such as `containerList`, `containerCreate`, and `networkCreate`. Rather than implementing container logic directly, the apiserver loads **plugins** that implement the actual service logic for images, networking, and runtime.

All communication is mediated by the **ContainerXPC** framework, which provides the underlying transport for inter-process RPCs. The apiserver forwards client requests to the appropriate helper and aggregates results, ensuring that a failure in one helper does not compromise the entire system.

## Image Management via XPC

The **Image Management** responsibility is handled by the `container-core-images` binary, which exposes the XPC service `com.apple.container.core.container-core-images`. This helper implements the content-store, OCI pull/push operations, and image-layer handling.

At startup, the apiserver loads the *CoreImages* plugin through [`ImagesHelper.swift`](https://github.com/apple/container/blob/main/ImagesHelper.swift) located in [`Sources/Plugins/CoreImages/ImagesHelper.swift`](https://github.com/apple/container/blob/main/Sources/Plugins/CoreImages/ImagesHelper.swift). The plugin registers its routes with the apiserver’s XPC server, allowing the `ContainerAPI` client to issue image-related RPCs:

- `imagePull`
- `imageList`
- `imagePush`

When a client requests an image that is not present locally, the apiserver forwards the request to the image helper, which contacts the remote registry and writes content to the local store.

## Networking Coordination

The **Networking** layer utilizes the `container-network-vmnet` binary, providing a virtual network backed by macOS `vmnet`. This helper handles subnet allocation, NAT, and DNS for containers, exposing the XPC service `com.apple.container.network.vmnet`.

In `APIServer+Start.swift`, the `initializeNetworksService` method loads the *Network* plugin ([`NetworkHelper.swift`](https://github.com/apple/container/blob/main/NetworkHelper.swift)). The service registers routes including:

- `networkCreate`
- `networkList`
- `networkDelete`

When a container is created, the apiserver asks the network helper for an IP address and subnet via the `allocate` or `lookup` routes. The apiserver stores the resulting `XPCClientSession` for later use, ensuring the container retains its network configuration throughout its lifecycle.

## Runtime Lifecycle Management

The **Runtime** operations are handled by `container-runtime-linux`, with one instance spawned per container. This binary exposes the XPC service `com.apple.container.runtime.linux` and implements lifecycle RPCs including bootstrap, start, stop, exec, and stats.

When processing a `containerCreate` request, the apiserver spawns a new `container-runtime-linux` helper and establishes an XPC client via [`RuntimeClient.swift`](https://github.com/apple/container/blob/main/RuntimeClient.swift) in [`Sources/Services/Runtime/RuntimeClient/RuntimeClient.swift`](https://github.com/apple/container/blob/main/Sources/Services/Runtime/RuntimeClient/RuntimeClient.swift). The helper returns an XPC endpoint that the apiserver caches and re-uses for the lifetime of the container.

All subsequent container-specific actions—`containerStartProcess`, `containerKill`, `containerStats`—are forwarded over this persistent connection to the runtime helper.

## End-to-End Container Launch Flow

The coordination between helpers follows a strict sequence when launching a container:

1. **Start the system** – `container system start` launches `container-apiserver`.

2. **Load plugins** – The apiserver’s `initializePluginLoader` discovers the three helper binaries and loads them as launch-agents.

3. **Create a network** – The apiserver calls the network helper’s `allocate` route to reserve an IP and subnet.

4. **Pull images** – If the requested image is absent, the apiserver invokes the image helper’s `pull` route, which downloads layers to the local content store.

5. **Spawn runtime** – The apiserver launches a `container-runtime-linux` helper, registers a route for that container, and obtains an XPC endpoint via `RuntimeClient.createEndpoint`.

6. **Bootstrap container** – Using the endpoint, the apiserver sends a `bootstrap` RPC to the runtime helper in [`Sources/Services/RuntimeLinux/Server/RuntimeService.swift`](https://github.com/apple/container/blob/main/Sources/Services/RuntimeLinux/Server/RuntimeService.swift). The helper creates the VM, attaches the network interface, mounts image layers, and returns a ready state.

7. **Run processes** – Subsequent commands such as `container exec` are forwarded over the same XPC connection to the runtime helper.

## Code Examples

The following Swift snippets demonstrate the client-side interaction with the apiserver's XPC coordination:

```swift
// Start the API server (simplified)
let server = XPCServer(
    identifier: "com.apple.container.apiserver",
    routes: routes,
    log: log
)
try await server.listen()          // launches XPC helpers as plugins

```

```swift
// Pull an image (client-side)
let imageClient = ImageClient()
try await imageClient.pull(named: "ubuntu:latest")   // talks to container-core-images

```

```swift
// Create a container (client-side)
let containerClient = ContainerClient()
let containerID = try await containerClient.create(
    image: "ubuntu:latest",
    network: "default"
)                                            // apiserver contacts network & runtime helpers

```

```swift
// Start a process inside the container
try await containerClient.startProcess(
    containerID: containerID,
    command: ["/bin/bash"]
)                                            // forwarded to container-runtime-linux via XPC

```

## Summary

- The `container-apiserver` in `Sources/APIServer/APIServer+Start.swift` creates an XPC server with identifier `com.apple.container.apiserver` to route client requests.
- **Image operations** are delegated to `container-core-images` via the [`ImagesHelper.swift`](https://github.com/apple/container/blob/main/ImagesHelper.swift) plugin, handling OCI registry interactions.
- **Network configuration** is managed by `container-network-vmnet` through the [`NetworkHelper.swift`](https://github.com/apple/container/blob/main/NetworkHelper.swift) plugin, providing VM-backed networking via `vmnet`.
- **Container execution** is isolated to per-container instances of `container-runtime-linux`, coordinated through [`RuntimeClient.swift`](https://github.com/apple/container/blob/main/RuntimeClient.swift) and [`RuntimeService.swift`](https://github.com/apple/container/blob/main/RuntimeService.swift).
- All inter-process communication uses the **ContainerXPC** framework, ensuring type-safe RPCs between the apiserver and its helpers.

## Frequently Asked Questions

### What XPC service identifier does container-apiserver register?

The apiserver registers the XPC service **`com.apple.container.apiserver`** when starting via `container system start`. This identifier is defined in `Sources/APIServer/APIServer+Start.swift` and serves as the primary endpoint for all container-related client requests.

### How does the apiserver isolate image operations from runtime execution?

The apiserver enforces isolation by loading separate binary helpers as plugins. Image operations run in `container-core-images`, while runtime execution occurs in `container-runtime-linux`. Each helper operates as an independent XPC service with distinct entitlements and process boundaries, preventing a crash in image parsing from affecting running containers.

### Why is container-runtime-linux spawned per container?

The `container-runtime-linux` helper is spawned as a separate process for each container to provide strong isolation and lifecycle management. According to the implementation in [`Sources/Services/Runtime/RuntimeClient/RuntimeClient.swift`](https://github.com/apple/container/blob/main/Sources/Services/Runtime/RuntimeClient/RuntimeClient.swift), the apiserver creates a unique XPC endpoint for each runtime instance, caching the connection for the container's lifetime. This design allows the apiserver to terminate or restart individual containers without affecting the system-wide container stack.

### What framework mediates communication between the apiserver and helpers?

All XPC communication is mediated by the **ContainerXPC** framework imported throughout the codebase. This framework provides the underlying transport for RPCs between the apiserver and the image, network, and runtime helpers, ensuring type-safe message passing and proper handling of XPC endpoints.