# How Container Implements OCI Image Specification Support for Building and Pulling Images

> Discover how apple/container implements OCI image specification support. Learn about building and pulling container images using its layered architecture and ContainerizationOCI library for full compliance.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: deep-dive
- Published: 2026-06-17

---

**The container toolchain leverages Apple's ContainerizationOCI library to provide full OCI image specification compliance for building and pulling operations through a layered architecture of CLI commands, async services, and registry-aware storage backends.**

The apple/container repository provides a Swift-native container runtime that implements the Open Container Initiative (OCI) image specification for both building and pulling operations. At its core, the toolchain relies on the **ContainerizationOCI** library, which defines Swift data models for OCI manifests, configurations, and platform descriptors. This architecture enables seamless interoperability with standard OCI registries while providing macOS-integrated authentication and platform-aware image selection.

## How OCI Image Pulling Works

The pull operation follows a structured pipeline from CLI parsing to layer verification. The `ImagesService` class in [`Sources/Services/ContainerImagesService/Server/ImagesService.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerImagesService/Server/ImagesService.swift) exposes a thin async façade that implements `list`, `pull`, `push`, `tag`, and `delete` operations, delegating heavy lifting to the underlying `ImageStore`.

### OCI Reference Parsing and Validation

When a user executes `container images pull docker.io/library/ubuntu:20.04`, the CLI first validates the reference string using `ContainerizationOCI.Reference.init(_:)`. This initializer, defined in the ContainerizationOCI library, enforces the domain pattern requirements specified by the OCI distribution specification. The `RegistryResource` struct in [`Sources/ContainerResource/Registry/RegistryResource.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Registry/RegistryResource.swift) performs additional hostname validation against the OCI distribution spec before establishing connections.

### Platform-Aware Manifest Selection

