# BuildKit Integration with Container Build: A Complete Guide to Apple's Container Toolchain

> Explore BuildKit integration with container build in Apple's toolchain. Learn how a self-contained buildkitd daemon and buildctl client streamline your builds with JSON progress events and a native terminal bar.

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

---

**The Apple container repository implements BuildKit integration by running a self-contained buildkitd daemon inside a lightweight Alpine-based builder container, using the buildctl client to execute builds while streaming JSON progress events to a native terminal progress bar.**

The Apple container repository provides a complete toolchain for building OCI images inside isolated container-based environments. The BuildKit integration sits at the heart of this workflow, wrapping the standard BuildKit daemon in a modular container architecture that keeps the host environment completely clean. This design enables modern build capabilities—layer caching, parallel builds, and advanced exports—through familiar CLI commands while maintaining strict isolation between the build environment and the host system.

## How the Builder Architecture Works

The BuildKit integration uses a **builder container pattern** rather than running the daemon directly on the host. When you execute `container build`, the tool orchestrates a multi-step sequence that manages container lifecycle, context mounting, and client-server communication automatically.

### The Builder Container Lifecycle

The builder exists as a dedicated container named `container-builder-<uuid>` that encapsulates the entire BuildKit runtime. In [`Sources/ContainerCommands/Builder/BuilderStart.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Builder/BuilderStart.swift), the `startBuildKit` helper (lines 307–338) handles the initialization sequence:

1. **Pull the BuildKit image** – By default uses `docker.io/library/buildkit:latest`, though this is configurable via `--image`
2. **Create the container** with resource limits (CPU/memory) that can be overridden via CLI flags
3. **Mount the socket** at `/run/buildkit` inside the container filesystem
4. **Launch buildkitd** using the containerd shim (`containerd-shim-buildkit`)

This containerized approach allows multiple independent builders to run simultaneously on the same host without interference. Each builder maintains its own daemon state, build cache, and resource quotas.

### Build Context Isolation

When you run `container build`, the command mounts your local build context into the builder container using a temporary volume or bind-mount. The [`BuildCommand.swift`](https://github.com/apple/container/blob/main/BuildCommand.swift) file orchestrates this by:

- Creating a temporary workspace directory
- Copying the user's build context (Dockerfile/Containerfile and sources) into the isolated environment
- Invoking `buildctl` inside the builder with `--local context` and `--local dockerfile` pointing to the mounted temporary directory

This isolation ensures that the BuildKit daemon never has direct access to the host filesystem, only to the explicitly provided context.

## The Build Execution Flow

The actual build process bridges the CLI and the containerized daemon through a Unix socket connection that lives entirely within the builder's filesystem.

### From buildctl to BuildKit Daemon

The [`BuildCommand.swift`](https://github.com/apple/container/blob/main/BuildCommand.swift) entry point validates that a builder container is running before executing the build. Once verified, it constructs and executes a `buildctl` command with arguments such as:

```bash
buildctl build \
  --frontend dockerfile.v0 \
  --local context=/tmp/ctx \
  --local dockerfile=/tmp/ctx \
  --output type=image,name=myimage,push=false

```

The client communicates with `buildkitd` over the Unix socket at `/run/buildkit` inside the builder container. For registry pushes, change the output specification to `type=image,name=registry.example.com/myimage,push=true`.

### Progress Event Streaming

BuildKit streams detailed JSON-encoded progress events back to the host process via the client connection. The [`Sources/TerminalProgress/ProgressTaskCoordinator.swift`](https://github.com/apple/container/blob/main/Sources/TerminalProgress/ProgressTaskCoordinator.swift) file handles these events, parsing the raw JSON and updating the terminal UI using the `ProgressBar` implementation.

This architecture separates the heavy lifting (image construction inside the container) from the user interface (progress rendering on the host), allowing for rich terminal output without requiring complex IPC mechanisms.

## Managing the Builder Lifecycle

The repository provides explicit commands for managing the BuildKit builder container throughout its lifecycle, ensuring resources can be reclaimed when builds complete.

### Starting the Builder

Use the `container builder start` command to initialize the environment. As implemented in [`BuilderStart.swift`](https://github.com/apple/container/blob/main/BuilderStart.swift), this command accepts flags for resource tuning:

```bash
container builder start \
  --image ghcr.io/apple/buildkit:latest \
  --cpu 2 \
  --memory 4Gi

```

The command checks for existing builders and creates a new container only if none are running. The builder persists after builds complete, maintaining the BuildKit cache for subsequent invocations.

### Stopping and Deleting

When you need to reclaim resources or upgrade the BuildKit version, use the lifecycle management commands:

- `container builder stop` – Stops the running builder container while preserving its filesystem state
- `container builder delete` – Removes the builder container entirely
- `container builder delete --force` – Overrides the "running" check to force removal of active builders (implemented in [`BuilderDelete.swift`](https://github.com/apple/container/blob/main/BuilderDelete.swift))

The [`BuilderDelete.swift`](https://github.com/apple/container/blob/main/BuilderDelete.swift) file handles the safety checks and container removal logic, ensuring that running builders cannot be accidentally deleted without the explicit `--force` flag.

## Practical BuildKit Commands

The [`docs/command-reference.md`](https://github.com/apple/container/blob/main/docs/command-reference.md) file documents the complete CLI surface. Here is a typical workflow for building and pushing an OCI image:

```bash

# Start the BuildKit builder with custom resources

container builder start --cpu 4 --memory 8Gi

# Verify the builder status

container builder status

# Build an image from the current directory

container build -t myapp:v1.0 .

# Build and push directly to a registry

container build \
  -t registry.example.com/myapp:latest \
  --push \
  .

# Clean up when finished

container builder stop
container builder delete

```

The `--push` flag automatically configures the output type for registry export, handling authentication through the host's Docker configuration or explicit registry credentials.

## Summary

- **Containerized Builder**: BuildKit runs inside a dedicated Alpine-based container (`container-builder-<uuid>`), keeping the host environment clean and allowing multiple isolated builders per host.
- **Socket-based Communication**: The `buildctl` client communicates with `buildkitd` over a Unix socket mounted at `/run/buildkit` inside the builder container.
- **Progress Streaming**: Build events flow from the daemon through `buildctl` to the `ProgressTaskCoordinator` in `Sources/TerminalProgress/`, rendering real-time progress bars.
- **Explicit Lifecycle**: Commands in `Sources/ContainerCommands/Builder/` manage builder state—[`BuilderStart.swift`](https://github.com/apple/container/blob/main/BuilderStart.swift) for initialization, [`BuilderDelete.swift`](https://github.com/apple/container/blob/main/BuilderDelete.swift) for removal with optional `--force`.
- **Context Isolation**: Build contexts are copied into temporary directories inside the builder, ensuring the daemon only accesses explicitly provided files.

## Frequently Asked Questions

### How does the container command communicate with the BuildKit daemon?

The `container` binary ships with an embedded `buildctl` client that connects to `buildkitd` over a Unix socket located at `/run/buildkit` inside the builder container. The socket is mounted into the container filesystem during startup via [`BuilderStart.swift`](https://github.com/apple/container/blob/main/BuilderStart.swift), and the host process proxies connections through this socket.

### Can I run multiple BuildKit builders simultaneously on the same machine?

Yes. Each builder receives a unique UUID and runs as a separate container (named `container-builder-<uuid>`). You can start multiple builders with different resource limits or BuildKit versions, and they operate independently without shared state or cache interference.

### Where does the build context get mounted during a container build?

The build context is copied into a temporary directory inside the builder container. According to [`BuildCommand.swift`](https://github.com/apple/container/blob/main/BuildCommand.swift), the context is mounted via temporary volumes or bind-mounts at paths like `/tmp/ctx`, with `--local context` and `--local dockerfile` arguments pointing to these locations when invoking `buildctl`.

### What happens if I force delete a running builder?

The [`BuilderDelete.swift`](https://github.com/apple/container/blob/main/BuilderDelete.swift) implementation supports a `--force` flag that bypasses the running state check. When used, the command immediately stops and removes the builder container regardless of whether it is currently executing a build, which may interrupt ongoing operations but ensures cleanup completes.