# How Apple Container Manages Container-to-Container Networking: A Deep Dive into the vmnet Architecture

> Discover how Apple Container manages container networking using the vmnet architecture and container-network-vmnet plugin for isolated virtual networks and IP communication.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: deep-dive
- Published: 2026-07-02

---

**Apple Container implements container-to-container networking through a dedicated network subsystem built on macOS's vmnet virtualization framework, using the container-network-vmnet plugin to create isolated virtual networks that enable IP-based communication between containers on the same network while enforcing strict isolation across different networks.**

The **apple/container** repository provides a container runtime for macOS that leverages native virtualization technologies. Its approach to **container-to-container networking** relies on the `vmnet` framework to establish virtual network interfaces and the `container-network-vmnet` plugin to orchestrate connectivity, all exposed through XPC-based APIs managed by the `container-apiserver` daemon.

## Network Creation and Configuration

Container networking begins with explicit network definition. Users create networks via the CLI, which constructs a `NetworkConfiguration` struct containing the network name, mode (NAT or host-only), optional subnets, labels, and the plugin identifier.

### Defining Network Parameters

In [`Sources/ContainerCommands/Network/NetworkCreate.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Network/NetworkCreate.swift), the `NetworkCreate` command parses CLI arguments and builds the configuration struct. The default plugin is `container-network-vmnet`, though the architecture supports pluggable networking backends.

The `NetworkConfiguration` struct, defined in [`Sources/ContainerResource/Network/NetworkConfiguration.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Network/NetworkConfiguration.swift), encapsulates all parameters required to instantiate a virtual network, including IPv4/IPv6 subnet specifications and host-only versus NAT mode selection.

### XPC Communication Layer

The CLI delegates network operations to the `container-apiserver` process through the `NetworkClient` XPC wrapper located in [`Sources/Services/ContainerAPIService/Client/NetworkClient.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Client/NetworkClient.swift). When creating a network, the client sends an `XPCMessage` with the route `.networkCreate` containing the serialized `NetworkConfiguration`.

This separation ensures that privileged network operations run within the daemon process, while the CLI operates with standard user permissions.

## The vmnet Plugin Architecture

Actual network instantiation occurs within the server-side plugin architecture. The `container-apiserver` loads the `ContainerNetworkClient` plugin (`container-network-vmnet`) to interface with macOS's virtualization framework.

### ContainerNetworkClient Plugin

The plugin implementation resides in `Sources/ContainerNetworkClient` and utilizes `NetworkVmnetHelper` defined in `Sources/Plugins/NetworkVmnet/NetworkVmnetHelper+Start.swift`. This helper coordinates with the `vmnet` framework to:

- Allocate virtual network interfaces
- Assign subnet ranges
- Spin up DHCP servers when operating in NAT mode
- Configure packet filtering and forwarding rules

### Virtual Interface Allocation

When `NetworkVmnetHelper.start()` executes, it requests a virtual interface from `vmnet` based on the specified mode. In **NAT mode**, the framework provides outbound connectivity through macOS's networking stack. In **host-only mode**, the interface remains isolated, permitting only container-to-host and container-to-container communication without external access.

Upon successful initialization, the helper returns a `NetworkResource` describing the allocated network ID, IP ranges, gateway addresses, and interface identifiers. This resource persists within the `container-apiserver` and becomes available through `NetworkClient.list()` and `NetworkClient.get(id:)` APIs.

## Attaching Containers to Networks

Container-network attachment happens at runtime during the `container run` execution flow.

### ContainerResource.Attachment

When users specify `--network <name>` arguments, the CLI translates these into `ContainerResource.Attachment` entries. According to the conceptual implementation in [`Sources/ContainerResource/Network/NetworkAttachment.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Network/NetworkAttachment.swift), each attachment records:

- The target network ID
- Allocated IPv4 and IPv6 addresses
- Assigned MAC address
- Optional hostname overrides

### Runtime Configuration

The `RuntimeLinuxHelper` (referenced in the attachment logic) configures the container's network namespace to utilize the virtual interface created for the specified network. This occurs before the container process starts, ensuring the networking stack is fully initialized when the container entrypoint executes.

Containers attached to the same network receive IP addresses from the same subnet, enabling direct communication via standard TCP/IP protocols.

## Isolation and Communication Model

Apple Container's networking model enforces strict isolation while facilitating intra-network communication through standard IP routing.

### Same-Network Communication

Containers sharing a network interface can address each other directly using assigned IPv4 or IPv6 addresses. For example, a container with address `10.0.2.3` can reach a sibling container at `10.0.2.4` using standard HTTP clients or socket connections without port mapping or bridge configuration.

