How Container Uses XPC Services: container-apiserver and container-network-vmnet Explained
Apple's Container framework uses XPC (Cross-Process Communication) to isolate the CLI, API server, and network helper, with container-apiserver managing container lifecycle and container-network-vmnet handling virtual network allocation through Mach service endpoints.
The apple/container repository implements a secure, multi-process architecture where XPC services provide the backbone for container management on macOS. Understanding how container-apiserver and container-network-vmnet collaborate via Mach services reveals the design patterns behind this production-grade container runtime.
Architecture Overview
The API Server Launch Agent (container-apiserver)
The container-apiserver acts as the central launch agent that implements the container management API. According to the source code in Sources/APIServer/APIServer.swift (lines 20-27), this executable defines the launch agent entry point using ArgumentParser scaffolding and registers sub-commands such as Start. The API server handles operations including container creation, image management, and lifecycle controls, exposing its functionality through the Mach service com.apple.container.apiserver.
The Network Helper Plug-in (container-network-vmnet)
The container-network-vmnet service operates as an XPC plug-in that owns the virtual network (vmnet) subsystem. Implemented in Sources/Plugins/NetworkVmnet/NetworkVmnetHelper.swift (lines 17-30), this helper is not a standalone persistent process but rather a specialized plug-in selected by the API server. It allocates IP addresses for containers and configures subnets by interfacing directly with the macOS vmnet framework. The helper shares the same Mach service endpoint as the API server, with the server routing network-specific requests to this component as needed.
XPC Implementation Details
Low-Level XPC Client (XPCClient.swift)
At the transport layer, Sources/ContainerXPC/XPCClient.swift (lines 21-38) provides the foundational XPC communication wrapper. This implementation utilizes xpc_connection_create_mach_service to establish the Mach connection and exposes a send(_:responseTimeout:) method that delivers an XPCMessage and awaits typed replies. The client handles connection lifecycle management, timeout enforcement, and low-level error translation, throwing on communication failures or missed deadlines.
High-Level Network Client (NetworkClient.swift)
Building atop the low-level transport, Sources/Services/ContainerAPIService/Client/NetworkClient.swift (lines 24-66) serves as the public Swift façade for network operations. This client constructs XPCMessage instances, transmits them via XPCClient, and decodes responses into Swift structs such as NetworkResource and NetworkConfiguration. It references NetworkClient.defaultServiceIdentifier to target the Mach service com.apple.container.apiserver, providing downstream developers with type-safe methods for network creation, listing, and deletion.
Lifecycle and Communication Flow
The interaction between Container XPC services follows a strict initialization sequence:
-
System Initialization: The user executes
container system start, which activates thecontainer-apiserverlaunch agent as defined inSources/APIServer/APIServer.swift. -
Helper Spawning: When the first network operation is requested (such as creating a container with network access),
container-apiserverautomatically spawns thecontainer-network-vmnetXPC helper. -
Client Connection: Application code or the CLI instantiates a
NetworkClient, which internally creates anXPCClientpointing at the Mach servicecom.apple.container.apiserver. -
Request Routing: Method calls such as
create,list, ordeleteare encoded intoXPCMessageobjects and sent over the XPC connection. The API server receives these messages and forwards network-specific requests to thecontainer-network-vmnetplug-in. -
Response Handling: The helper communicates with the
vmnetframework to allocate IPs and configure interfaces, then returns results through the same XPC channel.NetworkClientunmarshals these replies into typed Swift structs for consumption by the caller.
Practical Code Examples
Managing Networks with NetworkClient
The high-level Swift API provides the recommended interface for network management:
import ContainerResource
import ContainerXPC
import Foundation
// Create a client that talks to the default API server.
let client = NetworkClient()
// 1️⃣ Create a new network
let config = NetworkConfiguration(
id: "my-net",
subnet: "192.168.65.0/24",
gateway: "192.168.65.1"
)
let network = try await client.create(configuration: config)
print("Created network: \(network.id) – IP range \(network.subnet)")
// 2️⃣ List all networks
let networks = try await client.list()
print("All networks:")
for n in networks {
print("- \(n.id) (builtin: \(n.isBuiltin))")
}
// 3️⃣ Delete a network (fails for the built-in default network)
try await client.delete(id: network.id)
print("Deleted network \(network.id)")
Key files: NetworkClient (Sources/Services/ContainerAPIService/Client/NetworkClient.swift) provides the entry point for XPC communication, while XPCClient (Sources/ContainerXPC/XPCClient.swift) manages the underlying transport.
Direct XPC Communication
For scenarios requiring low-level protocol access, use XPCClient directly:
import ContainerXPC
// Low-level client – you normally use NetworkClient instead.
let xpc = XPCClient(service: "com.apple.container.apiserver")
// Build a raw XPCMessage that asks the server to list networks.
var request = XPCMessage(route: .networkList)
// Send and wait for a reply (1-second timeout for demo purposes).
let reply = try await xpc.send(request, responseTimeout: .seconds(1))
// Extract the binary payload; decode as JSON array of NetworkResource.
if let data = reply.dataNoCopy(key: .networkResources) {
let networks = try JSONDecoder().decode([NetworkResource].self, from: data)
print("Found \(networks.count) networks")
}
This example illustrates how the library constructs the Mach connection and marshals messages as implemented in the XPCMessage protocol definitions.
Starting the Container Subsystem
From the command line, initialize the XPC services:
# Start the container system (launches container-apiserver and its helpers)
$ container system start
# Verify the API server is running (process name appears in ps)
$ ps -ax | grep container-apiserver
The CLI internally instantiates an XPCClient targeting the Mach service, making subsequent commands such as container run or container network create thin wrappers around the XPC calls demonstrated above.
Summary
- Container XPC services achieve process isolation by separating the CLI, API server (
container-apiserver), and network helper (container-network-vmnet) into distinct components communicating via Mach services. container-apiserverfunctions as the launch agent implementing the container management API, whilecontainer-network-vmnetoperates as a plug-in handling virtual network allocation.- The XPC transport layer in
Sources/ContainerXPC/XPCClient.swiftmanages Mach connections and message delivery, while NetworkClient provides the type-safe Swift interface. - Both services share the Mach service identifier
com.apple.container.apiserver, with the API server routing network requests to the helper as documented indocs/technical-overview.md(lines 43-48).
Frequently Asked Questions
How does container-apiserver communicate with container-network-vmnet?
The API server spawns the network helper as an XPC plug-in when the first network operation is requested, forwarding specific requests to it while both utilize the same Mach service endpoint com.apple.container.apiserver. This architecture allows the network helper to run only when needed while maintaining a unified client interface.
What Mach service identifier does Container use for XPC connections?
The framework uses com.apple.container.apiserver as the primary Mach service identifier, which is defined in NetworkClient.defaultServiceIdentifier and passed to XPCClient to establish the Mach connection via xpc_connection_create_mach_service.
How do I start the Container XPC services and verify they are running?
Execute container system start to launch the container-apiserver launch agent; the network helper starts automatically when the first network request is made. Verify the API server is active by running ps -ax | grep container-apiserver or checking for the com.apple.container.apiserver Mach service registration.
What is the difference between XPCClient and NetworkClient?
XPCClient (Sources/ContainerXPC/XPCClient.swift) provides the low-level XPC transport handling connection creation, message sending, and timeout management, while NetworkClient (Sources/Services/ContainerAPIService/Client/NetworkClient.swift) offers the high-level Swift API that encodes method calls into XPCMessage objects and decodes responses into typed structs like NetworkResource.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →