# How to Handle Networking Between Multiple Containers in Apple Container

> Master networking between multiple containers using Apple's vmnet framework. Learn about isolated networks, DNS hostnames, and automatic IP allocation for seamless container communication.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: how-to-guide
- Published: 2026-07-11

---

**The Apple Container tool leverages the macOS vmnet framework to create virtual networks where containers communicate via DNS hostnames, supporting isolated user-defined networks and automatic IP allocation between multiple containers.**

The `apple/container` repository provides a Linux container runtime that creates lightweight virtual machines attaching to virtual networks managed by the macOS vmnet framework. Understanding how to handle networking between multiple containers requires knowledge of the three-tier architecture that manages network lifecycle, IP allocation, and DNS resolution. This guide explains the core components, CLI workflows, and programmatic APIs used to establish communication between containers.

## Core Networking Architecture

The networking stack relies on three integrated components that bridge the vmnet framework with container orchestration.

**`container-network-vmnet` XPC helper** – This system service drives the vmnet framework, allocates IP addresses to containers, and exposes a client API through `ContainerNetworkClient`.

**`NetworksService`** – Implemented as a Swift actor in [[`Sources/Services/ContainerAPIService/Server/Networks/NetworksService.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Server/Networks/NetworksService.swift)](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Server/Networks/NetworksService.swift), this component stores network configurations, registers the XPC service, and tracks the lifecycle of each network from creation to deletion.

**`ContainerDNSHandler`** – Located in [[`Sources/APIServer/ContainerDNSHandler.swift`](https://github.com/apple/container/blob/main/Sources/APIServer/ContainerDNSHandler.swift)](https://github.com/apple/container/blob/main/Sources/APIServer/ContainerDNSHandler.swift), this handler resolves container hostnames by querying the IP allocations stored in `NetworksService`, enabling containers to reach each other by name rather than IP address.

## Creating and Managing Networks

Networks in Apple Container fall into two categories: the automatic default network and user-defined isolated networks.

### Default Network Behavior

When the system service starts, it automatically creates a **default network** named `default`. Every container joins this network unless explicitly configured otherwise. Containers on the default network share a common subnet and can communicate freely, but they remain isolated from containers on other user-defined networks.

### User-Defined Networks

Create isolated networks using the CLI to segment container traffic:

```bash
container network create foo --subnet 192.168.100.0/24 --subnet-v6 fd00:1234::/64

```

Each user-defined network operates in complete isolation. Containers attached to network `foo` cannot communicate with containers on network `bar` or the default network unless a container is explicitly attached to multiple networks.

### Internal Networks

Add the `--internal` flag during network creation to establish a **host-only network** that blocks all external traffic:

```bash
container network create isolated-backend --internal

```

### Custom MAC and MTU Configuration

When attaching containers to networks, specify deterministic hardware addresses or adjust packet sizes using comma-separated options in the `--network` flag:

```bash
container run -d --network foo,mac=02:42:ac:11:00:02,mtu=1500 nginx

```

## Connecting Containers to Networks

The runtime attaches virtual network interfaces to containers during the start phase and registers hostnames for DNS resolution.

### Basic Container Attachment

Use the `--network` flag with `container run` to specify which network (or networks) a container joins:

```bash
container run -d --name web --network foo --rm nginx:latest
container run -d --name db --network foo --rm postgres:latest

```

Both containers share the `foo` network and can address each other via their hostnames (`web` and `db`) through the `ContainerDNSHandler`.

### Multiple Network Attachment

Attach a container to several networks simultaneously to create gateway or bridge scenarios:

```bash
container run -d --name gateway \
  --network default \
  --network foo,mac=02:42:ac:11:00:02 \
  --rm some-gateway-image

```

The first network listed determines which IP address receives published port forwards. The runtime configures each interface separately while maintaining the DNS entries for all attached networks.

### DNS Resolution Mechanism

When a container queries a hostname, the `ContainerDNSHandler` performs A and AAAA lookups by querying `NetworksService`. If a hostname exists but lacks an IPv6 address, the handler returns a "NODATA" response rather than NXDOMAIN to accommodate musl libc's resolver behavior.

## Practical Workflow for Multi-Container Networking

Follow this sequence to establish communication between multiple containers across isolated networks.

1. **Create a dedicated network** (optional but recommended for isolation):

   ```bash
   container network create backend --subnet 10.0.0.0/24
   ```

2. **Launch containers on the network**:

   ```bash
   container run -d --name api --network backend --rm myapp:latest
   container run -d --name cache --network backend --rm redis:latest
   ```

3. **Verify IP assignments and connectivity**:

   ```bash
   container network inspect backend
   ```

4. **Clean up unused networks** when containers stop:

   ```bash
   container network prune
   ```

The `prune` command removes any network not attached to a running container while preserving the default and system-managed networks.

## Programmatic Network Management

Interact with the networking layer directly through Swift APIs for custom tooling or testing.

### Creating Networks via NetworksService

```swift
import ContainerServices

let config = NetworkConfiguration(
    name: "production",
    mode: .bridge,
    ipv4Subnet: "192.168.100.0/24",
    ipv6Subnet: "fd00:1234::/64",
    labels: ["env": "prod"],
    plugin: "container-network-vmnet",
    options: [:]
)

let network = try await networksService.create(configuration: config)
// The returned network contains the persisted configuration and runtime status

```

### Resolving Container DNS

```swift
import ContainerAPI

let dnsHandler = ContainerDNSHandler(networkService: networksService)
let query = Message(questions: [Question(name: "api.production.test.", type: .A)])

if let answer = try await dnsHandler.answer(query: query) {
    // answer contains the A record with the allocated IP address
}

```

Network configurations persist to disk via `FilesystemEntityStore<NetworkConfiguration>`, ensuring that subnet allocations and labels survive service restarts.

## Summary

- **Apple Container** uses the macOS vmnet framework to provide virtual networking for Linux containers running as lightweight VMs.
- The **default network** automatically connects all containers unless overridden, while **user-defined networks** provide isolation between container groups.
- **NetworksService** manages network lifecycle and IP allocation, while **ContainerDNSHandler** enables hostname-based communication between containers.
- Attach containers to multiple networks using repeated `--network` flags, with the first network determining the primary IP for port forwarding.
- Networks persist to disk and can be pruned when no longer in use, while internal networks provide host-only isolation for sensitive workloads.

## Frequently Asked Questions

### How do containers resolve each other's hostnames in Apple Container?

The `ContainerDNSHandler` queries the `NetworksService` to translate container names into IP addresses. When a container performs a DNS lookup for another container's hostname, the handler returns A or AAAA records based on the IP allocations stored in the network service. This allows containers to communicate using names like `web` or `db` instead of memorizing IP addresses.

### Can a container belong to multiple networks simultaneously?

Yes. Specify multiple `--network` flags when running a container. Each flag can include optional `mac` and `mtu` parameters. The container receives a virtual network interface for each network, and the first network listed determines which IP address receives published port traffic. This configuration is useful for creating gateway containers that bridge isolated networks.

### What is the difference between the default network and user-defined networks?

The **default network** is created automatically when the system service starts and connects all containers unless specified otherwise. **User-defined networks** are isolated from each other and from the default network, providing segmentation for multi-tier applications. You can create user-defined networks with custom subnets, IPv6 support, and internal (host-only) restrictions using the `container network create` command.

### How does Apple Container handle network persistence and cleanup?

Network configurations are stored on disk via `FilesystemEntityStore<NetworkConfiguration>`, allowing subnet settings and allocations to survive service restarts. When containers stop, you can remove unused networks with `container network prune`, which deletes any network not attached to a running container while preserving the default and system networks.