The `vmnet` framework handles layer-2 switching between virtual interfaces attached to the same subnet, providing native Ethernet-like connectivity.

### Cross-Network Isolation

Containers attached to different networks remain isolated at the network layer. The `vmnet` framework maintains separate routing tables and interface groups for each network, preventing IP packets from crossing network boundaries unless explicitly bridged through external routing configurations.

This isolation model supports microservice architectures where database containers reside on isolated backend networks while application containers communicate through public-facing frontend networks.

### Default Network Behavior

The system automatically creates a **default network** (identified by `defaultNetworkName` in [`NetworkClient.swift`](https://github.com/apple/container/blob/main/NetworkClient.swift)) on first use. This network operates in NAT mode, providing immediate outbound connectivity for simple workloads. While convenient for development, production deployments benefit from explicit network creation to ensure proper segmentation.

## Network Lifecycle Management

Networks exist as first-class resources within the Apple Container ecosystem, supporting full lifecycle operations beyond initial creation.

The `NetworkClient` API supports:

- **Listing**: `NetworkClient.list()` returns all available networks with their modes and attachment counts
- **Inspection**: `NetworkClient.get(id:)` retrieves detailed `NetworkResource` information including IP ranges and gateway configuration
- **Deletion**: Networks can be removed only when no containers maintain active attachments and the network is not the built-in default

This lifecycle management prevents accidental deletion of networks hosting active workloads while allowing administrators to reclaim resources from decommissioned environments.

## Practical Code Examples

The following Swift examples demonstrate the network management workflow using Apple Container's client libraries:

```swift
// Create an isolated host-only network named "backend"
let create = Application.NetworkCreate()
create.name = "backend"
create.hostOnly = true
create.ipv4Subnet = CIDRv4("10.0.2.0/24")
try await create.run()

```

```swift
// List all provisioned networks
let client = NetworkClient()
let networks = try await client.list()
networks.forEach { print("\($0.id) – \($0.mode)") }

```

```swift
// Start a container attached to the custom network
let run = Application.Run()
run.image = "docker.io/library/nginx:latest"
run.arguments = ["--network", "backend"]
try await run.run()

```

Inside running containers, standard networking tools function normally:

```bash

# From within a container on the "backend" network

curl http://10.0.2.3  # Reaches sibling container directly

```

## Summary

- **Apple Container** implements **container-to-container networking** through the `vmnet` framework and the `container-network-vmnet` plugin integrated with `container-apiserver`.
- Network creation flows from CLI commands ([`NetworkCreate.swift`](https://github.com/apple/container/blob/main/NetworkCreate.swift)) through XPC messages ([`NetworkClient.swift`](https://github.com/apple/container/blob/main/NetworkClient.swift)) to the plugin layer (`NetworkVmnetHelper+Start.swift`).
- Containers attach to networks via `ContainerResource.Attachment` entries that bind virtual interfaces to specific network namespaces at runtime.
- Communication requires containers to share the same network; the `vmnet` framework enforces isolation between different networks.
- The default NAT network provides immediate connectivity, while custom networks support host-only isolation for secure multi-tier architectures.

## Frequently Asked Questions

### How does Apple Container assign IP addresses to containers?

The `NetworkVmnetHelper` coordinates with the `vmnet` framework to allocate IP addresses from the configured subnet range. When operating in NAT mode, the helper also manages a DHCP server process that assigns dynamic addresses to connecting containers. Each `ContainerResource.Attachment` entry records the specific IPv4/IPv6 addresses allocated during container startup.

### Can containers communicate across different networks?

No, containers on different networks cannot communicate directly. The `vmnet` framework maintains separate virtual switches and routing tables for each network defined in `NetworkConfiguration`. Cross-network communication requires explicit external routing or bridge configuration outside the Apple Container runtime, as the default implementation enforces strict layer-2 and layer-3 isolation between network boundaries.

### What is the difference between NAT and host-only network modes?

**NAT mode** (the default) allows containers to initiate connections to external hosts through macOS's network stack while remaining reachable from the host machine. **Host-only mode** creates isolated networks where containers can communicate with each other and the host system but cannot access external networks. The mode is specified during network creation via the `NetworkCreate` command and stored in the `NetworkConfiguration` struct.

### Where does the default network configuration originate?

The `container-apiserver` process initializes a default network (named according to `defaultNetworkName` in [`NetworkClient.swift`](https://github.com/apple/container/blob/main/NetworkClient.swift)) automatically on first use. This network uses NAT mode and requires no explicit creation, providing immediate networking for simple container workloads. The implementation references this default in `APIServer+Start.swift` to ensure the networking plugin is ready before container operations begin.