📦 deps(thirdparty): update snapshots

This commit is contained in:
ci[bot]
2026-07-10 16:04:20 +00:00
parent 2bb0dc8c1d
commit 92c0c3f687
594 changed files with 55224 additions and 19038 deletions
File diff suppressed because it is too large Load Diff
@@ -0,0 +1,294 @@
# `container` — Concepts & Architecture
Mental model for Apple's `container`: the one-VM-per-container design, the process
topology, platform requirements, networking, images/storage, and the security/isolation
model. Read this to explain *how* or *why* something works, or when a Docker mental model
gives the wrong answer. For concrete flags see `references/commands.md`; for defaults,
`config.toml`, and the machine settings see `references/configuration.md`; for end-to-end
recipes see `references/workflows.md`.
Sources: Apple's `docs/technical-overview.md`, `README.md`, `docs/container-machine.md`,
`SECURITY.md`, and `BUILDING.md`, as of the **1.0.0** release. For behavior on a specific
version, open the matching tag on the
[release page](https://github.com/apple/container/releases).
> **Not Docker.** The CLI is deliberately Docker-like (`container run`, `container build`, image
> ops under `container image`), but `container` is a distinct tool with a different runtime model.
> Do not assume Docker command paths, flags, defaults, or daemon behavior carry over (there is no
> `container images`/`push`/`pull` top-level command) — verify in `references/commands.md`.
---
## 1. What `container` is — one lightweight VM per container
`container` builds and runs standard **OCI/Linux containers** on **Apple-silicon** Macs. It's
written in Swift and built on Apple's open-source
[Containerization](https://github.com/apple/containerization) package for low-level container,
image, and process management.
The defining design choice: **each container you create runs inside its own dedicated
lightweight Linux VM.** This is the opposite of the usual macOS approach (Docker Desktop,
Podman, Lima), where a *single* long-lived Linux VM hosts a daemon and *all* containers share
that one kernel via namespaces.
Each per-container VM boots a **minimal Linux** — a small set of core utilities and dynamic
libraries plus a `vminitd` init — rather than a full userland. Consequences of the model:
| Property | What the per-container VM gives you |
|----------|-------------------------------------|
| **Security** | Every container has the isolation of a *full VM*, not just kernel namespaces. The minimal guest shrinks the attack surface and resource use. |
| **Privacy** | Mount **only the host data a given container needs** into that container's VM. A shared VM forces you to mount everything up front so it can be re-mounted selectively; per-container VMs avoid that broad exposure. |
| **Performance** | Lower memory than a full VM, with **boot times comparable to** containers inside a shared VM (sub-second in practice). |
| **Interop** | Consumes and produces standard **OCI images**, so images move freely to/from Docker registries and other OCI tooling. |
There is **no shared daemon** like `dockerd`. Instead, per-user background services run under
`launchd` and a runtime helper is launched **per container** (see §2).
---
## 2. Architecture — CLI, API server, and helper services
You drive everything through the **`container` CLI**. The CLI uses a **client library**
(`ContainerClient`) that talks over **XPC** to `container-apiserver` and its helpers.
```
container CLI
└── ContainerClient library ──XPC──► container-apiserver (launchd launch agent)
├──► container-core-images ──► local content store
├──► container-network-vmnet ──► virtual network (vmnet)
├──► builder (buildkit) ──► image builds
└──► container-runtime-linux (one instance per container)
└── my-web-server (that container's Linux VM)
```
| Component | Role | Lifecycle |
|-----------|------|-----------|
| `container` CLI + `ContainerClient` | Command entry point; talks to the apiserver over XPC. | Runs per invocation. |
| `container-apiserver` | **launchd launch agent** exposing the client APIs for container and network resources. Launches the helpers below. | Started by `container system start`, torn down by `container system stop`. |
| `container-core-images` | XPC helper exposing the **image-management API**; owns the **local content store**. | Started by the apiserver. |
| `container-network-vmnet` | XPC helper managing the **virtual network** via the vmnet framework; allocates container IPs. | Started by the apiserver. |
| `builder` (`buildkit`) | Utility VM that runs `container build`; communicates over gRPC. | On demand; runs as a container named `buildkit`. |
| `container-runtime-linux` | Container **runtime helper****one instance per container** — exposing the management API for that specific container's VM. | One per running container. |
`container system` is the control plane for this topology: `start`/`stop` bring the
apiserver and helpers up/down, `status` health-checks them, and `logs`/`df`/`kernel`/`dns`/
`property` manage system-wide state. **No container, image, or build command works until
`container system start` has run** — connection errors almost always mean the services are
stopped. See `references/configuration.md` for the full `container system` reference.
launchd service labels (all under the `com.apple.container.` prefix) look like:
```
com.apple.container.apiserver
com.apple.container.container-core-images
com.apple.container.container-network-vmnet.default
com.apple.container.container-runtime-linux.<container-name>
```
macOS frameworks `container` builds on: **Virtualization** (VMs + attached devices),
**vmnet** (virtual network), **XPC** (client↔service IPC), **launchd** (service management),
**Keychain** (registry credentials), and the **unified logging system** (logs, surfaced via
`container system logs`).
---
## 3. Requirements & platform constraints
| Requirement | Detail |
|-------------|--------|
| **Chip** | **Apple silicon only** (M1 or later). Intel Macs are not supported. |
| **macOS** | **macOS 26 is the supported target**`container` relies on new virtualization/networking features there. It **runs on macOS 15** but with the limitations in §7. Maintainers typically will not address issues that can't be reproduced on macOS 26. |
| **Install** | Download the signed `.pkg` from the GitHub release page and run it (installs under `/usr/local`, admin password required). Then `container system start`. |
Some features are **gated on macOS 26** because they depend on vmnet capabilities absent in
macOS 15 (see §4/§7). This gating is enforced at runtime: using a macOS-26-only feature (e.g.
`container network create`, or `--network <name>`) on macOS 15 **errors** rather than
degrading silently.
### macOS 26 vs macOS 15 — feature differences
| Capability | macOS 26 | macOS 15 |
|------------|----------|----------|
| Container-to-container traffic over the virtual network | Works | **Not possible** — vmnet only creates networks where attached containers are isolated from one another. |
| Multiple / custom networks (`container network` group, `--network <name>`) | Available | **Unavailable** — all containers attach to the single `default` vmnet network; `container network …` and `--network` **error**. |
| Container network creation timing | Robust | Network is created only when the **first container starts**; the network helper (which hands out IPs) and vmnet can **disagree on the subnet**, potentially cutting containers off. See "All networking fails on macOS 15" in the upstream `troubleshooting.md`. |
> Build-from-source requirement differs slightly: building needs **macOS 15 minimum, macOS 26
> recommended**, plus **Xcode 26** as the active developer directory (see §6).
---
## 4. Networking model
- Networking is provided by the macOS **vmnet framework**, managed by the
`container-network-vmnet` helper.
- `container system start` creates a vmnet network named **`default`**, typically on CIDR
**192.168.64.0/24** (gateway **192.168.64.1**). Containers attach to `default` unless
`--network` names another.
- **Each container is a first-class network endpoint with its own dedicated IP** on that
network (a direct consequence of the per-container-VM model — there is no shared Docker
bridge). The network helper allocates the IP; read it with `container ls` or
`container inspect <name>` (`.networks[].address`).
- **Reach a container by IP directly.** For name-based access, register a **local DNS domain**
(admin required) so unqualified container names resolve:
```bash
sudo container system dns create test # register domain "test" on the host resolver
# make it the default suffix by editing ~/.config/container/config.toml: [dns] domain = "test"
# (there is NO `property set` CLI — only `container system property list` to view values)
# a container named my-web-server is then reachable as my-web-server.test
```
DNS domain create/delete edits the host resolver configuration, so it **must run as
administrator** (`sudo`). The `dns.domain` property itself is set in `config.toml`, not via a
CLI setter. See `references/configuration.md` for the `dns` commands and the `dns.domain` property.
- **Reach a host service from a container:** create a domain pointed at a host IP with
`--localhost` (e.g. `sudo container system dns create host.container.internal --localhost
203.0.113.113`). Note the macOS caveats: this disables Private Relay, and the packet-filter
rule is dropped on restart.
- **Publish ports to the Mac's loopback** with `--publish [host-ip:]host-port:container-port
[/protocol]`. If a container is on multiple networks, published ports forward to the
interface on the **first** network.
- **Custom / isolated networks require macOS 26.** Create with `container network create
<name> [--subnet … --subnet-v6 …]`. Networks are **mutually isolated** — a container on one
network has no connectivity to containers on another. Default subnets for new networks come
from the `[network]` config (`network.subnet` / `subnetv6`) or are auto-allocated
non-overlapping; the system rejects overlapping custom subnets. Networks support IPv4 and
IPv6. On macOS 15 this whole group is unavailable (§3).
---
## 5. Images & storage
- **Standard OCI in, standard OCI out.** Pull/run images from any OCI registry, and push
images you build to any OCI registry; they run in any other OCI-compatible tool.
- The **local content store** (host-side image/content storage) is owned by the
`container-core-images` helper, which exposes the image-management API. Manage it with the
`images` command group and disk usage with `container system df`.
- **Registries:** image references that omit a host default to **`docker.io`**, configurable
via the `registry.domain` property (see `references/configuration.md`). Prefer
fully-qualified references (`docker.io/library/alpine`, not bare `alpine`) when the source
registry matters. Registry credentials are stored in the macOS **Keychain**.
- **Selective host data sharing.** Only the data a given container needs is mounted into that
container's VM — a privacy/isolation win over the shared-VM model where everything must be
mounted into the one VM up front.
- The application **data root** (default `~/Library/Application Support/com.apple.container/`)
holds `content/`, `containers/`, `images`, `kernels/`, `networks/`, `volumes/`, etc. — see
the data-locations table in `references/configuration.md`.
---
## 6. Security, isolation & building from source
**Isolation model.** Each container is a **full VM**, so isolation is VM-grade rather than
namespace-grade as in a shared-daemon runtime. The minimal guest (small core utility/library
set + `vminitd`) keeps each VM's attack surface and footprint small, and per-container host
mounts limit data exposure to exactly what each container needs.
**Security reporting.** Report vulnerabilities via the project's
[GitHub private vulnerability reporting](https://github.com/apple/container/security/advisories/new),
not public issues. Known/published CVEs may be filed as normal issues. These reports are
**not** eligible for Apple Security Bounties.
**Building from source (brief).** Requires Apple silicon, **macOS 15 min / 26 recommended**,
and **Xcode 26** set as the active developer directory.
```bash
# Build + run tests in an isolated data dir
rm -rf test-data
make APP_ROOT=test-data all test integration
# Install binaries to /usr/local/bin and /usr/local/libexec (admin password)
make install
# Release build (better perf than debug)
BUILD_CONFIGURATION=release make all test integration
BUILD_CONFIGURATION=release make install
```
> **vmnet path bug (macOS 26):** network creation fails if the `container` helper binaries
> live under `~/Documents` or `~/Desktop`. Use `make install` (runs from `/usr/local`), or
> keep the project elsewhere (e.g. `~/projects/container`) when running the `bin`/`libexec`
> build artifacts directly.
To develop against a local checkout of the Containerization package or `container-builder-shim`,
point the runtime config (`~/.config/container/config.toml`) at your local `vminit`/builder
image and restart the services — see `BUILDING.md` for the exact swift-package steps. Attach a
debugger to an XPC helper by exporting `CONTAINER_DEBUG_LAUNCHD_LABEL=<launchd-label>` before
`container system start`.
---
## 7. How it differs from Docker, when to prefer it, and known limits
### `container` vs Docker / shared-VM on macOS
| Aspect | `container` (Apple) | Docker / shared-VM on macOS |
|--------|---------------------|-----------------------------|
| VM topology | **One lightweight Linux VM per container** | One big Linux VM shared by all containers |
| Isolation | Full-VM per container | Namespace isolation within one VM |
| Guest contents | Minimal core utils + libs + `vminitd` | Full Linux userland + daemon |
| Control plane | CLI → `ContainerClient` → `container-apiserver` (launchd) + XPC helpers | `dockerd` daemon inside the shared VM |
| Host data sharing | Mount only what each container needs | Mount everything into the shared VM up front |
| Networking | Per-container dedicated IP on vmnet (`default` ≈ 192.168.64.0/24) | Shared VM networking / Docker bridge |
| Images | Standard **OCI** in/out | OCI |
| Platform | **Apple silicon + macOS 26** (15 with limits) | Cross-platform |
**Prefer `container` when:** you're on Apple silicon and want VM-grade isolation per
container, minimal per-container footprint, per-container IPs, tight macOS integration
(launchd/Keychain/unified logging), and no always-on shared daemon. **Prefer Docker/Podman
when:** you need Intel-Mac support, features `container` hasn't implemented yet, or maximum
Docker-flag/ecosystem compatibility.
### Known limitations
- **Memory is not fully returned to macOS.** The Virtualization framework has only partial
memory ballooning. A VM uses only what the app needs (start with `--memory 16g` but see ~2
GiB in Activity Monitor), but pages freed *inside* the guest are **not** relinquished to the
host. Running many memory-heavy containers may require occasionally **restarting** them.
- **Young project.** 1.0.0 is the first stable release; some containerization features common in
Docker are still unimplemented (check `container <group> --help`). Expect standard semver going
forward — breaking changes on major bumps, not patch releases.
- **macOS 15 networking limits** (see §3): no container-to-container traffic, single `default`
network only, `container network`/`--network` unavailable, and a network-creation race that
can cut containers off.
---
## 8. Container machines — a related but distinct concept
> **⚠️ Requires 1.0.0+.** The `container machine` group was added in 1.0.0 (not in 0.7.1). Check
> `container machine --help` on your install.
`container machine` (alias `m`) is **not** the app-shaped container above: it's a persistent,
integrated **Linux environment** modeled after a distro rather than a single app. It runs the
image's **init system** (so you can register long-running services / a process supervisor),
and **auto-maps your host username and home directory** into the guest, so your repos and
dotfiles are available on both sides with no copy step.
| Trait | Container | Container machine |
|-------|-----------|-------------------|
| Modeled after | one application | a full Linux environment / distro |
| Init | minimal (`vminitd`) | the image's own init (e.g. `systemd`) |
| User | as configured / `root` | matches your **host** account; `$HOME` mounted in |
| Lifetime | ephemeral by task | **persistent** across stop/start |
```bash
container machine create alpine:latest --name dev
container machine run -n dev whoami # your host username, not root
container machine run -n dev # interactive shell; your $HOME is mounted in
container machine set-default dev # then drop -n
container machine set -n dev cpus=4 memory=8G # takes effect after next stop/start
```
- Memory defaults to **half of host memory**; the home mount can be `rw` (default), `ro`, or
`none`. Changes via `container machine set` apply after the next stop/start.
- **Nested virtualization** (`--virtualization` + a custom `CONFIG_KVM=y` kernel via
`--kernel`) needs **Apple silicon M3+ and macOS 15+**; the default kernel does not support
it.
- **Bring your own image:** any Linux image with `/sbin/init` works. On first boot `container`
runs a built-in setup script to provision the mapped user; override it with an executable
`/etc/machine/create-user.sh` in the image (runs once as root with `CONTAINER_UID`,
`CONTAINER_GID`, `CONTAINER_USER`, `CONTAINER_HOME`, `CONTAINER_MACHINE_ID` set).
See `references/commands.md` for the full `machine` subcommand/flag matrix.
@@ -0,0 +1,499 @@
# Configuration & administration
Admin guide for Apple's `container` CLI runtime (Apple silicon macOS). This is **not Docker**
the CLI is Docker-like but the runtime is a per-container lightweight VM. For exhaustive
flags/subcommands see `commands.md`; this file covers the operator surface only.
The runtime is a set of launchd-managed services (`container-apiserver` + machine API server +
background helpers). Almost everything below drives those services. Every command accepts
`--debug` (env `CONTAINER_DEBUG`). Most `list`/`status` commands accept `--format` — commonly
`json`, `table`, `yaml`, and `toml` (the exact value set and default vary by command, e.g. `table`
for `container list` but `toml` for `system property list`; check `<command> --help`).
---
## 1. System service: start / stop / status / logs
The `container` services must be running before any container/image/build command works.
```bash
container system start # register services in launchd, launch apiserver + machine API
container system status # health-check; prints running state + data/install roots
container system stop # stop all services and deregister from launchd
container system logs # recent service logs (default last 5m)
container system logs -f # live tail
container system logs --last 1h
```
`system start` behavior worth knowing:
- Launches `container-apiserver` via launchd, then **pings it** and fails if unresponsive
(bump `--timeout <seconds>` on slow machines).
- On first run it **installs the base filesystem (`vminit`) image** and prompts to install the
**default kernel** unless you pass `--enable-kernel-install` / `--disable-kernel-install`.
- Loads `config.toml` (see §2) once, at startup. **Restart after any config/property change:**
`container system stop && container system start`.
| `system start` flag | Purpose | Default |
|---------------------|---------|---------|
| `-a, --app-root <path>` | Application data root | `~/Library/Application Support/com.apple.container/` |
| `--install-root <path>` | Executables/plugins root | `/usr/local/` |
| `--log-root <path>` | Log dir; unset → macOS unified log | unset |
| `--enable-kernel-install` / `--disable-kernel-install` | Install default kernel or not (mutually exclusive) | prompt |
| `--timeout <seconds>` | Wait for apiserver readiness | XPC default |
`system stop` takes `-p, --prefix <prefix>` (launchd prefix, default `com.apple.container.`);
`system status` takes the same `--prefix` plus `--format`.
`system df` shows reclaimable disk usage for images/containers/volumes:
```bash
container system df --format json
```
**Data locations** (reported by `system status`):
| Location | Default path |
|----------|--------------|
| App data root | `~/Library/Application Support/com.apple.container/` |
| Install root | `/usr/local/` |
| User config | `~/.config/container/config.toml` |
| Package config | `<installRoot>/etc/container/config.toml` (e.g. `/usr/local/etc/...`) |
Data root holds `apiserver/`, `builder/`, `containers/`, `content/`, `kernels/`, `networks/`,
`volumes/`, `snapshots/`, `plugin-state/`, `user-plugins/`, and `state.json`.
---
## 2. System properties / config.toml
One `ContainerSystemConfig` drives the runtime. **Configure it by editing `config.toml`**;
`container system property list` is a read-only view of the effective (merged) values.
- **`config.toml`** section tables (`[build]`, `[container]`, …) are loaded at service startup,
first-match-wins across `~/.config/container/config.toml` then
`<installRoot>/etc/container/config.toml`. Missing keys fall back to hardcoded defaults.
- **Flat property IDs** (e.g. `build.rosetta`, `dns.domain`) are how the same values are named
and reported. `container system property` has only the `list` subcommand — there is **no**
per-key `get`, `set`, or `clear`. To change a value edit `config.toml`; to revert one, remove
its key.
Property ID ⇄ TOML mapping is direct: `build.rosetta``[build] rosetta`, etc. (exceptions:
the builder/vminit image IDs — see table).
```bash
# View effective values (read-only)
container system property list # all IDs, types, current values (default: toml)
container system property list --format json
```
```toml
# Change values by editing ~/.config/container/config.toml, then restart services
[container]
cpus = 8
[registry]
domain = "ghcr.io"
```
```bash
container system stop && container system start # apply; remove a key to revert it
```
**Every configurable key:**
| Property ID | TOML | Type | Default | Meaning |
|-------------|------|------|---------|---------|
| `build.rosetta` | `[build] rosetta` | Bool | `true` | Build amd64 images on arm64 via Rosetta (else QEMU) |
| `build.cpus` | `[build] cpus` | Int | `2` | Builder VM CPU count |
| `build.memory` | `[build] memory` | MemorySize | `"2048mb"` | Builder VM RAM |
| `image.builder` | `[build] image` | String | `ghcr.io/apple/container-builder-shim/builder:<ver>` | Builder (BuildKit) image reference |
| `container.cpus` | `[container] cpus` | Int | `4` | Default CPUs per container (when `run`/`create` omit `--cpus`) |
| `container.memory` | `[container] memory` | MemorySize | `"1g"` | Default RAM per container |
| `dns.domain` | `[dns] domain` | String? | unset | Local domain appended to unqualified container names (§4) |
| `registry.domain` | `[registry] domain` | String | `"docker.io"` | Default registry for bare image refs (§5) |
| `kernel.url` | `[kernel] url` | URL | kata-static release URL | Kernel file or archive to install (§3) |
| `kernel.binaryPath` | `[kernel] binaryPath` | String | `opt/kata/share/kata-containers/vmlinux-<ver>` | Archive-member path of the kernel |
| `network.subnet` | `[network] subnet` | CIDRv4? | unset | Default IPv4 subnet for networks; auto-allocates when unset (§7) |
| — | `[network] subnetv6` | CIDRv6? | unset | Default IPv6 prefix for networks; auto-allocates when unset (§7) |
| `image.init` | `[vminit] image` | String | `ghcr.io/apple/containerization/vminit:<ver>` | `vminitd` image booting container VMs |
| — | `[plugin.<id>]` | — | — | Plugin-scoped config; each plugin reads only its own section |
> Exact defaults (kernel version, image tags) drift per release. Confirm with
> `container system property list`; do not assume a specific version.
**MemorySize** = quoted string, integer + binary unit (`b/kb/mb/gb/tb/pb`, powers of 1024, case-insensitive);
bare integer = bytes. `"2g"` re-emits as `"2gb"`. **CIDR** = quoted, e.g. `"192.168.100.0/24"`.
Minimal `config.toml` example:
```toml
[container]
cpus = 8
memory = "4g"
[dns]
domain = "test"
```
The full per-section `config.toml` schema (keys, types, defaults, meaning), the flat property
list as emitted by the CLI, type-format details, and data locations are in the
[appendix](#appendix-configtoml-schema--data-locations).
---
## 3. Default kernel
The default guest kernel is the Linux kernel every container VM boots. Managed via
`container system kernel set` (writes the default) plus the `kernel.url` / `kernel.binaryPath`
properties (the download source `--recommended` uses).
```bash
container system kernel set --recommended # download + install Apple's recommended kernel
container system kernel set --binary ./vmlinux --force # install a local binary, overwrite
container system kernel set --tar https://ex.com/kata-static.tar.xz \
--binary opt/kata/share/kata-containers/vmlinux-6.12.28-153 --arch arm64
```
| Flag | Purpose | Default |
|------|---------|---------|
| `--recommended` | Download+install recommended kernel. **Overrides `--arch`/`--binary`/`--tar`** | — |
| `--arch <amd64\|arm64>` | Kernel architecture | `arm64` |
| `--binary <path>` | Kernel file, or archive-member name when used with `--tar` | — |
| `--tar <path\|url>` | Tar archive (local or remote) containing the kernel | — |
| `--force` | Overwrite an existing kernel of the same name | — |
- Persist a custom source by editing `config.toml`:
```toml
[kernel]
url = "<url>"
binaryPath = "<member>"
```
- Kernel install is also toggled at startup via `system start --enable/--disable-kernel-install`.
- Per-machine kernel override is separate — see §7 (`machine set kernel=<path>`).
---
## 4. DNS / local domain resolution
Register a **local DNS domain** so unqualified container names resolve host-side (e.g.
`my-web` → `my-web.test`). Creating/deleting a domain **modifies the host resolver and
requires admin** (`sudo`); it restarts `mDNSResponder`.
```bash
sudo container system dns create test # register domain "test"
sudo container system dns create test --localhost 127.0.0.1 # redirect an IPv4 to localhost
container system dns list # list domains (no sudo)
sudo container system dns delete test # alias: rm
```
```toml
# Activate "test" as the default domain in ~/.config/container/config.toml
[dns]
domain = "test"
```
```bash
container system stop && container system start
```
- `--localhost` must be a valid **IPv4** address; it installs a pf redirect rule to `127.0.0.1`.
- Registering a domain is not enough — set `[dns] domain` in `config.toml` to activate it for
unqualified names.
- If domain deactivation misbehaves: `sudo killall -HUP mDNSResponder`.
---
## 5. Default registry & authentication
Bare image refs resolve against the default registry (`registry.domain`, default `docker.io` →
`alpine` becomes `docker.io/library/alpine`).
```toml
# Change the default registry in ~/.config/container/config.toml (restart to apply);
# remove the key to revert to docker.io
[registry]
domain = "ghcr.io"
```
**Auth** (`container registry`, alias `r`) — credentials are stored in the macOS keychain:
```bash
container registry login registry.example.com # prompts user + password
container registry login -u alice ghcr.io # prompt password only
echo "$TOKEN" | container registry login -u alice --password-stdin ghcr.io # non-interactive
container registry list # HOSTNAME/USERNAME/MODIFIED/CREATED (1.0.0+)
container registry logout ghcr.io
```
| Command | Key flags | Notes |
|---------|-----------|-------|
| `login <server>` | `-u/--username`, `--password-stdin`, `--scheme <http\|https\|auto>` | `--password-stdin` **requires** `--username`. On success pings the registry then saves to keychain |
| `logout <registry>` | — | Deletes keychain creds for the resolved host |
| `list` (`ls`) | `--format`, `-q/--quiet` | `-q` prints hostnames only |
**Insecure / HTTP registries** — `--scheme` (default `auto`):
- `auto` → `http` for internal/private hosts (`localhost`, the internal DNS domain, and RFC-1918
ranges `10/8`, `127/8`, `192.168/16`, `172.16/12`); `https` for everything else.
- Force plaintext against a local registry: `container registry login --scheme http localhost:5000`.
- `--scheme` also applies to image `pull`/`push` and `machine create` (same enum).
> `registry list` only lists saved logins. There is no `default-registry get/set` subcommand —
> the default registry lives in the `registry.domain` property (above).
---
## 6. BuildKit builder VM
`container build` runs inside a utility container named **`buildkit`** (a lightweight VM). It
auto-starts on first build; manage it explicitly with `container builder` when you need more
resources or a clean slate.
```bash
container builder start --cpus 8 --memory 32g # start with more resources
container builder status # ID/IMAGE/STATE/IP/CPUS/MEMORY
container builder stop
container builder delete # alias: rm (add --force if running)
```
To resize a running builder, recreate it:
```bash
container builder stop && container builder delete && container builder start --cpus 8 --memory 32g
```
| Command | Flags | Notes |
|---------|-------|-------|
| `start` | `-c/--cpus <n>`, `-m/--memory <size>` (K/M/G/T/P suffix) | Falls back to `build.cpus`/`build.memory` (defaults 2 CPUs / 2048 MiB). Reuses an existing matching builder; recreates if image/cpu/mem/env/DNS changed |
| `status` | `--format`, `-q/--quiet` | Prints `builder is not running` when absent |
| `stop` | — | No-op warning if not running |
| `delete` (`rm`) | `-f/--force` | Errors unless stopped; `--force` stops then deletes |
- Image comes from `image.builder` / `[build] image`; Rosetta-vs-QEMU for amd64 builds is
`build.rosetta`.
- Persistent builder defaults (not just this session) go in `[build] cpus` / `[build] memory`
in `config.toml`.
---
## 7. Machines, custom networks, volumes
### Machines (`container machine`, alias `m`)
> **⚠️ Requires 1.0.0+ — the `container machine` group was added in 1.0.0 (not in 0.7.1).**
A **container machine** is a persistent, bootable Linux **environment** (not a one-shot
container) — it runs the image's init system, auto-mounts your macOS `$HOME` and username, and
persists across restarts. Ideal for "edit on Mac, build inside Linux" and running long-lived
services. Distinct from the transient per-container VMs that back `container run`.
```bash
container machine create alpine:3.22 --name dev --set-default
container machine run # interactive shell in the default machine (matches host user)
container machine run -n dev uname
container machine run -n dev -- cat /proc/cpuinfo # everything after -- passed through verbatim
container machine list # ls: NAME/CREATED/IP/CPUS/MEMORY/DISK/STATE/DEFAULT(*)
container machine inspect dev # JSON detail
container machine set -n dev cpus=4 memory=8G home-mount=ro # takes effect after stop/start
container machine set-default dev
container machine stop dev
container machine delete dev # rm: also deletes persistent storage
container machine logs -f -n 100 dev # --boot for boot log
```
| Subcommand | Key flags / settable keys | Notes |
|------------|---------------------------|-------|
| `create <image>` | `-n/--name`, `--set-default`, `--no-boot`, `--cpus`, `--memory`, `--home-mount <ro\|rw\|none>`, `--virtualization`, `--kernel <path>` | Memory default = half host RAM; home-mount default `rw`. Name defaults to `<image>-<tag>` |
| `set [-n]` | `cpus=`, `memory=`, `home-mount=`, `virtualization=<bool>`, `kernel=<path>` (empty `kernel=` resets to default) | `key=value`; last dupe wins; unknown key errors. Changes apply after stop/start |
| `run` | `-d/--detach`, `--root`, `-e/--env`, `-i`, `-t`, `-u/--user`, `-w/--workdir`, `--ulimit` | Boots machine if stopped; forwards `SSH_AUTH_SOCK` |
| `logs` | `--boot`, `-f/--follow`, `-n <lines>` | `-n` is short-only |
| `list`/`inspect`/`stop`/`delete`(`rm`)/`set-default` | ID optional (uses default) except `set-default`/`delete` | — |
**Nested virtualization / custom kernel** (per-machine): requires Apple Silicon **M3+** on
**macOS 15+** and a kernel with `CONFIG_KVM=y` (the default kernel does not qualify).
```bash
container machine create --virtualization --kernel /path/to/vmlinux-kvm -n kvm-dev alpine:latest
container machine run -n kvm-dev -- ls -l /dev/kvm # verify /dev/kvm exposed
```
Any Linux image with `/sbin/init` works. Override first-boot user provisioning by adding an
executable `/etc/machine/create-user.sh` (runs once as root; env `CONTAINER_{UID,GID,USER,HOME,MACHINE_ID}`).
### Custom networks (`container network`, alias `n`) — **macOS 26+**
`system start` always creates a builtin vmnet network `default`. On **macOS 26+** you can create
additional **isolated** networks (no cross-network connectivity). Builtin networks cannot be deleted.
```bash
container network create foo # prints network ID
container network create foo --subnet 192.168.100.0/24 --subnet-v6 fd00:1234::/64
container network list # ls: NETWORK/SUBNET
container network inspect foo # pretty JSON
container run -d --name web --network foo web-test # attach a container
container network delete foo # rm; add --all for all non-builtin
container network prune # remove networks with no attached containers
```
| Flag (`create`) | Purpose | Default |
|-----------------|---------|---------|
| `--subnet <cidr4>` / `--subnet-v6 <cidr6>` | Custom subnets (validated non-overlapping) | auto-allocate / `network.subnet(v6)` |
| `--internal` | Host-only network (no NAT) | NAT |
| `--label k=v` / `--option k=v` | Metadata / plugin option (repeatable) | — |
| `--plugin <name>` | Network plugin | `container-network-vmnet` |
`delete --all` skips builtin networks; deleting a network fails if any IP is still in use.
Persistent default subnets → `network.subnet` / `[network] subnetv6`. Their effect is
version-dependent: on **macOS 15** they set the subnet of the single builtin `default` network;
on **macOS 26+** they additionally seed the default subnet for custom networks created without an
explicit `--subnet`/`--subnet-v6`. In both cases, if left unset the system auto-allocates a
non-overlapping subnet.
### Volumes (`container volume`, alias `v`)
A **volume** is host-backed storage you mount into containers to persist/share data across runs
(`container run --volume <name>:/path` or a host `path:path`). Driver is always `local`.
```bash
container volume create mydata -s 10G # prints volume name (-s takes K/M/G/T/P)
container volume create mydata --label env=dev --opt key=val
container volume list # ls: NAME/TYPE/DRIVER/OPTIONS
container volume inspect mydata # pretty JSON
container volume delete mydata # rm; --all for all volumes
container volume prune # remove volumes with no container refs; reports reclaimed space
```
| Flag (`create`) | Purpose |
|-----------------|---------|
| `-s <size>` | Size in bytes, K/M/G/T/P suffix (stored as driver opt `size`) |
| `--label k=v` | Metadata (repeatable) |
| `--opt k=v` | Driver-specific option (repeatable) |
`delete`/`network delete` require either names **or** `--all` (not both); a missing named
resource errors, while `--all` tolerates an empty set.
---
## Appendix: `config.toml` schema & data locations
One underlying `ContainerSystemConfig` is configured by editing a **`config.toml`** file with
`[section]` tables loaded once at service startup. The same values are also named as flat
**property IDs** (`build.rosetta`, `dns.domain`, …) — view them read-only with
`container system property list` (its only subcommand; there is no `get`/`set`/`clear`). Property
IDs map onto TOML sections directly (`build.rosetta` ⇄ `[build] rosetta`), with two naming
exceptions: the builder image is `image.builder` ⇄ `[build] image`, and the vminitd image is
`image.init` ⇄ `[vminit] image`. For the CLI commands themselves see `commands.md`.
### Sources & precedence
TOML is loaded **first-match-wins**, then any key absent from both files falls back to a
hardcoded default:
1. User file — `~/.config/container/config.toml`
2. Package file (optional) — `<installRoot>/etc/container/config.toml`
(e.g. `/usr/local/etc/container/config.toml`)
The file is read **once at startup**; restart after edits
(`container system stop && container system start`).
### Top-level sections
```toml
[build] # builder VM resources and image
[container] # default per-container resources
[dns] # default DNS domain for host DNS resolution
[kernel] # guest kernel binary path and download URL
[network] # default subnets for networks
[registry] # default registry domain
[vminit] # default vminitd image
[plugin.<id>] # zero or more plugin-scoped sections
```
All sections are optional; an omitted section falls back to its defaults wholesale. (The Swift
source also defines an internal `[machine]` section, not part of the documented user schema.)
### `[build]` — builder VM (runs `container build`)
| Key | Property ID | Type | Default | Description |
|-----|-------------|------|---------|-------------|
| `rosetta` | `build.rosetta` | Bool | `true` | Build amd64 images on arm64 using Rosetta translation, instead of QEMU. |
| `cpus` | `build.cpus` | Int | `2` | CPU count for the builder VM. |
| `memory` | `build.memory` | MemorySize | `"2048mb"` | RAM allocation for the builder VM. |
| `image` | `image.builder` | String | `ghcr.io/apple/container-builder-shim/builder:<tag>` | Reference for the builder image; `<tag>` tracks the bundled `container-builder-shim` version. (Property ID is `image.builder`, not `build.image` — see the naming exception above.) |
### `[container]` — default per-container resources
Applied when `container run` / `container create` runs without `--cpus` / `--memory`.
| Key | Property ID | Type | Default | Description |
|-----|-------------|------|---------|-------------|
| `cpus` | `container.cpus` | Int | `4` | Default CPU count per container. |
| `memory` | `container.memory` | MemorySize | `"1g"` | Default RAM per container. |
### `[dns]` — local DNS domain
| Key | Property ID | Type | Default | Description |
|-----|-------------|------|---------|-------------|
| `domain` | `dns.domain` | String? | unset | Local DNS domain appended to unqualified container hostnames. `"test"` makes `my-web` resolvable as `my-web.test`. Unset → no domain appended. See §4 for the register-then-activate workflow. |
### `[kernel]` — default guest kernel
Defaults change per release as kernels are bumped; confirm with
`container system property list`.
| Key | Property ID | Type | Default | Description |
|-----|-------------|------|---------|-------------|
| `binaryPath` | `kernel.binaryPath` | String | `opt/kata/share/kata-containers/vmlinux-<ver>` | Archive-member pathname of the kernel, when the URL points at an archive. |
| `url` | `kernel.url` | URL | kata-static release `.tar.xz`/`.tar.zst` | URL of the kernel file to install, or of an archive containing it. |
### `[network]` — default subnets
Used when creating networks without explicit `--subnet` / `--subnet-v6`. See §7 for the
macOS 15 vs macOS 26+ behavior.
| Key | Property ID | Type | Default | Description |
|-----|-------------|------|---------|-------------|
| `subnet` | `network.subnet` | CIDRv4? | unset | IPv4 CIDR, e.g. `"192.168.100.0/24"`. Unset → system auto-allocates a non-overlapping subnet. |
| `subnetv6` | — | CIDRv6? | unset | IPv6 CIDR, e.g. `"fd00:abcd::/64"`. Unset → system auto-allocates. |
### `[registry]` — default registry
| Key | Property ID | Type | Default | Description |
|-----|-------------|------|---------|-------------|
| `domain` | `registry.domain` | String | `"docker.io"` | Default registry for image references that omit a registry host (`alpine` → `docker.io/library/alpine`). See §5. |
### `[vminit]` — default vminitd image
| Key | Property ID | Type | Default | Description |
|-----|-------------|------|---------|-------------|
| `image` | `image.init` | String | `ghcr.io/apple/containerization/vminit:<tag>` | Reference for the `vminitd` image used to boot container VMs; `<tag>` tracks the bundled `containerization` version. |
### `[plugin.<id>]` — plugin-scoped config
Plugins ship their own schemas under `[plugin.<id>]` (`<id>` = plugin identifier). Each plugin
defines and reads only its own section; values cannot leak across plugins. Consult the specific
plugin's documentation for its keys.
### Type formats
**MemorySize** — a quoted string: numeric prefix + binary unit suffix (case-insensitive). All
units are **binary** (powers of 1024) even when written `kb`/`mb`/`gb`. A bare integer (`"2048"`)
parses as bytes. Encoded form uses lowercase `b`/`kb`/`mb`/`gb`/`tb`/`pb` (so `"2g"` re-emits as
`"2gb"`).
| Suffix family | Unit | Examples |
|---------------|------|----------|
| `b` | bytes | `"1024b"` |
| `k`, `kb`, `kib` | kibibytes (1024 B) | `"512k"`, `"512kb"` |
| `m`, `mb`, `mib` | mebibytes | `"2048mb"` |
| `g`, `gb`, `gib` | gibibytes | `"4g"`, `"4gb"` |
| `t`, `tb`, `tib` | tebibytes | `"1t"` |
| `p`, `pb`, `pib` | pebibytes | `"1p"` |
**CIDRv4 / CIDRv6** — quoted strings, e.g. `"192.168.100.0/24"` and `"fd00:abcd::/64"`. Invalid
CIDR strings are rejected at decode time.
### Data locations
Reported by `container system status`:
| Location | Path (default) | Overridable with |
|----------|----------------|------------------|
| Application data root | `~/Library/Application Support/com.apple.container/` | `container system start --app-root <path>` |
| Application install root | `/usr/local/` | `container system start --install-root <path>` |
| Log root | macOS unified log facility (if unset) | `container system start --log-root <path>` |
| User config file | `~/.config/container/config.toml` | — |
| Package config file | `<installRoot>/etc/container/config.toml` (e.g. `/usr/local/etc/container/config.toml`) | — |
The data root contains subdirectories such as `apiserver/`, `builder/`, `containers/`,
`content/`, `kernels/`, `networks/`, `plugin-state/`, `snapshots/`, `user-plugins/`, `volumes/`,
and a top-level `state.json`.
@@ -0,0 +1,498 @@
# `container` — Task-Oriented Workflows
Copy-pasteable recipes for Apple's `container` CLI (`apple/container`) — Linux containers as
lightweight VMs on Apple-silicon macOS. This is **Apple's `container`, not Docker**: flags,
defaults, and the daemon model differ. See `commands.md` for the full flag reference. Use
fully-qualified image refs (`docker.io/library/alpine`) in scripts. `container` targets
**macOS 26**; several features are gated (called out inline).
> **Version:** recipes track the **1.0.0** release. `container cp`, `container prune`,
> `container image prune`, and `container system version` used below were added in 1.0.0 (not in
> 0.7.1) — run `container --help` to confirm your installed surface.
## Recipes
- [First run: install + start + first container](#first-run-install--start--first-container)
- [Run interactive vs detached](#run-interactive-vs-detached)
- [Publish ports](#publish-ports)
- [Set environment variables](#set-environment-variables)
- [Mounts: bind, volume, tmpfs](#mounts-bind-volume-tmpfs)
- [Build an image from a Dockerfile](#build-an-image-from-a-dockerfile)
- [Multi-tag, build-args, no-cache, target](#multi-tag-build-args-no-cache-target)
- [Tag & push to Docker Hub / private registry](#tag--push-to-docker-hub--private-registry)
- [Set the default registry](#set-the-default-registry)
- [Container-to-container networking](#container-to-container-networking)
- [Local DNS domain for name resolution](#local-dns-domain-for-name-resolution)
- [Custom isolated networks (macOS 26)](#custom-isolated-networks-macos-26)
- [Inspect a container](#inspect-a-container)
- [View logs](#view-logs)
- [Exec into a running container](#exec-into-a-running-container)
- [Copy files in and out](#copy-files-in-and-out)
- [Resource limits (CPU / memory)](#resource-limits-cpu--memory)
- [Cleanup: stop, remove, prune](#cleanup-stop-remove-prune)
- [Upgrade / downgrade / uninstall](#upgrade--downgrade--uninstall)
- [Troubleshooting](#troubleshooting)
---
### First run: install + start + first container
There is **no CLI installer command** — download and double-click the signed `.pkg`, then start
the services and run a container.
```bash
# 1. Download the signed installer .pkg from the GitHub releases page:
# https://github.com/apple/container/releases
# Double-click the .pkg and follow the prompts (admin password installs under /usr/local).
# 2. Start the background services. On first run this prompts to install the default Linux kernel.
container system start
# 3. Verify (empty list is expected on a fresh install).
container list --all
# 4. Run your first container.
container run --rm -it docker.io/library/alpine:latest sh
```
Note: double-clicking the `.pkg` is the only install path; `container system start` prompts for the recommended kernel (or use `container system kernel set --recommended`).
---
### Run interactive vs detached
```bash
# Interactive shell (-i keeps stdin open, -t allocates a TTY; commonly combined as -it).
container run --rm -it docker.io/library/ubuntu:latest /bin/bash
# Detached, named, auto-removed on stop.
container run -d --name web --rm docker.io/library/nginx:latest
# One-shot command in the foreground (exits when the command finishes).
container run --rm docker.io/library/alpine:latest uname -a
```
Note: foreground by default; stdin stays closed unless `-i`. `--rm` deletes the container after it exits.
---
### Publish ports
`-p` / `--publish` forwards loopback traffic to the container. Spec: `[host-ip:]host-port:container-port[/protocol]` (`tcp`/`udp`, case-insensitive).
```bash
# host 8080 -> container 80
container run -d --rm -p 8080:80 docker.io/library/nginx:latest
# bind to a specific host IP
container run -d --rm -p 127.0.0.1:8080:8000 docker.io/library/node:latest npx http-server -a :: -p 8000
# IPv6 loopback (quote the bracketed address)
container run -d --rm -p '[::1]:8080:8000' docker.io/library/node:latest npx http-server -a :: -p 8000
# UDP
container run -d --rm -p 5353:5353/udp docker.io/library/alpine:latest
```
Note: if a container attaches to multiple networks, published ports forward to the IP of the first network's interface.
---
### Set environment variables
```bash
# Individual vars (-e / --env); repeatable. Bare `KEY` inherits from the host.
container run --rm -e NODE_ENV=production -e PORT=8080 docker.io/library/node:latest env
# Inherit HOME from the host shell
container run --rm -e HOME docker.io/library/alpine:latest sh -c 'echo $HOME'
# From a file (KEY=value per line; # comments and blanks ignored); repeatable.
container run --rm --env-file ./app.env docker.io/library/alpine:latest env
```
Note: `-e` and `--env-file` may be combined and each repeated; later values win.
---
### Mounts: bind, volume, tmpfs
```bash
# Bind-mount a host folder (-v host:container). Use absolute host paths.
container run --rm -v "${HOME}/Desktop/assets:/content/assets" docker.io/library/python:alpine ls -l /content/assets
# Same via --mount key=value syntax.
container run --rm --mount source="${HOME}/Desktop/assets",target=/content/assets docker.io/library/python:alpine ls /content/assets
# Named volume (create first, then mount by name).
container volume create data
container run --rm -v data:/var/lib/app docker.io/library/alpine:latest sh
# Anonymous volume (-v /path) — NOT auto-removed by --rm; delete it yourself.
container run --rm -v /data docker.io/library/alpine:latest sh
# It leaves an anon-<id> volume. List to find the exact name, then remove THAT one by name:
container volume list # locate the new anon-<id> row
container volume rm anon-<id> # ⚠️ delete the specific volume — do NOT `grep anon | rm`, which
# would match (and destroy) every anonymous volume on the machine
# Read-only bind via --mount.
container run --rm --mount type=bind,source="${PWD}/conf",target=/etc/conf,readonly docker.io/library/alpine:latest cat /etc/conf/app.ini
# tmpfs (in-memory) mount; repeatable.
container run --rm --tmpfs /scratch docker.io/library/alpine:latest sh -c 'df -h /scratch'
```
Note: unlike Docker, anonymous volumes do not auto-clean with `--rm` — remove them via `container volume rm`.
---
### Build an image from a Dockerfile
```bash
# Build from ./Dockerfile in the current context, tag as web-test.
container build -t web-test .
# Explicit Dockerfile path.
container build -f docker/Dockerfile.prod -t web-test:prod .
# Build, then run it.
container build -t web-test .
container run -d --name my-web-server --rm web-test
```
Note: with no `-f`, the builder looks for `Dockerfile` then `Containerfile`. The builder runs in its own VM (see resource-limits recipe to size it).
---
### Multi-tag, build-args, no-cache, target
```bash
# Multiple tags on one build (-t repeatable).
container build -t my-app:latest -t my-app:v1.0.0 .
# Build-time variables (repeatable).
container build --build-arg NODE_VERSION=18 --build-arg ENV=prod -t my-app .
# Skip the build cache.
container build --no-cache -t my-app .
# Target a specific multi-stage build stage.
container build --target production -t my-app:prod .
# Multi-architecture image (arm64 + amd64 via Rosetta).
container build --arch arm64 --arch amd64 -t docker.io/me/web-test:latest .
```
Note: `--arch` is repeatable/comma-separated; `--platform` (`os/arch[/variant]`) takes precedence over `--os`/`--arch`.
---
### Tag & push to Docker Hub / private registry
Registry commands live under the **Image** group (`container registry`, alias `r`). Credentials are stored in the macOS keychain.
```bash
# Log in (prompts for username + password, or use -u / --password-stdin).
container registry login docker.io
container registry login -u alice ghcr.io
echo "$TOKEN" | container registry login -u alice --password-stdin ghcr.io
# HTTP for a local registry.
container registry login --scheme http localhost:5000
# Tag the local image with a full registry reference.
container image tag web-test docker.io/alice/web-test:latest
# Push it (the final reference is printed on success).
container image push docker.io/alice/web-test:latest
# Private registry.
container image tag web-test registry.example.com/fido/web-test:latest
container image push registry.example.com/fido/web-test:latest
# List saved logins / log out.
container registry list # 1.0.0+ (added after 0.7.1)
container registry logout ghcr.io
```
Note: the default registry is `docker.io`, so a bare `web-test:latest` resolves against Docker Hub. Change it via the `registry.domain` property (next recipe).
---
### Set the default registry
```bash
# Inspect current properties (includes [registry] domain).
container system property list
```
Edit `~/.config/container/config.toml`:
```toml
[registry]
domain = "registry.example.com"
```
Note: with `registry.domain` set, unqualified image names resolve against that host instead of `docker.io`.
---
### Container-to-container networking
Each container gets its own IP on the `default` vmnet network. Read it from `container ls` or `container inspect`.
```bash
# Start a server, then find its IP.
container run -d --name my-web-server --rm web-test
container ls # IP column shows e.g. 192.168.64.3
# Scriptable IP lookup via inspect + jq.
container inspect my-web-server | jq -r '.[0].networks[0].address'
# Reach it from another container by IP (requires macOS 26 — see note).
container run --rm -it web-test curl http://192.168.64.3
```
Note: container-to-container access over the virtual network requires macOS 26 and **does not work on macOS 15**, where containers are isolated from one another at the network layer (see `concepts.md` §3) — a naming scheme cannot restore connectivity. The DNS domain in the next recipe resolves names **host-side only** (host → container); it does not enable container-to-container traffic on macOS 15.
---
### Local DNS domain for name resolution
Register a local domain so `<name>.<domain>` resolves to a named container's IP. `dns create`/`delete` need `sudo` (writes under `/etc/resolver`).
```bash
# Create the domain (admin password required).
sudo container system dns create test
```
Make it the default DNS domain by setting `dns.domain` in `~/.config/container/config.toml`
(there is no `property set` command — properties are edited in the config file):
```toml
[dns]
domain = "test"
```
```bash
# Now a named container is reachable as <name>.<domain>.
container run -d --name my-web-server --rm web-test
curl http://my-web-server.test
# List / remove domains.
container system dns list
sudo container system dns delete test
# Confirm the effective domain.
container system property list # shows [dns] domain = "test"
```
Note: `container system property` only supports `list`/`ls` — set `dns.domain` via `config.toml`, not a CLI setter. A container named `my-web-server` with domain `test` answers at `my-web-server.test`.
---
### Custom isolated networks (macOS 26)
The entire `container network` group **requires macOS 26** (absent on macOS 15, which has only the single default subnet).
```bash
# Create an isolated network.
container network create foo
# With custom subnets.
container network create foo --subnet 192.168.100.0/24 --subnet-v6 fd00:1234::/64
# Attach a container to it.
container run -d --name my-web-server --network foo --rm web-test
# List / delete (detach all containers first).
container network list
container stop my-web-server
container network delete foo
```
Note: networks are mutually isolated — a container on `foo` has no connectivity to containers on `default`.
---
### Inspect a container
```bash
# Full pretty JSON (one or more IDs).
container inspect my-web-server
# Extract specific fields with jq.
container inspect my-web-server | jq -r '.[0].status'
container inspect my-web-server | jq -r '.[0].networks[0].address'
# Table/JSON listing of all containers, including stopped.
container ls --all
container ls --all --format json | jq '.[] | [.configuration.id, .networks[0].address]'
```
Note: `inspect` requires at least one ID; a missing ID errors. `container image inspect <ref>` does the same for images.
---
### View logs
```bash
# Application stdio.
container logs my-web-server
# Follow live output.
container logs -f my-web-server
# Last N lines (-n is short-only; there is no --lines).
container logs -n 100 my-web-server
# VM boot / init logs.
container logs --boot my-web-server
```
Note: `--boot` shows the VM kernel + `vminitd` init log, useful for boot/networking diagnostics.
---
### Exec into a running container
```bash
# Interactive shell in a running container.
container exec -it my-web-server sh
# One-off command.
container exec my-web-server ls /content
# With env / as a specific user.
container exec -e DEBUG=1 -u root my-web-server env
```
Note: `exec` targets a **running** container and shares the same process options as `run` (`-e`, `--env-file`, `-u`, `-w`, etc.).
---
### Copy files in and out
Exactly one side must be a `container_id:path` reference. The container must be running.
```bash
# Host -> container.
container cp ./config.json my-web-server:/etc/app/
# Container -> host.
container cp my-web-server:/var/log/app.log ./logs/
```
Note: `container copy` and `container cp` are the same command.
---
### Resource limits (CPU / memory)
Container defaults: 4 CPUs, 1 GiB RAM. Builder VM defaults: 2 CPUs, 2 GiB RAM.
```bash
# Per-container limits on run/create.
container run --rm --cpus 8 --memory 32g docker.io/library/alpine:latest sh
# Short flags.
container run --rm -c 2 -m 1G docker.io/library/node:latest
# Size the builder VM before a heavy build.
container builder start --cpus 8 --memory 32g
container build -t big-app .
# Change a running builder: stop, delete, restart with new limits.
# ⚠️ `builder delete` discards the BuildKit builder and its layer cache — the next build
# re-fetches base images and rebuilds every layer from scratch.
container builder stop
container builder delete
container builder start --cpus 8 --memory 32g
```
Note: memory accepts `K`/`M`/`G`/`T`/`P` suffixes. Monitor live usage with `container stats` (`--no-stream` for a single snapshot).
---
### Cleanup: stop, remove, prune
> **⚠️ Scope matters.** The `-a`/`--all`/`prune` variants act on **every** container, image,
> volume, or network on the machine — not just this project's. `container volume prune` and
> `container image rm --all` permanently delete data belonging to *unrelated* containers. To clean
> up after one workload, use the **targeted** commands (by name/tag); reach for the machine-wide
> ones only when you deliberately want a full sweep. Do not paste this whole block blindly.
```bash
# --- Targeted (scoped to named resources — safe for cleaning up one workload) ---
container stop my-web-server # stop one container
container delete my-web-server # rm is an alias; add -f to remove a running one
container image delete web-test # remove one image by name/tag
container volume rm data # remove one volume by name
# --- Machine-wide (destroys ALL matching resources — use deliberately) ---
container stop -a # stop every running container
container rm --all # delete every container
container image rm --all # delete every image
container image prune # remove dangling (untagged) images only
container image prune -a # remove every image not used by a container
container volume prune # delete every volume with no container reference
container network prune # macOS 26+; delete every unused network
container prune # remove all stopped containers
# Check disk usage across images/containers/volumes.
container system df
```
Note: `container prune` only removes **stopped** containers. `image prune` (no `-a`) removes only dangling images.
---
### Upgrade / downgrade / uninstall
Both scripts install to `/usr/local/bin`. **Stop the services first.**
```bash
# Always stop before upgrading/downgrading.
container system stop
# Upgrade to the latest release.
/usr/local/bin/update-container.sh
# Downgrade: uninstall (keep user data with -k), then pin the previous release.
/usr/local/bin/uninstall-container.sh -k
/usr/local/bin/update-container.sh -v 0.7.1 # replace with the version you want
# Restart after any change.
container system start
# Uninstall. Default to -k (keep user data) unless you truly want everything gone.
/usr/local/bin/uninstall-container.sh -k # keep images/containers/volumes for a later reinstall
/usr/local/bin/uninstall-container.sh -d # ⚠️ also deletes ALL user data (images, containers, volumes) — irreversible
```
Note: you can also upgrade/downgrade by re-downloading and double-clicking the signed `.pkg`. `-v` pins `update-container.sh` to a specific version.
---
### Troubleshooting
```bash
# "XPC connection error" / commands hang -> services aren't running. Start them.
container system start
# Confirm services are up.
container system status
# View service logs (default last 5m; --last <n>[m|h|d], -f to follow).
container system logs
container system logs --last 1h
container system logs -f
# Add --debug to any command for verbose output (or set CONTAINER_DEBUG).
container --debug run --rm docker.io/library/alpine:latest true
# Version info for CLI + API server.
container system version
```
Note: an XPC/connection error means the background API server isn't started — run `container system start`. Feature gates to keep in mind: container-to-container access and the `container network` group require **macOS 26** (both unavailable on **macOS 15**). The CLI refuses to run under Rosetta — Apple silicon only.