
Apple Container
- 1 installs
- 5 repo stars
- Updated June 1, 2026
- schpet/toolbox
Uses Apple's native container CLI to run and build OCI-compatible Linux containers on macOS with Apple silicon instead of Docker.
About
Guides using the macOS container runtime for building and running OCI images on Apple silicon. A developer uses it as a Docker alternative when working on a Mac.
- Runs Linux containers as lightweight VMs on Apple silicon
- OCI-compatible images work with standard registries
Apple Container by the numbers
- 1 all-time installs (skills.sh)
- Ranked #1,173 of 1,435 DevOps & CI/CD skills by installs in the Skillselion catalog
- Data as of Aug 5, 2026 (Skillselion catalog sync)
npx skills add https://github.com/schpet/toolbox --skill apple-containerAdd your badge
Show developers this skill is listed on Skillselion. Paste this into your README.
| Installs | 1 |
|---|---|
| repo stars | ★ 5 |
| Last updated | June 1, 2026 |
| Repository | schpet/toolbox ↗ |
What it does
Uses Apple's native container CLI to run and build OCI-compatible Linux containers on macOS with Apple silicon instead of Docker.
Files
Apple Container
Overview
Apple Container is a native container platform for macOS that runs Linux containers as lightweight virtual machines. It should be used instead of Docker on macOS with Apple silicon.
The container CLI is installed and available. It produces and consumes OCI-compatible container images, so images work with any standard container registry.
Requirements
- Mac with Apple silicon
- macOS 26 or later
Quick Start
# Start the system service (required once)
container system start
# Run a container
container run -it ubuntu:latest /bin/bash
# Build an image
container build -t myimage .
# List containers
container list
# Stop a container
container stop <container-id>Common Commands
| Command | Description |
|---|---|
container run | Run a container |
container build | Build an image from Dockerfile |
container list | List containers |
container stop | Stop running containers |
container exec | Run command in running container |
container logs | Fetch container logs |
container image list | List images |
container system start | Start the system service |
container system stop | Stop the system service |
Docker Compatibility
The container CLI uses familiar Docker-like syntax:
| Docker Command | Container Command |
|---|---|
docker run | container run |
docker build | container build |
docker ps | container list |
docker stop | container stop |
docker exec | container exec |
docker logs | container logs |
docker images | container image list |
Troubleshooting
Builder Freezes
The buildkit builder can freeze, often due to insufficient memory. To fix:
1. Find and kill the frozen builder process:
ps aux | grep buildkit
kill -9 <pid>2. Restart with more resources:
container builder start --cpus 6 --memory 8gReferences
- Tutorial - Guided tour building a simple web server
- How-To Guide - Feature-specific guides
- Technical Overview - Architecture and internals
- Command Reference - Full CLI documentation
Container CLI Command Reference
[!IMPORTANT]
This file contains documentation for the CURRENT BRANCH. To find documentation for official releases, find the target release on the Release Page and click the tag corresponding to your release version.
>
Example: release 0.4.1 tag
Note: Command availability may vary depending on host operating system and macOS version.
Core Commands
container run
Runs a container from an image. If a command is provided, it will execute inside the container; otherwise the image's default command runs. By default the container runs in the foreground and stdin remains closed unless -i/--interactive is specified.
Usage
container run [<options>] <image> [<arguments> ...]Arguments
-
<image>: Image name -
<arguments>: Container init process arguments
Process Options
-
-e, --env <env>: Set environment variables (format: key=value) -
--env-file <env-file>: Read in a file of environment variables (key=value format, ignores # comments and blank lines) -
--gid <gid>: Set the group ID for the process -
-i, --interactive: Keep the standard input open even if not attached -
-t, --tty: Open a TTY with the process -
-u, --user <user>: Set the user for the process (format: name|uid[:gid]) -
--uid <uid>: Set the user ID for the process -
-w, --workdir, --cwd <dir>: Set the initial working directory inside the container
Resource Options
-
-c, --cpus <cpus>: Number of CPUs to allocate to the container -
-m, --memory <memory>: Amount of memory (1MiByte granularity), with optional K, M, G, T, or P suffix
Management Options
-
-a, --arch <arch>: Set arch if image can target multiple architectures (default: arm64) -
--cidfile <cidfile>: Write the container ID to the path provided -
-d, --detach: Run the container and detach from the process -
--dns <ip>: DNS nameserver IP address -
--dns-domain <domain>: Default DNS domain -
--dns-option <option>: DNS options -
--dns-search <domain>: DNS search domains -
--entrypoint <cmd>: Override the entrypoint of the image -
-k, --kernel <path>: Set a custom kernel path -
-l, --label <label>: Add a key=value label to the container -
--mount <mount>: Add a mount to the container (format: type=<>,source=<>,target=<>,readonly) -
--name <name>: Use the specified name as the container ID -
--network <network>: Attach the container to a network -
--no-dns: Do not configure DNS in the container -
--os <os>: Set OS if image can target multiple operating systems (default: linux) -
-p, --publish <spec>: Publish a port from container to host (format: [host-ip:]host-port:container-port[/protocol]) -
--platform <platform>: Platform for the image if it's multi-platform. This takes precedence over --os and --arch -
--publish-socket <spec>: Publish a socket from container to host (format: host_path:container_path) -
--rm, --remove: Remove the container after it stops -
--ssh: Forward SSH agent socket to container -
--tmpfs <tmpfs>: Add a tmpfs mount to the container at the given path -
-v, --volume <volume>: Bind mount a volume into the container -
--virtualization: Expose virtualization capabilities to the container (requires host and guest support)
Registry Options
-
--scheme <scheme>: Scheme to use when connecting to the container registry. One of (http, https, auto) (default: auto)
- Behavior of `auto`
When auto is selected, the target registry is considered internal/local if the registry host matches any of these criteria:
- The host is a loopback address (e.g.,
localhost,127.*) - The host is within the
RFC1918private IP ranges: 10.*.*.*192.168.*.*172.16.*.*through172.31.*.*- The host ends with the machine's default container DNS domain (as defined in
DefaultsStore.Keys.defaultDNSDomain, located here)
For internal/local registries, the client uses HTTP. Otherwise, it uses HTTPS.
Progress Options
-
--progress <type>: Progress type (format: none|ansi) (default: ansi)
Examples
# run a container and attach an interactive shell
container run -it ubuntu:latest /bin/bash
# run a background web server
container run -d --name web -p 8080:80 nginx:latest
# set environment variables and limit resources
container run -e NODE_ENV=production --cpus 2 --memory 1G node:18
# run a container with a specific MAC address
container run --network default,mac=02:42:ac:11:00:02 ubuntu:latestcontainer build
Builds an OCI image from a local build context. It reads a Dockerfile (default Dockerfile) or Containerfile and produces an image tagged with -t option. The build runs in isolation using BuildKit, and resource limits may be set for the build process itself.
When no -f/--file is specified, the build command will look for Dockerfile first, then fall back to Containerfile if Dockerfile is not found.
Usage
container build [<options>] [<context-dir>]Arguments
-
<context-dir>: Build directory (default: .)
Options
-
-a, --arch <value>: Add the architecture type to the build -
--build-arg <key=val>: Set build-time variables -
-c, --cpus <cpus>: Number of CPUs to allocate to the builder container (default: 2) -
-f, --file <path>: Path to Dockerfile -
-l, --label <key=val>: Set a label -
-m, --memory <memory>: Amount of builder container memory (1MiByte granularity), with optional K, M, G, T, or P suffix (default: 2048MB) -
--no-cache: Do not use cache -
-o, --output <value>: Output configuration for the build (format: type=<oci|tar|local>[,dest=]) (default: type=oci) -
--os <value>: Add the OS type to the build -
--platform <platform>: Add the platform to the build (format: os/arch[/variant], takes precedence over --os and --arch) -
--progress <type>: Progress type (format: auto|plain|tty) (default: auto) -
-q, --quiet: Suppress build output -
-t, --tag <name>: Name for the built image (can be specified multiple times) -
--target <stage>: Set the target build stage -
--vsock-port <port>: Builder shim vsock port (default: 8088)
Examples
# build an image and tag it as my-app:latest
container build -t my-app:latest .
# use a custom Dockerfile
container build -f docker/Dockerfile.prod -t my-app:prod .
# pass build args
container build --build-arg NODE_VERSION=18 -t my-app .
# build the production stage only and disable cache
container build --target production --no-cache -t my-app:prod .
# build with multiple tags
container build -t my-app:latest -t my-app:v1.0.0 -t my-app:stable .Container Management
container create
Creates a container from an image without starting it. This command accepts most of the same process/resource/management flags as container run, but leaves the container stopped after creation.
Usage
container create [<options>] <image> [<arguments> ...]Arguments
-
<image>: Image name -
<arguments>: Container init process arguments
Process Options
-
-e, --env <env>: Set environment variables (format: key=value) -
--env-file <env-file>: Read in a file of environment variables (key=value format, ignores # comments and blank lines) -
--gid <gid>: Set the group ID for the process -
-i, --interactive: Keep the standard input open even if not attached -
-t, --tty: Open a TTY with the process -
-u, --user <user>: Set the user for the process (format: name|uid[:gid]) -
--uid <uid>: Set the user ID for the process -
-w, --workdir, --cwd <dir>: Set the initial working directory inside the container
Resource Options
-
-c, --cpus <cpus>: Number of CPUs to allocate to the container -
-m, --memory <memory>: Amount of memory (1MiByte granularity), with optional K, M, G, T, or P suffix
Management Options
-
-a, --arch <arch>: Set arch if image can target multiple architectures (default: arm64) -
--cidfile <cidfile>: Write the container ID to the path provided -
-d, --detach: Run the container and detach from the process -
--dns <ip>: DNS nameserver IP address -
--dns-domain <domain>: Default DNS domain -
--dns-option <option>: DNS options -
--dns-search <domain>: DNS search domains -
--entrypoint <cmd>: Override the entrypoint of the image -
-k, --kernel <path>: Set a custom kernel path -
-l, --label <label>: Add a key=value label to the container -
--mount <mount>: Add a mount to the container (format: type=<>,source=<>,target=<>,readonly) -
--name <name>: Use the specified name as the container ID -
--network <network>: Attach the container to a network -
--no-dns: Do not configure DNS in the container -
--os <os>: Set OS if image can target multiple operating systems (default: linux) -
-p, --publish <spec>: Publish a port from container to host (format: [host-ip:]host-port:container-port[/protocol]) -
--platform <platform>: Platform for the image if it's multi-platform. This takes precedence over --os and --arch -
--publish-socket <spec>: Publish a socket from container to host (format: host_path:container_path) -
--rm, --remove: Remove the container after it stops -
--ssh: Forward SSH agent socket to container -
--tmpfs <tmpfs>: Add a tmpfs mount to the container at the given path -
-v, --volume <volume>: Bind mount a volume into the container -
--virtualization: Expose virtualization capabilities to the container (requires host and guest support)
Registry Options
-
--scheme <scheme>: Scheme to use when connecting to the container registry. One of (http, https, auto) (default: auto)
container start
Starts a stopped container. You can attach to the container's output streams and optionally keep STDIN open.
Usage
container start [--attach] [--interactive] [--debug] <container-id>Arguments
-
<container-id>: Container ID
Options
-
-a, --attach: Attach stdout/stderr -
-i, --interactive: Attach stdin
container stop
Stops running containers gracefully by sending a signal. A timeout can be specified before a SIGKILL is issued. If no containers are specified, nothing is stopped unless --all is used.
Usage
container stop [--all] [--signal <signal>] [--time <time>] [--debug] [<container-ids> ...]Arguments
-
<container-ids>: Container IDs
Options
-
-a, --all: Stop all running containers -
-s, --signal <signal>: Signal to send to the containers (default: SIGTERM) -
-t, --time <time>: Seconds to wait before killing the containers (default: 5)
container kill
Immediately kills running containers by sending a signal (defaults to KILL). Use with caution: it does not allow for graceful shutdown.
Usage
container kill [--all] [--signal <signal>] [--debug] [<container-ids> ...]Arguments
-
<container-ids>: Container IDs
Options
-
-a, --all: Kill or signal all running containers -
-s, --signal <signal>: Signal to send to the container(s) (default: KILL)
container delete (rm)
Deletes one or more containers. If the container is running, you may force deletion with --force. Without a container ID, nothing happens unless --all is supplied.
Usage
container delete [--all] [--force] [--debug] [<container-ids> ...]Arguments
-
<container-ids>: Container IDs
Options
-
-a, --all: Delete all containers -
-f, --force: Delete containers even if they are running
container list (ls)
Lists containers. By default only running containers are shown. Output can be formatted as a table or JSON.
Usage
container list [--all] [--format <format>] [--quiet] [--debug]Options
-
-a, --all: Include containers that are not running -
--format <format>: Format of the output (values: json, table; default: table) -
-q, --quiet: Only output the container ID
container exec
Executes a command inside a running container. It uses the same process flags as container run to control environment, user, and TTY settings.
Usage
container exec [--detach] [--env <env> ...] [--env-file <env-file> ...] [--gid <gid>] [--interactive] [--tty] [--user <user>] [--uid <uid>] [--workdir <dir>] [--debug] <container-id> <arguments> ...Arguments
-
<container-id>: Container ID -
<arguments>: New process arguments
Options
-
-d, --detach: Run the process and detach from it
Process Options
-
-e, --env <env>: Set environment variables (format: key=value) -
--env-file <env-file>: Read in a file of environment variables (key=value format, ignores # comments and blank lines) -
--gid <gid>: Set the group ID for the process -
-i, --interactive: Keep the standard input open even if not attached -
-t, --tty: Open a TTY with the process -
-u, --user <user>: Set the user for the process (format: name|uid[:gid]) -
--uid <uid>: Set the user ID for the process -
-w, --workdir, --cwd <dir>: Set the initial working directory inside the container
container logs
Fetches logs from a container. You can follow the logs (-f/--follow), restrict the number of lines shown, or view boot logs.
Usage
container logs [--boot] [--follow] [-n <n>] [--debug] <container-id>Arguments
-
<container-id>: Container ID
Options
-
--boot: Display the boot log for the container instead of stdio -
-f, --follow: Follow log output -
-n <n>: Number of lines to show from the end of the logs. If not provided this will print all of the logs
container inspect
Displays detailed container information in JSON. Pass one or more container IDs to inspect multiple containers.
Usage
container inspect [--debug] <container-ids> ...Arguments
-
<container-ids>: Container IDs
Options
No options.
container stats
Displays real-time resource usage statistics for containers. Shows CPU percentage, memory usage, network I/O, block I/O, and process count. By default, continuously updates statistics in an interactive display (like top). Use --no-stream for a single snapshot.
Usage
container stats [--format <format>] [--no-stream] [--debug] [<container-ids> ...]Arguments
-
<container-ids>: Container IDs or names (optional, shows all running containers if not specified)
Options
-
--format <format>: Format of the output (values: json, table; default: table) -
--no-stream: Disable streaming stats and only pull the first result
Examples
# show stats for all running containers (interactive)
container stats
# show stats for specific containers
container stats web db cache
# get a single snapshot of stats (non-interactive)
container stats --no-stream web
# output stats as JSON
container stats --format json --no-stream webImage Management
container image list (ls)
Lists local images. Verbose output provides additional details such as image ID, creation time and size; JSON output provides the same data in machine-readable form.
Usage
container image list [--format <format>] [--quiet] [--verbose] [--debug]Options
-
--format <format>: Format of the output (values: json, table; default: table) -
-q, --quiet: Only output the image name -
-v, --verbose: Verbose output
container image pull
Pulls an image from a registry. Supports specifying a platform and controlling progress display.
Usage
container image pull [--debug] [--scheme <scheme>] [--progress <type>] [--arch <arch>] [--os <os>] [--platform <platform>] <reference>Arguments
-
<reference>: Image reference to pull
Options
-
--scheme <scheme>: Scheme to use when connecting to the container registry. One of (http, https, auto) (default: auto) -
--progress <type>: Progress type (format: none|ansi) (default: ansi) -
-a, --arch <arch>: Limit the pull to the specified architecture -
--os <os>: Limit the pull to the specified OS -
--platform <platform>: Limit the pull to the specified platform (format: os/arch[/variant], takes precedence over --os and --arch)
container image push
Pushes an image to a registry. The flags mirror those for image pull with the addition of specifying a platform for multi-platform images.
Usage
container image push [--scheme <scheme>] [--progress <type>] [--arch <arch>] [--os <os>] [--platform <platform>] [--debug] <reference>Arguments
-
<reference>: Image reference to push
Options
-
--scheme <scheme>: Scheme to use when connecting to the container registry. One of (http, https, auto) (default: auto) -
--progress <type>: Progress type (format: none|ansi) (default: ansi) -
-a, --arch <arch>: Limit the push to the specified architecture -
--os <os>: Limit the push to the specified OS -
--platform <platform>: Limit the push to the specified platform (format: os/arch[/variant], takes precedence over --os and --arch)
container image save
Saves an image to a tar archive on disk. Useful for exporting images for offline transport.
Usage
container image save [--arch <arch>] [--os <os>] --output <output> [--platform <platform>] [--debug] <references> ...Arguments
-
<references>: Image references to save
Options
-
-a, --arch <arch>: Architecture for the saved image -
--os <os>: OS for the saved image -
-o, --output <output>: Pathname for the saved image -
--platform <platform>: Platform for the saved image (format: os/arch[/variant], takes precedence over --os and --arch)
container image load
Loads images from a tar archive created by image save. The tar file must be specified via --input.
Usage
container image load --input <input> [--debug]Options
-
-i, --input <input>: Path to the image tar archive
container image tag
Applies a new tag to an existing image. The original image reference remains unchanged.
Usage
container image tag <source> <target> [--debug]Arguments
-
<source>: The existing image reference (format: image-name[:tag]) -
<target>: The new image reference
Options
No options.
container image delete (rm)
Deletes one or more images. If no images are provided, --all can be used to delete all images. Images currently referenced by running containers cannot be deleted without first removing those containers.
Usage
container image delete [--all] [--debug] [<images> ...]Arguments
-
<images>: Image names or IDs
Options
-
-a, --all: Delete all images
container image prune
Removes unused images to reclaim disk space. By default, only removes dangling images (images with no tags). Use -a to remove all images not referenced by any container.
Usage
container image prune [--all] [--debug]Options
-
-a, --all: Remove all unused images, not just dangling ones
container image inspect
Shows detailed information for one or more images in JSON format. Accepts image names or IDs.
Usage
container image inspect [--debug] <images> ...Arguments
-
<images>: Images to inspect
Options
No options.
Builder Management
The builder commands manage the BuildKit-based builder used for image builds.
container builder start
Starts the BuildKit builder container. CPU and memory limits can be set for the builder.
Usage
container builder start [--cpus <cpus>] [--memory <memory>] [--debug]Options
-
-c, --cpus <cpus>: Number of CPUs to allocate to the builder container (default: 2) -
-m, --memory <memory>: Amount of builder container memory (1MiByte granularity), with optional K, M, G, T, or P suffix (default: 2048MB)
container builder status
Shows the current status of the BuildKit builder. Without flags a human-readable table is displayed; with --format json the status is returned as JSON.
Usage
container builder status [--format <format>] [--quiet] [--debug]Options
-
--format <format>: Format of the output (values: json, table; default: table) -
-q, --quiet: Only output the container ID
container builder stop
Stops the BuildKit builder container.
Usage
container builder stop [--debug]Options
No options.
container builder delete (rm)
Deletes the BuildKit builder container. It can optionally force deletion if the builder is still running.
Usage
container builder delete [--force] [--debug]Options
-
-f, --force: Delete the builder even if it is running
Network Management (macOS 26+)
The network commands are available on macOS 26 and later and allow creation and management of user-defined container networks.
container network create
Creates a new network with the given name.
Usage
container network create [--label <label> ...] [--subnet <subnet>] [--subnet-v6 <subnet-v6>] [--debug] <name>Arguments
-
<name>: Network name
Options
-
--label <label>: Set metadata for a network -
--subnet <subnet>: Set the IPv4 subnet for a network (CIDR format, e.g., 192.168.100.0/24) -
--subnet-v6 <subnet-v6>: Set the IPv6 prefix for a network (CIDR format, e.g., fd00:1234::/64)
container network delete (rm)
Deletes one or more networks. When deleting multiple networks, pass them as separate arguments. To delete all networks, use --all.
Usage
container network delete [--all] [--debug] [<network-names> ...]Arguments
-
<network-names>: Network names
Options
-
-a, --all: Delete all networks
container network prune
Removes networks not connected to any containers. However, default and system networks are preserved.
Usage
container network prune [--debug]Options
No options.
container network list (ls)
Lists user-defined networks.
Usage
container network list [--format <format>] [--quiet] [--debug]Options
-
--format <format>: Format of the output (values: json, table; default: table) -
-q, --quiet: Only output the network name
container network inspect
Shows detailed information about one or more networks.
Usage
container network inspect <networks> ... [--debug]Arguments
-
<networks>: Networks to inspect
Options
No options.
Volume Management
Manage persistent volumes for containers. Volumes can be explicitly created with volume create or implicitly created when referenced in container commands (e.g., -v myvolume:/path or -v /path for anonymous volumes).
container volume create
Creates a new named volume with an optional size and driver-specific options.
Usage
container volume create [--label <label> ...] [--opt <opt> ...] [-s <s>] [--debug] <name>Arguments
-
<name>: Volume name
Options
-
--label <label>: Set metadata for a volume -
--opt <opt>: Set driver specific options -
-s <s>: Size of the volume in bytes, with optional K, M, G, T, or P suffix
Anonymous Volumes
Anonymous volumes are auto-created when using -v /path or --mount type=volume,dst=/path without specifying a source. They use UUID-based naming (anon-{36-char-uuid}):
# Creates anonymous volume
container run -v /data alpine
# Reuse anonymous volume by ID
VOL=$(container volume list -q | grep anon)
container run -v $VOL:/data alpine
# Manual cleanup
container volume rm $VOLNote: Unlike Docker, anonymous volumes do NOT auto-cleanup with --rm. Manual deletion is required.
container volume delete (rm)
Deletes one or more volumes by name. Volumes that are currently in use by containers (running or stopped) cannot be deleted.
Usage
container volume delete [--all] [--debug] [<names> ...]Arguments
-
<names>: Volume names
Options
-
-a, --all: Delete all volumes
Examples
# delete a specific volume
container volume delete myvolume
# delete multiple volumes
container volume delete vol1 vol2 vol3
# delete all unused volumes
container volume delete --allcontainer volume prune
Removes all volumes that have no container references. This includes volumes that are not attached to any running or stopped containers. The command reports the actual disk space reclaimed after deletion.
Usage
container volume prune [--debug]Options
No options.
container volume list (ls)
Lists volumes.
Usage
container volume list [--format <format>] [--quiet] [--debug]Options
-
--format <format>: Format of the output (values: json, table; default: table) -
-q, --quiet: Only output the volume name
container volume inspect
Displays detailed information for one or more volumes in JSON.
Usage
container volume inspect [--debug] <names> ...Arguments
-
<names>: Volume names
Options
No options.
Registry Management
The registry commands manage authentication and defaults for container registries.
container registry login
Authenticates with a registry. Credentials can be provided interactively or via flags. The login is stored for reuse by subsequent commands.
Usage
container registry login [--scheme <scheme>] [--password-stdin] [--username <username>] [--debug] <server>Arguments
-
<server>: Registry server name
Options
-
--scheme <scheme>: Scheme to use when connecting to the container registry. One of (http, https, auto) (default: auto) -
--password-stdin: Take the password from stdin -
-u, --username <username>: Registry user name
container registry logout
Logs out of a registry, removing stored credentials.
Usage
container registry logout [--debug] <registry>Arguments
-
<registry>: Registry server name
Options
No options.
System Management
System commands manage the container apiserver, logs, DNS settings and kernel. These are only available on macOS hosts.
container system start
Starts the container services and (optionally) installs a default kernel. It will start the container-apiserver and background services.
Usage
container system start [--app-root <app-root>] [--install-root <install-root>] [--enable-kernel-install] [--disable-kernel-install] [--debug]Options
-
-a, --app-root <app-root>: Path to the root directory for application data -
--install-root <install-root>: Path to the root directory for application executables and plugins -
--enable-kernel-install/--disable-kernel-install: Specify whether the default kernel should be installed or not (default: prompt user)
container system stop
Stops the container services and deregisters them from launchd. You can specify a prefix to target services created with a different launchd prefix.
Usage
container system stop [--prefix <prefix>] [--debug]Options
-
-p, --prefix <prefix>: Launchd prefix for services (default: com.apple.container.)
container system status
Checks whether the container services are running and prints status information. It will ping the apiserver and report readiness.
Usage
container system status [--prefix <prefix>] [--debug]Options
-
-p, --prefix <prefix>: Launchd prefix for services (default: com.apple.container.)
container system version
Shows version information for the CLI and, if available, the API server. The table format is consistent with other list outputs and includes a header. If the API server responds to a health check, a second row for the server is added.
Usage
container system version [--format <format>]Options
-
--format <format>: Output format (values: json, table; default: table)
Table Output
Columns: COMPONENT, VERSION, BUILD, COMMIT.
Example:
container system versionCOMPONENT VERSION BUILD COMMIT
CLI 1.2.3 debug abcdef1
API Server container-apiserver 1.2.3 release 1234abcJSON Output
Backward-compatible with previous CLI-only output. Top-level fields describe the CLI. When available, a server object is included with the same fields.
{
"version": "1.2.3",
"buildType": "debug",
"commit": "abcdef1",
"appName": "container CLI",
"server": {
"version": "container-apiserver 1.2.3",
"buildType": "release",
"commit": "1234abc",
"appName": "container API Server"
}
}container system logs
Displays logs from the container services. You can specify a time interval or follow new logs in real time.
Usage
container system logs [--follow] [--last <last>] [--debug]Options
-
-f, --follow: Follow log output -
--last <last>: Fetch logs starting from the specified time period (minus the current time); supported formats: m, h, d (default: 5m)
container system df
Shows disk usage for images, containers, and volumes. Displays total count, active count, size, and reclaimable space for each resource type.
Usage
container system df [--format <format>] [--debug]Options
-
--format <format>: Format of the output (values: json, table; default: table)
container system dns create
Creates a local DNS domain for containers. Requires administrator privileges (use sudo).
Usage
container system dns create [--debug] <domain-name>Arguments
-
<domain-name>: The local domain name
Options
No options.
container system dns delete (rm)
Deletes a local DNS domain. Requires administrator privileges (use sudo).
Usage
container system dns delete [--debug] <domain-name>Arguments
-
<domain-name>: The local domain name
Options
No options.
container system dns list (ls)
Lists configured local DNS domains for containers.
Usage
container system dns list [--debug]Options
No options.
container system kernel set
Installs or updates the Linux kernel used by the container runtime on macOS hosts.
Usage
container system kernel set [--arch <arch>] [--binary <binary>] [--force] [--recommended] [--tar <tar>] [--debug]Options
-
--arch <arch>: The architecture of the kernel binary (values: amd64, arm64) (default: arm64) -
--binary <binary>: Path to the kernel file (or archive member, if used with --tar) -
--force: Overwrites an existing kernel with the same name -
--recommended: Download and install the recommended kernel as the default (takes precedence over all other flags) -
--tar <tar>: Filesystem path or remote URL to a tar archive containing a kernel file
container system property list (ls)
Lists all available system properties with their current values, types, and descriptions. Output can be formatted as a table or JSON.
Usage
container system property list [--format <format>] [--quiet] [--debug]Options
-
--format <format>: Format of the output (values: json, table; default: table) -
-q, --quiet: Only output the property ID
Examples
# list all properties in table format
container system property list
# get only property IDs
container system property list --quiet
# output as JSON for scripting
container system property list --format jsoncontainer system property get
Retrieves the current value of a specific system property by its ID.
Usage
container system property get [--debug] <id>Arguments
-
<id>: The property ID
Options
No options.
Examples
# get the default registry domain
container system property get registry.domain
# get the current DNS domain setting
container system property get dns.domaincontainer system property set
Sets the value of a system property. The command validates the value based on the property type (boolean, domain name, image reference, URL, or CIDR address).
Usage
container system property set [--debug] <id> <value>Arguments
-
<id>: The property ID -
<value>: The property value
Options
No options.
Examples
# enable Rosetta for AMD64 builds on ARM64
container system property set build.rosetta true
# set a custom DNS domain
container system property set dns.domain mycompany.local
# configure a custom registry
container system property set registry.domain registry.example.com
# set a custom builder image
container system property set image.builder myregistry.com/custom-builder:latestcontainer system property clear
Clears (unsets) a system property, reverting it to its default value.
Usage
container system property clear [--debug] <id>Arguments
-
<id>: The property ID
Options
No options.
Examples
# clear custom DNS domain (revert to default)
container system property clear dns.domain
# clear custom registry setting
container system property clear registry.domain
How-to
[!IMPORTANT]
This file contains documentation for the CURRENT BRANCH. To find documentation for official releases, find the target release on the Release Page and click the tag corresponding to your release version.
>
Example: release 0.4.1 tag
How to use the features of container.
Configure memory and CPUs for your containers
Since the containers created by container are lightweight virtual machines, consider the needs of your containerized application when you use container run. The --memory and --cpus options allow you to override the default memory and CPU limits for the virtual machine. The default values are 1 gigabyte of RAM and 4 CPUs. You can use abbreviations for memory units; for example, to run a container for image big with 8 CPUs and 32 GiBytes of memory, use:
container run --rm --cpus 8 --memory 32g bigConfigure memory and CPUs for large builds
When you first run container build, container starts a builder, which is a utility container that builds images from your Dockerfiles. As with anything you run with container run, the builder runs in a lightweight virtual machine, so for resource-intensive builds, you may need to increase the memory and CPU limits for the builder VM.
By default, the builder VM receives 2 GiBytes of RAM and 2 CPUs. You can change these limits by starting the builder container before running container build:
container builder start --cpus 8 --memory 32gIf your builder is already running and you need to modify the limits, just stop, delete, and restart the builder:
container builder stop
container builder delete
container builder start --cpus 8 --memory 32gShare host files with your container
With the --volume option of container run, you can share data between the host system and one or more containers, and you can persist data across multiple container runs. The volume option allows you to mount a folder on your host to a filesystem path in the container.
This example mounts a folder named assets on your Desktop to the directory /content/assets in a container:
<pre> % ls -l ~/Desktop/assets total 8 -rw-r--r--@ 1 fido staff 2410 May 13 18:36 link.svg % container run --volume ${HOME}/Desktop/assets:/content/assets docker.io/python:alpine ls -l /content/assets total 4 -rw-r--r-- 1 root root 2410 May 14 01:36 link.svg % </pre>
The argument to --volume in the example consists of the full pathname for the host folder and the full pathname for the mount point in the container, separated by a colon.
The --mount option uses a comma-separated key=value syntax to achieve the same result:
<pre> % container run --mount source=${HOME}/Desktop/assets,target=/content/assets docker.io/python:alpine ls -l /content/assets total 4 -rw-r--r-- 1 root root 2410 May 14 01:36 link.svg % </pre>
Build and run a multiplatform image
Using the project from the tutorial example, you can create an image to use both on Apple silicon Macs and on x86-64 servers.
When building the image, just add --arch options that direct the builder to create an image supporting both the arm64 and amd64 architectures:
container build --arch arm64 --arch amd64 --tag registry.example.com/fido/web-test:latest --file Dockerfile .Try running the command uname -a with the arm64 variant of the image to see the system information that the virtual machine reports:
<pre> % container run --arch arm64 --rm registry.example.com/fido/web-test:latest uname -a Linux 7932ce5f-ec10-4fbe-a2dc-f29129a86b64 6.1.68 #1 SMP Mon Mar 31 18:27:51 UTC 2025 aarch64 GNU/Linux % </pre>
When you run the command with the amd64 architecture, the x86-64 version of uname runs under Rosetta translation, so that you will see information for an x86-64 system:
<pre> % container run --arch amd64 --rm registry.example.com/fido/web-test:latest uname -a Linux c0376e0a-0bfd-4eea-9e9e-9f9a2c327051 6.1.68 #1 SMP Mon Mar 31 18:27:51 UTC 2025 x86_64 GNU/Linux % </pre>
The command to push your multiplatform image to a registry is no different than that for a single-platform image:
container image push registry.example.com/fido/web-test:latestGet container or image details
container image list and container list provide basic information for all of your images and containers. You can also use list and inspect commands to print detailed JSON output for one or more resources.
Use the inspect command and send the result to the jq command to get pretty-printed JSON for the images or containers that you specify:
<pre> % container image inspect web-test | jq [ { "name": "web-test:latest", "variants": [ { "platform": { "os": "linux", "architecture": "arm64" }, "config": { "created": "2025-05-08T22:27:23Z", "architecture": "arm64", ... % container inspect my-web-server | jq [ { "status": "running", "networks": [ { "address": "192.168.64.3/24", "gateway": "192.168.64.1", "hostname": "my-web-server.test.", "network": "default" } ], "configuration": { "mounts": [], "hostname": "my-web-server", "id": "my-web-server", "resources": { "cpus": 4, "memoryInBytes": 1073741824, }, ... </pre>
Use the list command with the --format option to display information for all images or containers. In this example, the --all option shows stopped as well as running containers, and jq selects the IP address for each running container:
<pre> % container ls --format json --all | jq '.[] | select ( .status == "running" ) | [ .configuration.id, .networks[0].address ]' [ "my-web-server", "192.168.64.3/24" ] [ "buildkit", "192.168.64.2/24" ] </pre>
Forward traffic from localhost to your container
Use the --publish option to forward TCP or UDP traffic from your loopback IP to the container you run. The option value has the form [host-ip:]host-port:container-port[/protocol], where protocol may be tcp or udp, case insensitive.
If your container attaches to multiple networks, the ports you publish forward to the IP address of the interface attached to the first network.
To forward requests from port 8080 on the IPv4 loopback IP to a NodeJS webserver on container port 8000, run:
container run -d --rm -p 127.0.0.1:8080:8000 node:latest npx http-server -a :: -p 8000Test access using curl:
% curl http://127.0.0.1:8080
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Index of /</title>
...
<br><address>Node.js v25.2.1/ <a href="https://github.com/http-party/http-server">http-server</a> server running @ 127.0.0.1:8080</address>
</body></html>To forward requests from port 8080 on the IPv6 loopback IP to a NodeJS webserver on container port 8000, run:
container run -d --rm -p '[::1]:8080:8000' node:latest npx http-server -a :: -p 8000Test access using curl:
% curl -6 'http://[::1]:8080'
<!doctype html>
<html>
<head>
<meta charset="utf-8">
<meta name="viewport" content="width=device-width">
<title>Index of /</title>
...
<br><address>Node.js v25.2.1/ <a href="https://github.com/http-party/http-server">http-server</a> server running @ [::1]:8080</address>
</body></html>Set a custom MAC address for your container
Use the mac option to specify a custom MAC address for your container's network interface. This is useful for:
- Network testing scenarios requiring predictable MAC addresses
- Consistent network configuration across container restarts
The MAC address must be in the format XX:XX:XX:XX:XX:XX (with colons or hyphens as separators). Set the two least significant bits of the first octet to 10 (locally signed, unicast address).
container run --network default,mac=02:42:ac:11:00:02 ubuntu:latestTo verify the MAC address is set correctly, run ip addr show inside the container:
% container run --rm --network default,mac=02:42:ac:11:00:02 ubuntu:latest ip addr show eth0
2: eth0: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000
link/ether 02:42:ac:11:00:02 brd ff:ff:ff:ff:ff:ff
inet 192.168.64.2/24 brd 192.168.64.255 scope global eth0
valid_lft forever preferred_lft foreverIf you don't specify a MAC address, container will generate one for you. The generated address has a first nibble set to hexadecimal f (fX:XX:XX:XX:XX:XX) in case you want to minimize the very small chance of conflict between your MAC address and generated addresses.
Mount your host SSH authentication socket in your container
Use the --ssh option to mount the macOS SSH authentication socket into your container, so that you can clone private git repositories and perform other tasks requiring passwordless SSH authentication.
When you use --ssh, it performs the equivalent of the options --volume "${SSH_AUTH_SOCK}:/run/host-services/ssh-auth.sock" --env SSH_AUTH_SOCK=/run/host-services/ssh-auth.sock". The added benefit of --ssh is that when you stop your container, log out, log back in, and restart your container, the system automatically updates the target path for the socket mount to the new value of SSH_AUTH_SOCK, so that socket forwarding continues to function.
% container run -it --rm --ssh alpine:latest sh
/ # env
SHLVL=1
HOME=/root
TERM=xterm
PATH=/usr/local/sbin:/usr/local/bin:/usr/sbin:/usr/bin:/sbin:/bin
SSH_AUTH_SOCK=/run/host-services/ssh-auth.sock
PWD=/
/ # apk add openssh-client
(1/6) Installing openssh-keygen (10.0_p1-r7)
(2/6) Installing ncurses-terminfo-base (6.5_p20250503-r0)
(3/6) Installing libncursesw (6.5_p20250503-r0)
(4/6) Installing libedit (20250104.3.1-r1)
(5/6) Installing openssh-client-common (10.0_p1-r7)
(6/6) Installing openssh-client-default (10.0_p1-r7)
Executing busybox-1.37.0-r18.trigger
OK: 12 MiB in 22 packages
/ # ssh-add -l
...auth key output...
/ # apk add git
(1/12) Installing brotli-libs (1.1.0-r2)
(2/12) Installing c-ares (1.34.5-r0)
(3/12) Installing libunistring (1.3-r0)
(4/12) Installing libidn2 (2.3.7-r0)
(5/12) Installing nghttp2-libs (1.65.0-r0)
(6/12) Installing libpsl (0.21.5-r3)
(7/12) Installing zstd-libs (1.5.7-r0)
(8/12) Installing libcurl (8.14.1-r1)
(9/12) Installing libexpat (2.7.1-r0)
(10/12) Installing pcre2 (10.43-r1)
(11/12) Installing git (2.49.1-r0)
(12/12) Installing git-init-template (2.49.1-r0)
Executing busybox-1.37.0-r18.trigger
OK: 24 MiB in 34 packages
/ # git clone git@github.com:some-org/some-private-repo.git
Cloning into 'some-private-repo'...
...Create and use a separate isolated network
[!NOTE]
This feature is available on macOS 26 and later.
Running container system start creates a vmnet network named default to which your containers will attach unless you specify otherwise.
You can create a separate isolated network using container network create.
This command creates a network named foo:
container network create fooYou can also specify custom IPv4 and IPv6 subnets when creating a network:
container network create foo --subnet 192.168.100.0/24 --subnet-v6 fd00:1234::/64The foo network, the default network, and any other networks you create are isolated from one another. A container on one network has no connectivity to containers on other networks.
Run container network list to see the networks that exist:
% container network list
NETWORK STATE SUBNET
default running 192.168.64.0/24
foo running 192.168.65.0/24
%Run a container that is attached to that network using the --network flag:
container run -d --name my-web-server --network foo --rm web-testUse container ls to see that the container is on the foo subnet:
% container ls
ID IMAGE OS ARCH STATE ADDR
my-web-server web-test:latest linux arm64 running 192.168.65.2You can delete networks that you create once no containers are attached:
container stop my-web-server
container network delete fooNetworks support both IPv4 and IPv6. When creating a network without explicit subnet options, the system uses default values if configured via system properties (see below), or automatically allocates subnets. The system validates that custom subnets don't overlap with existing networks.
Configure default network subnets
You can customize the default IPv4 and IPv6 subnets used for new networks using system properties.
Set default IPv4 subnet
container system property set network.subnet 192.168.100.1/24Set default IPv6 prefix
container system property set network.subnetv6 fd00:abcd::/64These settings apply to networks created without explicit --subnet or --subnet-v6 options.
View container logs
The container logs command displays the output from your containerized application:
<pre> % container run -d --name my-web-server --rm registry.example.com/fido/web-test:latest my-web-server % curl http://my-web-server.test <!DOCTYPE html><html><head><title>Hello</title></head><body><h1>Hello, world!</h1></body></html> % container logs my-web-server 192.168.64.1 - - [15/May/2025 03:00:03] "GET / HTTP/1.1" 200 - % </pre>
Use the --boot option to see the logs for the virtual machine boot and init process:
<pre> % container logs --boot my-web-server [ 0.098284] cacheinfo: Unable to detect cache hierarchy for CPU 0 [ 0.098466] random: crng init done [ 0.099657] brd: module loaded [ 0.100707] loop: module loaded [ 0.100838] virtio_blk virtio2: 1/0/0 default/read/poll queues [ 0.101051] virtio_blk virtio2: [vda] 1073741824 512-byte logical blocks (550 GB/512 GiB) ... [ 0.127467] EXT4-fs (vda): mounted filesystem without journal. Quota mode: disabled. [ 0.127525] VFS: Mounted root (ext4 filesystem) readonly on device 254:0. [ 0.127635] devtmpfs: mounted [ 0.127773] Freeing unused kernel memory: 2816K [ 0.143252] Run /sbin/vminitd as init process 2025-05-15T02:24:08+0000 info vminitd : [vminitd] vminitd booting... 2025-05-15T02:24:08+0000 info vminitd : [vminitd] serve vminitd api 2025-05-15T02:24:08+0000 debug vminitd : [vminitd] starting process supervisor 2025-05-15T02:24:08+0000 debug vminitd : port=1024 [vminitd] booting grpc server on vsock ... 2025-05-15T02:24:08+0000 debug vminitd : exits=[362: 0] pid=363 [vminitd] checking for exit of managed process 2025-05-15T02:24:08+0000 debug vminitd : [vminitd] waiting on process my-web-server [ 1.122742] IPv6: ADDRCONF(NETDEV_CHANGE): eth0: link becomes ready 2025-05-15T02:24:39+0000 debug vminitd : sec=1747275879 usec=478412 [vminitd] setTime % </pre>
Monitor container resource usage
The container stats command displays real-time resource usage statistics for your running containers, similar to the top command for processes. This is useful for:
- Monitoring CPU and memory consumption
- Tracking network and disk I/O
- Identifying resource-intensive containers
- Verifying container resource limits are appropriate
By default, container stats shows live statistics for all running containers in an interactive display:
% container stats
Container ID Cpu % Memory Usage Net Rx/Tx Block I/O Pids
my-web-server 2.45% 45.23 MiB / 1.00 GiB 1.23 MiB / 856.00 KiB 4.50 MiB / 2.10 MiB 3
db 125.12% 512.50 MiB / 2.00 GiB 5.67 MiB / 3.21 MiB 125.00 MiB / 89.00 MiB 12To monitor specific containers, provide their names or IDs:
% container stats my-web-server dbFor a single snapshot (non-interactive), use the --no-stream flag:
% container stats --no-stream my-web-server
Container ID Cpu % Memory Usage Net Rx/Tx Block I/O Pids
my-web-server 30.45% 45.23 MiB / 1.00 GiB 1.23 MiB / 856.00 KiB 4.50 MiB / 2.10 MiB 3You can also output statistics in JSON format for scripting:
% container stats --format json --no-stream my-web-server | jq
[
{
"id": "my-web-server",
"memoryUsageBytes": 47431680,
"memoryLimitBytes": 1073741824,
"cpuUsageUsec": 1234567,
"networkRxBytes": 1289011,
"networkTxBytes": 876544,
"blockReadBytes": 4718592,
"blockWriteBytes": 2202009,
"numProcesses": 3
}
]Understanding the metrics:
- Cpu %: Percentage of CPU usage. ~100% = one fully utilized core. A multi-core container can show > 100%.
- Memory Usage: Current memory usage vs. the container's memory limit.
- Net Rx/Tx: Network bytes received and transmitted.
- Block I/O: Disk bytes read and written.
- Pids: Number of processes running in the container.
Expose virtualization capabilities to a container
[!NOTE]
This feature requires a M3 or newer Apple silicon machine and a Linux kernel that supports virtualization. For a kernel configuration that has all of the right features enabled, see https://github.com/apple/containerization/blob/0.5.0/kernel/config-arm64#L602.
You can enable virtualization capabilities in containers by using the --virtualization option of container run and container create.
If your machine does not have support for nested virtualization, you will see the following:
container run --name nested-virtualization --virtualization --kernel /path/to/a/kernel/with/virtualization/support --rm ubuntu:latest sh -c "dmesg | grep kvm"
Error: unsupported: "nested virtualization is not supported on the platform"When nested virtualization is enabled successfully, dmesg will show output like the following:
container run --name nested-virtualization --virtualization --kernel /path/to/a/kernel/with/virtualization/support --rm ubuntu:latest sh -c "dmesg | grep kvm"
[ 0.017245] kvm [1]: IPA Size Limit: 40 bits
[ 0.017499] kvm [1]: GICv3: no GICV resource entry
[ 0.017501] kvm [1]: disabling GICv2 emulation
[ 0.017506] kvm [1]: GIC system register CPU interface enabled
[ 0.017685] kvm [1]: vgic interrupt IRQ9
[ 0.017893] kvm [1]: Hyp mode initialized successfullyConfigure system properties
The container system property subcommand manages the configuration settings for the container CLI and services. You can customize various aspects of container behavior, including build settings, default images, and network configuration.
Use container system property list to show information for all available properties:
% bin/container system property ls
ID TYPE VALUE DESCRIPTION
build.rosetta Bool true Build amd64 images on arm64 using Rosetta, instead of QEMU.
dns.domain String *undefined* If defined, the local DNS domain to use for containers with unqualified names.
image.builder String ghcr.io/apple/container-builder-shim/... The image reference for the utility container that `container build` uses.
image.init String ghcr.io/apple/containerization/vminit... The image reference for the default initial filesystem image.
kernel.binaryPath String opt/kata/share/kata-containers/vmlinu... If the kernel URL is for an archive, the archive member pathname for the kernel file.
kernel.url String https://github.com/kata-containers/ka... The URL for the kernel file to install, or the URL for an archive containing the kernel file.
network.subnet String *undefined* Default subnet for IPv4 allocation.
network.subnetv6 String *undefined* Default IPv6 network prefix.Example: Disable Rosetta for builds
If you want to prevent the use of Rosetta translation during container builds on Apple Silicon Macs:
container system property set build.rosetta falseThis is useful when you want to ensure builds only produce native arm64 images and avoid any x86_64 emulation.
View system logs
The container system logs command allows you to look at the log messages that container writes:
<pre> % container system logs | tail -8 2025-06-02 16:46:11.560780-0700 0xf6dc5 Info 0x0 61684 0 container-apiserver: [com.apple.container:APIServer] Registering plugin [id=com.apple.container.container-runtime-linux.my-web-server] 2025-06-02 16:46:11.699095-0700 0xf6ea8 Info 0x0 61733 0 container-runtime-linux: [com.apple.container:RuntimeLinuxHelper] starting container-runtime-linux [uuid=my-web-server] 2025-06-02 16:46:11.699125-0700 0xf6ea8 Info 0x0 61733 0 container-runtime-linux: [com.apple.container:RuntimeLinuxHelper] configuring XPC server [uuid=my-web-server] 2025-06-02 16:46:11.700908-0700 0xf6ea8 Info 0x0 61733 0 container-runtime-linux: [com.apple.container:RuntimeLinuxHelper] starting XPC server [uuid=my-web-server] 2025-06-02 16:46:11.703028-0700 0xf6ea8 Info 0x0 61733 0 container-runtime-linux: [com.apple.container:RuntimeLinuxHelper] bootstrap xpc handler [uuid=my-web-server] 2025-06-02 16:46:11.720836-0700 0xf6dc3 Info 0x0 61689 0 container-network-vmnet: [com.apple.container:NetworkVmnetHelper] allocated attachment [hostname=my-web-server.test.] [address=192.168.64.2/24] [gateway=192.168.64.1] [id=default] 2025-06-02 16:46:12.293193-0700 0xf6eaa Info 0x0 61733 0 container-runtime-linux: [com.apple.container:RuntimeLinuxHelper] start xpc handler [uuid=my-web-server] 2025-06-02 16:46:12.368723-0700 0xf6e93 Info 0x0 61684 0 container-apiserver: [com.apple.container:APIServer] Handling container my-web-server Start. % </pre>
Generating and installing completion scripts
Overview
The container --generate-completion-script [zsh|bash|fish] command generates completion scripts for the provided shell. Below is a detailed guide on how to install the completion scripts.
[!NOTE]
See the swift-argument-parser documentation for more information about generating and installing shell completion scripts.
Installing zsh completions
If you have oh-my-zsh installed, you already have a directory of automatically loaded completion scripts — .oh-my-zsh/completions. Copy your new completion script to that directory. If the completions directory does not exist, simply make it.
mkdir -p ~/.oh-my-zsh/completions
container --generate-completion-script zsh > ~/.oh-my-zsh/completions/_container
source ~/.oh-my-zsh/completions/_container[!NOTE]
Your completion script must have the filename _container.Without oh-my-zsh, you’ll need to add a path for completion scripts to your function path, and turn on completion script autoloading. First, add these lines to your ~/.zshrc file:
fpath=(~/.zsh/completion $fpath)
autoload -U compinit
compinitNext, create a directory at ~/.zsh/completion and copy the completion script to the new directory.
mkdir -p ~/.zsh/completion
container --generate-completion-script zsh > ~/.zsh/completion/_container
source ~/.zshrcInstalling bash completions
If you have bash-completion installed, you can just copy your new completion script to the bash_completion.d directory.
[!NOTE]
The path to the directory is dependent on how bash-completion was installed. Find the correct path and then copy the completion script there. For example, if you used homebrew to install bash-completion:```bash
container --generate-completion-script bash > /opt/homebrew/etc/bash_completion.d/container
source /opt/homebrew/etc/bash_completion.d/container
```
Without bash-completion, you’ll need to source the completion script directly. Create and copy it to a directory such as ~/.bash_completions.
mkdir -p ~/.bash_completions
container --generate-completion-script bash > ~/.bash_completions/container
source ~/.bash_completions/containerFurthermore, you can add the following line to ~/.bash_profile or ~/.bashrc, in order for every new bash session to have autocompletion ready.
source ~/.bash_completions/containerInstalling fish completions
Copy the completion script to any path listed in the environment variable $fish_completion_path.
container --generate-completion-script fish > ~/.config/fish/completions/container.fishTechnical Overview
[!IMPORTANT]
This file contains documentation for the CURRENT BRANCH. To find documentation for official releases, find the target release on the Release Page and click the tag corresponding to your release version.
>
Example: release 0.4.1 tag
A brief description and technical overview of container.
What are containers?
Containers are a way to package an application and its dependencies into a single unit. At runtime, containers provide isolation from the host machine as well as other colocated containers, allowing applications to run securely and efficiently in a wide variety of environments.
Containerization is an important server-side technology that is used throughout the software lifecycle:
- Backend developers use containers on their personal systems to create predictable execution environments for applications, and to develop and test their applications under conditions that better approximate how they would run in the datacenter.
- Continuous integration and deployment (CI/CD) systems use containerization to perform reproducible builds of applications, package the results as deployable images, and deploy them to the datacenter.
- Datacenters run container orchestration platforms that use the images to run containerized applications in a reliable, highly available compute cluster.
None of this workflow would be practical without ensuring interoperability between different container implementations. The Open Container Initiative (OCI) creates and maintains these standards for container images and runtimes.
How does container run my container?
Many operating systems support containers, but the most commonly encountered containers are those that run on the Linux operating system. With macOS, the typical way to run Linux containers is to launch a Linux virtual machine (VM) that hosts all of your containers.
container runs containers differently. Using the open source Containerization package, it runs a lightweight VM for each container that you create. This approach has the following properties:
- Security: Each container has the isolation properties of a full VM, using a minimal set of core utilities and dynamic libraries to reduce resource utilization and attack surface.
- Privacy: When sharing host data using
container, you mount only necessary data into each VM. With a shared VM, you need to mount all data that you may ever want to use into the VM, so that it can be mounted selectively into containers. - Performance: Containers created using
containerrequire less memory than full VMs, with boot times that are comparable to containers running in a shared VM.
Since container consumes and produces standard OCI images, you can easily build with and run images produced by other container applications, and the images that you build will run everywhere.
container and the underlying Containerization package integrate with many of the key technologies and frameworks of macOS:
- The Virtualization framework for managing Linux virtual machines and their attached devices.
- The vmnet framework for managing the virtual network to which the containers attach.
- XPC for interprocess communication.
- Launchd for service management.
- Keychain services for access to registry credentials.
- The unified logging system for application logging.
You use the container command line interface (CLI) to start and manage your containers, build container images, and transfer images from and to OCI container registries. The CLI uses a client library that communicates with container-apiserver and its helpers.
The container-apiserver is a launch agent that launches when you run the container system start command, and terminates when you run container system stop. It provides the client APIs for managing container and network resources.
When container-apiserver starts, it launches an XPC helper container-core-images that exposes an API for image management and manages the local content store, and another XPC helper container-network-vmnet for the virtual network. For each container that you create, container-apiserver launches a container runtime helper container-runtime-linux that exposes the management API for that specific container.
What limitations does container have today?
With the initial release of container, you get basic facilities for building and running containers, but many common containerization features remain to be implemented. Consider contributing new features and bug fixes to container and the Containerization projects!
Container to host networking
In the initial release, there is no way to route traffic directly from a client in a container to a host-based application listening on the loopback interface at 127.0.0.1. If you were to configure the application in your container to connect to 127.0.0.1 or localhost, requests would simply go to the loopback interface in the container, rather than your host-based service.
You can work around this limitation by configuring the host-based application to listen on the wildcard address 0.0.0.0, but this practice is insecure and not recommended because, without firewall rules, this exposes the application to external requests.
A more secure approach uses socat to redirect traffic from the container network gateway to the host-based service. For example, to forward traffic for port 8000, configure your containerized application to connect to 192.168.64.1:8000 instead of 127.0.0.1:8000, and then run the following command in a terminal on your Mac to forward the port traffic from the gateway to the host:
socat TCP-LISTEN:8000,fork,bind=192.168.64.1 TCP:127.0.0.1:8000Releasing container memory to macOS
The macOS Virtualization framework implements only partial support for memory ballooning, which is a technology that allows virtual machines to dynamically use and relinquish host memory. When you create a container, the underlying virtual machine only uses the amount of memory that the containerized application needs. For example, you might start a container using the option --memory 16g, but see that the application is only using 2 GiBytes of RAM in the macOS Activity Monitor.
Currently, memory pages freed to the Linux operating system by processes running in the container's VM are not relinquished to the host. If you run many memory-intensive containers, you may need to occasionally restart them to reduce memory utilization.
macOS 15 limitations
container relies on the new features and enhancements present in macOS 26. You can run container on macOS 15, but you will need to be aware of some user experience and functional limitations. There is no plan to address issues found with macOS 15 that cannot be reproduced on macOS 26.
Network isolation
The vmnet framework in macOS 15 can only provide networks where the attached containers are isolated from one another. Container-to-container communication over the virtual network is not possible.
Multiple networks
In macOS 15, all containers attach to the default vmnet network. The container network commands are not available on macOS 15, and using the --network option for container run or container create will result in an error.
Container IP addresses
In macOS 15, limitations in the vmnet framework mean that the container network can only be created when the first container starts. Since the network XPC helper provides IP addresses to containers, and the helper has to start before the first container, it is possible for the network helper and vmnet to disagree on the subnet address, resulting in containers that are completely cut off from the network.
Normally, vmnet creates the container network using the CIDR address 192.168.64.1/24, and on macOS 15, container defaults to using this CIDR address in the network helper. To diagnose and resolve issues stemming from a subnet address mismatch between vmnet and the network helper:
- Before creating the first container, scan the output of the command
ifconfigfor a bridge interface named similarly tobridge100. - After creating the first container, run
ifconfigagain, and locate the new bridge interface to determine the container subnet address. - Run
container lsto check the IP address given to the container by the network helper. If the address corresponds to a different network: - Run
container system stopto terminate the services forcontainer. - Using the macOS
defaultscommand, update the default subnet value used by the network helper process. For example, if the bridge address shown byifconfigis 192.168.66.1, run:
defaults write com.apple.container.defaults network.subnet 192.168.66.1/24- Run
container system startto launch services again. - Try running the container again and verify that its IP address matches the current bridge interface value.
Tutorial
[!IMPORTANT]
This file contains documentation for the CURRENT BRANCH. To find documentation for official releases, find the target release on the Release Page and click the tag corresponding to your release version.
>
Example: release 0.4.1 tag
Take a guided tour of container by building, running, and publishing a simple web server image.
Try out the container CLI
Start the application, and try out some basic commands to familiarize yourself with the command line interface (CLI) tool.
Start the container service
Start the services that container uses:
container system startIf you have not installed a Linux kernel yet, the command will prompt you to install one:
<pre> % container system start
Verifying apiserver is running... Installing base container filesystem... No default kernel configured. Install the recommended default kernel from [https://github.com/kata-containers/kata-containers/releases/download/3.17.0/kata-static-3.17.0-arm64.tar.xz]? [Y/n]: y Installing kernel... % </pre>
Then, verify that the application is working by running a command to list all containers:
container list --allIf you haven't created any containers yet, the command outputs an empty list:
<pre> % container list --all ID IMAGE OS ARCH STATE ADDR % </pre>
Get CLI help
You can get help for any container CLI command by appending the --help option:
<pre> % container --help OVERVIEW: A container platform for macOS
USAGE: container [--debug] <subcommand>
OPTIONS: --debug Enable debug output [environment: CONTAINER_DEBUG] --version Show the CLI version (single line). -h, --help Show help information.
Detailed version information is available under the system command:
container system version [--format json|table]CONTAINER SUBCOMMANDS: create Create a new container delete, rm Delete one or more containers exec Run a new command in a running container inspect Display information about one or more containers kill Kill one or more running containers list, ls List containers logs Fetch container stdio or boot logs run Run a container start Start a container stop Stop one or more running containers
IMAGE SUBCOMMANDS: build Build an image from a Dockerfile image, i Manage images registry, r Manage registry configurations
SYSTEM SUBCOMMANDS: builder Manage an image builder instance system, s Manage system components
% </pre>
Abbreviations
You can save keystrokes by abbreviating commands and options. For example, abbreviate the container list command to container ls, and the --all option to -a:
<pre> % container ls -a ID IMAGE OS ARCH STATE ADDR % </pre>
Use the --help flag to see which abbreviations exist.
Set up a local DNS domain (optional)
container includes an embedded DNS service that simplifies access to your containerized applications. If you want to configure a local DNS domain named test for this tutorial, run:
sudo container system dns create test
container system property set dns.domain testEnter your administrator password when prompted. The first command requires administrator privileges to create a file containing the domain configuration under the /etc/resolver directory, and to tell the macOS DNS resolver to reload its configuration files.
The second command makes test the default domain to use when running a container with an unqualified name. For example, if the default domain is test and you use --name my-web-server to start a container, queries to my-web-server.test will respond with that container's IP address.
Build an image
Set up a Dockerfile for a basic Python web server, and use it to build a container image named web-test.
Set up a simple project
Start a terminal, create a directory named web-test for the files needed to create the container image:
mkdir web-test
cd web-testIn the web-test directory, create a file named Dockerfile with this content:
FROM docker.io/python:alpine
WORKDIR /content
RUN apk add curl
RUN echo '<!DOCTYPE html><html><head><title>Hello</title></head><body><h1>Hello, world!</h1></body></html>' > index.html
CMD ["python3", "-m", "http.server", "80", "--bind", "0.0.0.0"]The FROM line instructs the container builder to start with a base image containing the latest production version of Python 3.
The WORKDIR line creates a directory /content in the image, and makes it the current directory.
The first RUN line adds the curl command to your image, and the second RUN line creates a simple HTML landing page named /content/index.html.
The CMD line configures the container to run a simple web server in Python on port 80. Since the working directory is /content, the web server runs in that directory and delivers the content of the file /content/index.html when a user requests the index page URL.
The server listens on the wildcard address 0.0.0.0 to allow connections from the host and other containers. You can safely use the listen address 0.0.0.0 inside the container, because external systems have no access to the virtual network to which the container attaches.
Build the web server image
Run the container build command to create an image with the name web-test from your Dockerfile:
container build --tag web-test --file Dockerfile .The last argument . tells the builder to use the current directory (web-test) as the root of the build context. You can copy files within the build context into your image using the COPY command in your Dockerfile.
After the build completes, list the images. You should see both the base image and the image that you built in the results:
<pre> % container image list NAME TAG DIGEST python alpine b4d299311845147e7e47c970... web-test latest 25b99501f174803e21c58f9c... % </pre>
Run containers
Using your container image, run a web server and try out different ways of interacting with it.
Start the webserver
Use container run to start a container named my-web-server that runs your webserver:
container run --name my-web-server --detach --rm web-testThe --detach flag runs the container in the background, so that you can continue running commands in the same terminal. The --rm flag causes the container to be removed automatically after it stops.
When you list containers now, my-web-server is present, along with the container that container started to build your image. Note that its IP address, shown in the ADDR column, is 192.168.64.3:
<pre> % container ls ID IMAGE OS ARCH STATE ADDR buildkit ghcr.io/apple/container-builder-shim/builder:0.0.3 linux arm64 running 192.168.64.2 my-web-server web-test:latest linux arm64 running 192.168.64.3 % </pre>
Open the website, using the container's IP address in the URL:
open http://192.168.64.3If you configured the local domain test earlier in the tutorial, you can also open the page with the full hostname for the container:
open http://my-web-server.testMonitor container resource usage
Now that your web server is running, you can monitor its resource usage with the container stats command:
container stats my-web-serverThis displays real-time statistics about CPU usage, memory consumption, network traffic, disk I/O, and the number of running processes:
<pre> % container stats --no-stream my-web-server Container ID Cpu % Memory Usage Net Rx/Tx Block I/O Pids my-web-server 0.23% 12.45 MiB / 1.00 GiB 856.00 KiB / 1.2 KiB 2.10 MiB / 512 KiB 2 % </pre>
[!NOTE]
Without the--no-streamflag,container statscontinuously updates the display in real-time, similar to thetopcommand. Press Ctrl+C to exit the live view.
Run other commands in the container
You can run other commands in my-web-server by using the container exec command. To list the files under the content directory, run an ls command:
<pre> % container exec my-web-server ls /content index.html % </pre>
If you want to poke around in the container, run a shell and issue one or more commands:
<pre> % container exec --tty --interactive my-web-server sh /content # ls index.html /content # uname -a Linux my-web-server 6.12.28 #1 SMP Tue May 20 15:19:05 UTC 2025 aarch64 Linux /content # exit % </pre>
The --tty and --interactive flag allow you to interact with the shell from your host terminal. The --tty flag tells the shell in the container that its input is a terminal device, and the --interactive flag connects what you input in your host terminal to the input of the shell in the container.
You will often see these two options abbreviated and specified together as -ti or -it.
Access the web server from another container
Your web server is accessible from other containers as well as from your host. Launch a second container using your web-test image, and this time, specify a curl command to retrieve the index.html content from the first container.
[!NOTE]
Container relies on the new features and enhancements present in macOS 26.
As a result, the functionality of accessing the web server from another container will not work on macOS 15.
See https://github.com/apple/container/blob/main/docs/technical-overview.md#macos-15-limitations for more details.
container run -it --rm web-test curl http://192.168.64.3The output should appear as:
<pre> % container run -it --rm web-test curl http://192.168.64.3 <!DOCTYPE html><html><head><title>Hello</title></head><body><h1>Hello, world!</h1></body></html> % </pre>
If you set up the test domain earlier, you can achieve the same result with:
container run -it --rm web-test curl http://my-web-server.testRun a published image
Push your image to a container registry, publishing it so that you and others can use it.
Publish the web server image
To publish your image, you need to push images to a registry service that stores the image for future use. Typically, you need to authenticate with a registry to push an image. This example assumes that you have an account at a hypothetical registry named some-registry.example.com with username fido and a password or token my-secret, and that your personal repository name is the same as your username.
To sign into a secure registry with your login credentials, enter your username and password at the prompts after running:
container registry login some-registry.example.comCreate another name for your image that includes the registry name, your repository name, and the image name, with the tag latest:
container image tag web-test some-registry.example.com/fido/web-test:latestThen, push the image:
container image push some-registry.example.com/fido/web-test:latest[!NOTE]
By default container is configured to use Docker Hub.You can change the default registry to another value by running container system property set registry.domain some-registry.example.com.See the other sub commands under container registry for more options.Pull and run your image
To validate your published image, stop your current web server container, remove the image that you built, and then run using the remote image:
container stop my-web-server
container image delete web-test some-registry.example.com/fido/web-test:latest
container run --name my-web-server --detach --rm some-registry.example.com/fido/web-test:latestClean up
Stop your container and shut down the application.
Shut down the web server
Stop your web server container with:
container stop my-web-serverIf you list all running and stopped containers, you will see that the --rm flag you supplied with the container run command caused the container to be removed:
<pre> % container list --all ID IMAGE OS ARCH STATE ADDR buildkit ghcr.io/apple/container-builder-shim/builder:0.0.3 linux arm64 running 192.168.64.2 % </pre>
Stop the container service
When you want to stop container completely, run:
container system stop