The `ImagesService` handles platform negotiation through helpers in [`Sources/ContainerAPIService/Client/DefaultPlatform.swift`](https://github.com/apple/container/blob/main/Sources/ContainerAPIService/Client/DefaultPlatform.swift). When a user specifies `--platform linux/arm64`, the service constructs a `ContainerizationOCI.Platform` value to select the matching manifest entry from multi-platform images. If no platform is specified, the system defaults to the current host platform (`.current`).

### Layer Download and Verification

The `ImageStore` implementation orchestrates the actual download by iterating over the `manifest.layers` array. For each layer, it performs an HTTP GET request, verifies the SHA256 digest against the manifest, and writes validated blobs to the local content store. Concurrency is controlled by the `maxConcurrentDownloads` parameter, which defaults to **3** to prevent registry overwhelm. Progress reporting uses `TerminalProgress` and [`ProgressBar.swift`](https://github.com/apple/container/blob/main/ProgressBar.swift) to provide blob-wise download status.

### Authentication Flow

Before initiating transfers, `ImagesService.pull` wraps the store call with `Self.withAuthentication(ref:)`. This method retrieves credentials from the macOS keychain or from `~/.container/config.json`, injecting the appropriate `Authorization` header into registry requests. The [`RegistryLogin.swift`](https://github.com/apple/container/blob/main/RegistryLogin.swift) file in `Sources/ContainerCommands/Registry/` handles the credential storage interface.

## How OCI Image Building Works

The container build process bootstraps itself using the same OCI infrastructure it ultimately produces. Rather than treating BuildKit as a host-native binary, the system runs BuildKit itself as an OCI container.

### Bootstrapping the BuildKit Container

The `BuilderStart` command in [`Sources/ContainerCommands/Builder/BuilderStart.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Builder/BuilderStart.swift) (lines 94-101) first calls `ImagesService.pull` to fetch the BuildKit OCI image (typically `docker.io/docker/buildkit:latest`). After successfully pulling and unpacking this image into a VM-level container, the code invokes `startBuildKit` (lines 307-309) to launch the BuildKit daemon inside the sandbox.

### Build Execution

Once the BuildKit daemon runs inside the VM, the CLI forwards standard `docker build` commands to it via the containerd shim. BuildKit resolves base images using the same `ImagesService` layer, processes Dockerfiles according to OCI specifications, and writes resulting image layers back to the local content store as OCI-compliant blobs.

## Registry Communication and Validation

The [`RegistryResource.swift`](https://github.com/apple/container/blob/main/RegistryResource.swift) file implements OCI distribution spec compliance by validating registry hostnames and constructing authenticated HTTP requests. It ensures that all push and pull operations follow the OCI distribution specification for manifest and blob endpoints.

### Pushing OCI Images

When pushing via `container images push myregistry.example.com/myapp:1.0`, the `ImagesService.push` method (lines 17-22 in [`ImagesService.swift`](https://github.com/apple/container/blob/main/ImagesService.swift)) authenticates to the target registry and calls `ImageStore.push`. This creates a new manifest referencing existing layer digests (without re-uploading unchanged layers) and pushes both the manifest and config JSON according to OCI spec requirements.

## Key Source Files

- **[`Sources/Services/ContainerImagesService/Server/ImagesService.swift`](https://github.com/apple/container/blob/main/Sources/Services/ContainerImagesService/Server/ImagesService.swift)**: Public async façade for image operations (`list`, `pull`, `push`, `tag`, `delete`).
- **[`Sources/ContainerCommands/Builder/BuilderStart.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Builder/BuilderStart.swift)**: Starts BuildKit by first pulling its OCI image (lines 94-101).
- **[`Sources/ContainerResource/Registry/RegistryResource.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Registry/RegistryResource.swift)**: Validates registry hostnames and builds authenticated HTTP requests per OCI distribution spec.
- **[`Sources/ContainerAPIService/Client/DefaultPlatform.swift`](https://github.com/apple/container/blob/main/Sources/ContainerAPIService/Client/DefaultPlatform.swift)**: Platform selection logic for multi-architecture OCI manifests.
- **[`Sources/ContainerResource/Image/ImageResource.swift`](https://github.com/apple/container/blob/main/Sources/ContainerResource/Image/ImageResource.swift)**: Swift representation of OCI image structures using `ContainerizationOCI.Image`.
- **[`Sources/ContainerCommands/Registry/RegistryLogin.swift`](https://github.com/apple/container/blob/main/Sources/ContainerCommands/Registry/RegistryLogin.swift)**: Handles OCI registry authentication and credential storage.

## Summary

- Container implements OCI image specification support through the **ContainerizationOCI** library, which provides Swift-native models for manifests, configs, and references.
- The **ImagesService** in [`ImagesService.swift`](https://github.com/apple/container/blob/main/ImagesService.swift) provides a unified async interface for pull, push, and tag operations, delegating to the **ImageStore** for OCI-specific logic.
- **Pulling** involves parsing references via `ContainerizationOCI.Reference`, platform selection via [`DefaultPlatform.swift`](https://github.com/apple/container/blob/main/DefaultPlatform.swift), and concurrent layer downloads with SHA256 verification.
- **Building** first pulls the BuildKit OCI image using the same `ImagesService.pull` path, then launches the daemon inside a VM to process Dockerfiles into OCI-compliant output.
- **Authentication** integrates with macOS keychain and `~/.container/config.json`, while **RegistryResource.swift** ensures OCI distribution spec compliance for all registry communications.

## Frequently Asked Questions

### How does container validate OCI image references?

The toolchain uses `ContainerizationOCI.Reference.init(_:)` to parse reference strings like `docker.io/library/ubuntu:20.04@sha256:...`, enforcing the domain pattern defined by the OCI distribution specification. Additional validation occurs in [`RegistryResource.swift`](https://github.com/apple/container/blob/main/RegistryResource.swift), which verifies that registry hostnames conform to OCI standards before establishing HTTP connections.

### What authentication methods does container support for OCI registries?

The `ImagesService` authenticates via `Self.withAuthentication(ref:)`, which retrieves credentials from the macOS keychain or from the `~/.container/config.json` configuration file. The [`RegistryLogin.swift`](https://github.com/apple/container/blob/main/RegistryLogin.swift) command handles the credential storage interface, allowing users to log in to registries using standard CLI commands.

### How does container handle multi-platform OCI images?

When pulling, the service checks `ContainerizationOCI.Platform` helpers in [`DefaultPlatform.swift`](https://github.com/apple/container/blob/main/DefaultPlatform.swift) to select the appropriate manifest entry matching the requested platform (e.g., `linux/arm64`). If no platform is specified, the system defaults to the current host platform, ensuring architecture-appropriate images are retrieved from multi-arch manifests.

### What is the role of BuildKit in the container build process?

BuildKit runs as an OCI container itself, fetched via `ImagesService.pull` in [`BuilderStart.swift`](https://github.com/apple/container/blob/main/BuilderStart.swift) (lines 94-101). After unpacking the BuildKit image into a VM-level container, the system launches the daemon inside the sandbox. The CLI then forwards build contexts to this daemon, which resolves base OCI images and produces new OCI-compliant image layers according to Dockerfile instructions.