How to Build Container Images with the Apple Container CLI
Building container images with Apple's container tool requires a Dockerfile (or Containerfile), a running Linux builder VM that hosts BuildKit, and the container build command to compile layers into an OCI-compliant image stored in the local registry.
The Apple container repository provides a Docker-compatible CLI for macOS that enables you to build container images using standard Dockerfiles while leveraging a lightweight Linux VM for build isolation. As documented in docs/tutorials/start-here.md and docs/command-reference.md, this open-source tool implements the complete container image build workflow through BuildKit execution inside a configurable builder environment.
Core Build Components
Three primary components work together to build container images:
-
Dockerfile: A text file describing image layers, base images,
RUNsteps, and entrypoints. The CLI accepts bothDockerfileandContainerfilenaming conventions. -
Builder VM: A lightweight Linux virtual machine defined in
ContainerSystemConfig.buildthat isolates the build process from the host macOS system. Configuration includes CPU count, memory allocation, and the builder image reference (default:ghcr.io/apple/container-builder-shim/builder:<tag>), as specified inSources/ContainerPersistence/ContainerSystemConfig.swift. -
BuildKit: The underlying build engine running inside the VM that executes Dockerfile instructions, handles layer caching, and produces OCI-compliant images.
Step-by-Step Process to Build Container Images
1. Prepare Your Dockerfile
Create a Dockerfile in your project directory describing the desired image state. The repository provides reference examples in examples/container-machine-vscode/Dockerfile, demonstrating standard patterns such as base image selection, package installation, and command configuration.
2. Configure the Builder VM
The builder VM starts automatically on first build, but you can pre-configure resources using commands implemented in Sources/ContainerCommands/Builder/BuilderStart.swift. This allows you to allocate sufficient CPU and memory for complex builds before compilation begins:
container builder start --cpus 8 --memory 32g
Resource limits and the builder image reference persist in Sources/ContainerPersistence/ContainerSystemConfig.swift within the ContainerSystemConfig.build structure.
3. Execute the Build Command
Invoke the build process through the CLI implementation in Sources/ContainerCommands/BuildCommand.swift. The command parses flags such as --arch, --build-arg, and --memory, then streams the build context to the builder VM:
container build --tag web-test --file Dockerfile .
The CLI communicates with the builder VM over vsock, transmitting the Dockerfile and build context for processing.
4. Monitor Build Progress
BuildKit streams layer creation progress to your terminal in real-time. You can suppress output with -q/--quiet for CI/CD environments, or export the image directly to a tarball using --output type=tar,dest=./image.tar without loading it into the local store.
5. Verify the Output
After the build completes, verify the image exists in the local OCI store managed by the container-core-images XPC helper:
container image list
You can now run the image locally, re-tag it for a registry, or push it to a remote repository using standard container image subcommands.
Architectural Implementation
The build process follows this data flow according to the source implementation:
-
CLI → Builder VM: The
containercommand parses user options, authenticates againstContainerSystemConfig, and establishes a vsock connection to the builder container. -
Builder VM → BuildKit: Inside the VM,
container-builder-shim(located at/usr/local/bin/container-builder-shim) launches BuildKit to process the Dockerfile steps and resolve build contexts. -
BuildKit → OCI Store: Completed layers write to the local content store managed by
container-core-images, an XPC helper launched byContainerAPIService(seeSources/Services/ContainerAPIService). The resulting artifact is an OCI-compatible image that can be inspected withcontainer image inspector pushed to any OCI registry.
Advanced Build Options
The container build command supports sophisticated workflows beyond basic image compilation:
-
Multi-architecture builds: Compile for multiple platforms simultaneously:
container build --arch arm64 --arch amd64 -t myapp:latest . -
Build arguments: Pass variables into the Dockerfile:
container build --build-arg NODE_VERSION=18 -t myapp . -
Cache control: Disable layer caching for reproducible builds:
container build --no-cache -t myapp . -
OCI output: Export to a specific destination without loading into the local store:
container build --output type=oci,dest=./myapp.tar -t myapp .
Summary
- Building container images requires a Dockerfile, a configured builder VM, and the
container buildcommand to orchestrate the process - The builder VM configuration resides in
Sources/ContainerPersistence/ContainerSystemConfig.swift, with defaults pointing toghcr.io/apple/container-builder-shim/builder - BuildKit executes inside the isolated VM while the CLI communicates via vsock, with implementation details in
Sources/ContainerCommands/BuildCommand.swift - Output produces OCI-compliant images stored locally through the XPC helper and manageable through standard CLI commands
Frequently Asked Questions
How do I increase memory for large container builds?
Use container builder start --memory 32g to allocate additional RAM to the builder VM before running container build. This configuration persists in ContainerSystemConfig.build and prevents out-of-memory errors during complex layer compilation involving large binaries or extensive package installations.
Can I build container images for multiple architectures simultaneously?
Yes. Pass multiple --arch flags to the build command: container build --arch arm64 --arch amd64 -t myimage:latest .. BuildKit handles cross-compilation inside the builder VM, producing a multi-architecture manifest that can run on both Apple Silicon and Intel-based systems.
Where does the builder VM image come from?
The default builder image is ghcr.io/apple/container-builder-shim/builder:<tag>, defined in Sources/ContainerPersistence/ContainerSystemConfig.swift. You can customize this reference through configuration options to use internal mirrors, air-gapped registries, or specific version tags required by your organization.
How does the build process differ from Docker Desktop?
Unlike Docker Desktop's integrated daemon, Apple's container uses a separate builder VM managed through explicit container builder commands and communicates via vsock rather than a local Unix socket. While the BuildKit implementation remains compatible with standard Dockerfiles, VM resources require explicit management through ContainerSystemConfig.build settings rather than automatic allocation.
Have a question about this repo?
These articles cover the highlights, but your codebase questions are specific. Give your agent direct access to the source. Share this with your agent to get started:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →