# How to Create and Run a Container with `container run` on macOS

> Learn how to easily create and run containers using container run on macOS. This command simplifies image acquisition, VM creation, and process execution for a seamless workflow.

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

---

**`container run` is the primary command for launching a container from an OCI image on macOS, combining image acquisition, VM creation, and process execution into a single workflow.**

The `apple/container` repository provides a native container runtime for macOS that uses Apple's Virtualization framework to run Linux containers. Understanding how to create and run a container with `container run` requires familiarity with the command-line interface, the underlying XPC communication architecture, and the resource configuration options available.

## Prerequisites: Building or Pulling an Image

Before you can create and run a container, you must have an OCI-compliant image available locally. You can either build a custom image or pull an existing one from a registry.

According to the tutorial documentation in [`docs/tutorials/start-here.md`](https://github.com/apple/container/blob/main/docs/tutorials/start-here.md), the standard workflow begins with building an image:

```bash
container build --tag web-test --file Dockerfile .

```

Alternatively, you can use pre-built images from registries. Once the image is available locally, the `container run` command can reference it by tag or digest.

## The Architecture of `container run`

When you execute `container run`, the CLI translates your arguments into a **ContainerRuntime** request that is sent over XPC to the `container-runtime-linux` helper. This process involves several key components from the `apple/container` source code.

### Command Parsing and Validation

The `container run` definition and its options are documented in the command reference at [`docs/command-reference.md`](https://github.com/apple/container/blob/main/docs/command-reference.md). The CLI validates flags such as `--cpus`, `--memory`, and `--network` before constructing the runtime request.

On macOS 15+, all containers attach to the default `vmnet` network automatically. If you specify an unsupported network option, the runtime returns an error during the validation phase.

### XPC Communication and Runtime Service

The core communication happens in [`Sources/Services/Runtime/RuntimeClient/RuntimeClient.swift`](https://github.com/apple/container/blob/main/Sources/Services/Runtime/RuntimeClient/RuntimeClient.swift). The `RuntimeClient` serializes your request into an `XPCMessage` and sends it to the runtime service.

The runtime service, implemented in [`Sources/Services/RuntimeLinux/Server/RuntimeService.swift`](https://github.com/apple/container/blob/main/Sources/Services/RuntimeLinux/Server/RuntimeService.swift), receives the XPC message and initiates the following sequence:

1. Creates a lightweight virtual machine (VZ) using Apple's Virtualization framework
2. Configures CPU and memory limits based on the request
3. Sets up the root filesystem from the OCI image
4. Starts the container process inside the VM

### Resource Allocation and Network Defaults

Default values for CPU, memory, and network configuration are stored in [`Sources/ContainerPersistence/ContainerSystemConfig.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ContainerSystemConfig.swift). When you omit resource flags, the system applies these defaults:

- **CPU limits**: Mapped to VZ CPU limits via the `--cpus` flag
- **Memory limits**: Configured using the `--memory` flag (e.g., `--memory 2G`)
- **Network**: Automatically assigned via `vmnet` with an IP address in the 192.168.64.x range

The runtime service tracks the container state (`running`, `stopped`, etc.) and implements signals, `kill`, `resize`, and cleanup based on flags like `--rm` and `--init`.

## Step-by-Step Process to Create and Run a Container

The complete workflow to create and run a container involves the following steps, as illustrated in the tutorial at [`docs/tutorials/start-here.md`](https://github.com/apple/container/blob/main/docs/tutorials/start-here.md).

### 1. Build the Image

Create your application image using the build command:

```bash
container build --tag my-app --file Dockerfile .

```

### 2. Run the Container

Invoke `container run` with your desired options. This example runs a detached container with automatic cleanup:

```bash
container run --name my-web-server --detach --rm web-test

```

The `--detach` flag runs the container in the background, while `--rm` ensures the container is automatically removed when the process exits. The CLI sends this request via XPC to the runtime service, which creates the VM and starts the process.

### 3. Verify the Container is Running

List running containers to confirm successful creation:

```bash
container ls

```

The output displays the container ID, image name, OS, architecture, state, and assigned IP address (e.g., `192.168.64.3`).

### 4. Interact with the Container

For interactive processes, use the `-it` flags:

```bash
container run -it my-app /bin/bash

```

To execute commands in a running container:

```bash
container exec my-web-server curl http://192.168.64.3

```

### 5. Monitor Resource Usage

Check container statistics with:

```bash
container stats --no-stream my-web-server

```

This displays CPU percentage, memory usage, network I/O, block I/O, and PID count.

### 6. Stop and Clean Up

If you did not use the `--rm` flag, stop and remove the container manually:

```bash
container stop my-web-server
container rm my-web-server

```

## Practical Code Examples

Here are common patterns for creating and running containers with various configurations:

```bash

# Run with an interactive shell

container run -it my-app /bin/bash

# Run detached with port mapping and resource limits

container run -d --name web \
    -p 8080:80 \
    --memory 2G \
    --cpus 2 \
    my-app

# Run with an init process to reap zombie processes

container run --init my-app

# Bind-mount a host directory into the container

container run --volume ${HOME}/src:/app \
    my-app

# Publish a UNIX socket from host to container

container run --publish-socket /tmp/host.sock:/var/run/container.sock \
    my-app

# Run with automatic cleanup and custom name

container run --rm --name temp-test alpine:latest echo "Hello"

```

## Summary

- **`container run`** is the primary command to create and run a container from an OCI image on macOS, handling VM creation, resource allocation, and process execution.
- **XPC Communication**: The CLI uses `RuntimeClient` ([`Sources/Services/Runtime/RuntimeClient/RuntimeClient.swift`](https://github.com/apple/container/blob/main/Sources/Services/Runtime/RuntimeClient/RuntimeClient.swift)) to send requests to the runtime service over XPC.
- **Resource Management**: CPU and memory limits are passed to the VZ virtual machine; defaults are stored in [`ContainerSystemConfig.swift`](https://github.com/apple/container/blob/main/ContainerSystemConfig.swift).
- **Networking**: On macOS 15+, containers automatically attach to the `vmnet` network with assigned IP addresses.
- **Lifecycle**: Use flags like `--rm` for automatic cleanup and `--init` for proper process management.

## Frequently Asked Questions

### What is the difference between `container run` and `container start`?

`container run` both creates and starts a new container from an image in a single command, whereas `container start` is used to start an existing, stopped container. According to the source in [`Sources/Services/RuntimeLinux/Server/RuntimeService.swift`](https://github.com/apple/container/blob/main/Sources/Services/RuntimeLinux/Server/RuntimeService.swift), `container run` initiates the full VM creation sequence, while `container start` resumes a previously configured container state.

### How does the `container run` command communicate with the macOS kernel?

The `container run` command does not interact directly with the kernel. Instead, it creates a `RuntimeClient` that sends XPC messages to the `container-runtime-linux` helper process. This helper, as implemented in [`RuntimeClient.swift`](https://github.com/apple/container/blob/main/RuntimeClient.swift), creates a lightweight Linux virtual machine using Apple's Virtualization framework (VZ), and the container process runs inside that isolated VM environment.

### Why does my container get an IP address in the 192.168.64.x range?

On macOS 15 and later, the `apple/container` runtime automatically attaches all containers to the default `vmnet` network bridge. This implementation detail, documented in [`docs/technical-overview.md`](https://github.com/apple/container/blob/main/docs/technical-overview.md), provides NAT-based networking where the host can communicate with the container via a predictable IP address range, while the container maintains network isolation from the host's primary interfaces.

### What happens if I omit the `--memory` or `--cpus` flags when running a container?

If you omit resource allocation flags, the runtime applies default values defined in [`Sources/ContainerPersistence/ContainerSystemConfig.swift`](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ContainerSystemConfig.swift). These defaults ensure that containers receive reasonable baseline resources without exhausting the host system. You can view and modify these defaults through the container configuration system, though explicit flags are recommended for production workloads to ensure predictable performance.