📦 deps(thirdparty): update snapshots
This commit is contained in:
+165
@@ -0,0 +1,165 @@
|
||||
---
|
||||
name: apple-container
|
||||
description: "Build, run, and manage OCI/Linux containers as lightweight per-container VMs on Apple-silicon macOS using Apple's open-source container CLI, no Docker daemon required."
|
||||
category: devops
|
||||
risk: critical
|
||||
source: https://github.com/sanjay3290/ai-skills/tree/main/skills/apple-container
|
||||
source_repo: sanjay3290/ai-skills
|
||||
source_type: community
|
||||
date_added: "2026-07-09"
|
||||
author: sanjay3290
|
||||
tags: [macos, containers, oci, apple-silicon]
|
||||
tools: [claude, cursor, gemini]
|
||||
license: "Apache-2.0"
|
||||
license_source: "https://github.com/sanjay3290/ai-skills/blob/main/LICENSE"
|
||||
---
|
||||
|
||||
# Apple `container`
|
||||
|
||||
## When to Use
|
||||
|
||||
- Use when building, running, or managing OCI/Linux containers on Apple-silicon macOS with Apple's open-source `container` CLI
|
||||
- Use when you want lightweight per-container VMs instead of a Docker daemon
|
||||
- Use when translating Docker-style workflows (build, run, exec, logs, networking) to Apple's container tooling
|
||||
|
||||
Apple's `container` is an open-source CLI for building, running, and managing OCI/Linux
|
||||
containers on Apple-silicon Macs. Each container runs inside its own lightweight virtual
|
||||
machine (backed by the Containerization framework and the Virtualization API), so there is no
|
||||
shared daemon like Docker — services run per-user via `launchd`. Images are standard OCI
|
||||
artifacts, so they interoperate with Docker registries and other OCI tooling. The CLI is
|
||||
deliberately Docker-like (`container run`, `container build`, and image ops under
|
||||
`container image push`/`pull`), but it is a distinct tool: do not assume Docker command paths,
|
||||
flags, defaults, or daemon behavior carry over (e.g. there is no `container images`/`push`/`pull`
|
||||
top-level command — image verbs live under `container image`).
|
||||
|
||||
## Safety Gate
|
||||
|
||||
Container installation, service startup, image pulls, builds, runs, registry login, pushes,
|
||||
and resource cleanup change local or remote state. Explain the exact command, image registry,
|
||||
mounts, ports, privileges, and data-persistence impact, then obtain explicit user approval
|
||||
before executing it. Do not provide registry credentials, mount sensitive paths, or expose
|
||||
ports without the user's explicit instruction.
|
||||
|
||||
## Requirements
|
||||
|
||||
- **Apple silicon only** (M1 or later). Intel Macs are not supported.
|
||||
- **macOS 26 (Tahoe) is the officially supported target.** The maintainers do not support
|
||||
older macOS and typically will not fix issues that can't be reproduced on 26. The binary
|
||||
still runs on **macOS 15 (Sequoia)** but with reduced networking: only the single default
|
||||
subnet is available, and the `container network` group and `--network` flag error out.
|
||||
macOS-26-gated features are called out throughout the reference files.
|
||||
- **Version:** this skill documents the **1.0.0** release (the fullest feature set). The `machine`
|
||||
group, `container cp`, `container export`, `container prune`, `container image prune`,
|
||||
`container registry list`, and `container system version` were **added in 1.0.0** (not in 0.7.1)
|
||||
— features that postdate 0.7.1 are flagged *(1.0.0+)* in the reference files. Run `container --version` and
|
||||
`container <group> --help` to see what your installed build supports.
|
||||
- Install by downloading the signed `.pkg` installer from the project's GitHub releases
|
||||
(`apple/container`) and running it. See `references/concepts.md` for the full
|
||||
requirements/compatibility matrix and how the VM-per-container model works.
|
||||
|
||||
## Setup
|
||||
|
||||
Install the signed package, then start the background services once:
|
||||
|
||||
1. **Download** the latest signed installer `.pkg` from the
|
||||
[GitHub releases page](https://github.com/apple/container/releases).
|
||||
2. **Double-click** the downloaded package and follow the prompts, entering your admin
|
||||
password so it can place files under `/usr/local`. (There is no documented CLI `installer`
|
||||
invocation — installation is via the GUI package.)
|
||||
3. **Start the services** and confirm they are healthy:
|
||||
|
||||
```bash
|
||||
# Start the container services (container-apiserver + helpers via launchd). On first run it
|
||||
# offers to install the default Linux kernel — accept it, or start non-interactively with
|
||||
# `--disable-kernel-install` and add a kernel later via `container system kernel set`.
|
||||
container system start
|
||||
|
||||
# Verify services are healthy
|
||||
container system status
|
||||
```
|
||||
|
||||
`container system start` must have run before any container/image/build command works — a
|
||||
connection/XPC error almost always means the services are stopped, so run it again. Stop and
|
||||
deregister the `launchd` services with `container system stop` (which takes only `-p/--prefix`).
|
||||
The startup flags for `container system start` (`-a/--app-root`, `--install-root`, `--log-root`,
|
||||
`--enable-kernel-install`/`--disable-kernel-install`, `--timeout`) are in
|
||||
`references/configuration.md`.
|
||||
|
||||
**Upgrade / downgrade / uninstall** use helper scripts in `/usr/local/bin` (stop first with
|
||||
`container system stop`): `update-container.sh` (add `-v <version>` to pin a version), and
|
||||
`uninstall-container.sh -d` to remove user data or `-k` to keep it. Full recipes in
|
||||
`references/workflows.md`.
|
||||
|
||||
## Command groups at a glance
|
||||
|
||||
Invoke everything as `container <group> <subcommand>`. Container-lifecycle verbs (`run`,
|
||||
`create`, `start`, `stop`, `exec`, `logs`, `inspect`, `list`/`ls`, `delete`/`rm`, `kill`,
|
||||
`stats`) and `build` are top-level; image operations like `push`, `pull`, and `tag` live
|
||||
under `container image`. Run `container <group> --help` for exact flags, or read
|
||||
`references/commands.md` for the exhaustive matrix.
|
||||
|
||||
| Group | What it does | Example |
|
||||
|-------|--------------|---------|
|
||||
| container lifecycle | Create, start, run, stop, exec, inspect, list, remove containers | `container run --rm -it docker.io/library/alpine sh` |
|
||||
| build | Build an OCI image from a Dockerfile in the builder VM | `container build -t myapp:latest .` |
|
||||
| image | List, tag, inspect, remove, load/save, prune local images; push/pull to registries | `container image ls` |
|
||||
| registry | Authenticate (login/logout/list) to OCI registries | `container registry login ghcr.io` |
|
||||
| system | Start/stop/status services, logs, disk usage (`df`), DNS, kernel, properties | `container system status` |
|
||||
| network | Create/list/remove container networks (**macOS 26 only**) | `container network create mynet` |
|
||||
| volume | Create/list/inspect/remove persistent volumes | `container volume create data` |
|
||||
| builder | Manage the builder VM that runs `container build` (start/stop/status) | `container builder status` |
|
||||
| machine *(1.0.0+)* | Persistent Linux "machine" environments (added in 1.0.0) | `container machine --help` |
|
||||
|
||||
Exact subcommand names, aliases, arguments, and flags for each group live in
|
||||
`references/commands.md` — consult it before running an unfamiliar command rather than
|
||||
guessing Docker-equivalent syntax.
|
||||
|
||||
## Navigating this skill
|
||||
|
||||
Read the reference file that matches the task; do not guess flags or behavior.
|
||||
|
||||
- **`references/commands.md`** — exhaustive CLI reference: every command group, subcommand,
|
||||
alias, argument, and flag. Read this to construct any concrete `container ...` invocation,
|
||||
or to confirm a flag exists before using it.
|
||||
- **`references/concepts.md`** — architecture (VM-per-container, Containerization framework),
|
||||
system requirements and macOS 15 vs 26 differences, networking model, per-container IPs,
|
||||
security model, and a Docker-vs-`container` comparison. Read this to explain how or why
|
||||
something works, or when a Docker mental model gives the wrong answer.
|
||||
- **`references/configuration.md`** — the system service, `config.toml` / property model,
|
||||
default kernel, DNS domains, default registry, builder resources, and machine settings.
|
||||
Read this to change defaults, tune CPU/memory, point at a private registry, or manage the
|
||||
kernel.
|
||||
- **`references/workflows.md`** — copy-pasteable task recipes (run an image, build & push,
|
||||
wire up local DNS, mount a volume, expose ports) and troubleshooting for common failures.
|
||||
Read this first when the user wants to accomplish a concrete end-to-end task.
|
||||
|
||||
## Key rules
|
||||
|
||||
- **This is not Docker.** The CLI resembles Docker, but flags, defaults, and daemon behavior
|
||||
differ. Verify syntax in `references/commands.md` instead of assuming Docker equivalence.
|
||||
- **Always ensure services are up first.** Run `container system start` (and confirm with
|
||||
`container system status`) before any container/image/build command; connection errors
|
||||
usually mean the services are stopped.
|
||||
- **Images are standard OCI artifacts** and interoperate with Docker registries and other OCI
|
||||
tools. Image references that omit a registry default to `docker.io` (configurable via the
|
||||
`registry.domain` property — see `references/configuration.md`).
|
||||
- **Each container gets its own IP address** on its network (one lightweight VM per
|
||||
container). There is no shared Docker bridge; reach a container directly by its IP, or set
|
||||
up a local DNS domain (`container system dns create ...`, admin required) for name-based
|
||||
access.
|
||||
- **`container network` requires macOS 26.** On macOS 15 only the single default subnet is
|
||||
available and the network command group is unavailable — see `references/concepts.md`.
|
||||
- **Use fully-qualified image references** when precision matters (e.g.
|
||||
`docker.io/library/alpine` rather than bare `alpine`) to avoid ambiguity about the source
|
||||
registry.
|
||||
|
||||
## Limitations
|
||||
|
||||
- Apple Container requires Apple silicon and has materially different support and networking
|
||||
behavior across macOS releases; verify the installed CLI version before relying on a flag.
|
||||
- OCI images and registry content are third-party inputs. Inspect and trust the image source
|
||||
before pulling or running it.
|
||||
- This skill does not make container workloads safe by default: mounts, published ports,
|
||||
privileged settings, registry credentials, and cleanup can expose or destroy data.
|
||||
- Stop before uninstalling, pruning, deleting containers, volumes, or images, and require
|
||||
explicit approval for each destructive action.
|
||||
+1593
File diff suppressed because it is too large
Load Diff
+294
@@ -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.
|
||||
+499
@@ -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`.
|
||||
+498
@@ -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.
|
||||
Reference in New Issue
Block a user