How to Push a Container Image to a Registry with the Apple Container CLI

Use container image push <reference> to upload OCI-compatible images to a remote registry, with optional platform filtering via --platform, --arch, or --os flags.

The apple/container repository provides an OCI-compatible CLI tool for building, running, and managing container images. When you need to push a container image to a registry, the container image push command handles the entire workflow from local image store to registry upload. This command operates entirely locally, contacting the registry directly while authenticating via your Docker config or environment variables.

Command Syntax and Basic Usage

The push command follows a straightforward syntax that accepts an image reference as the primary argument. You can optionally specify platform constraints to push specific variants of multi-architecture images.

The basic structure is:

container image push [OPTIONS] NAME[:TAG]

Key options include:

  • --platform – Filter by platform (e.g., linux/arm64)
  • --arch – Specify architecture (e.g., arm64, amd64)
  • --os – Specify operating system (e.g., linux)

How the Push Workflow Works

The container image push command traverses several architectural layers before bytes reach the registry. Understanding this flow helps debug authentication issues and optimize upload performance.

Step 1: Command Parsing in ImagePush.swift

The entry point resides in Sources/ContainerCommands/Image/ImagePush.swift. The ImagePush struct defines the sub-command, parses user-supplied options, and captures the image reference. This module validates flags like --arch, --os, and --platform before invoking the underlying services.

Step 2: Registry Scheme Detection

Before establishing a connection, the Flags.Registry component determines whether to use HTTP or HTTPS by constructing a RequestScheme object. This logic resides around line 63 of ImagePush.swift, ensuring secure-by-default connections while allowing insecure-registry overrides for local development.

Step 3: Image Lookup via ClientImage

The ClientImage.get method in Sources/Services/ContainerAPIService/Client/ClientImage.swift retrieves the locally-stored image definition and metadata from the image store (line 384). This step validates that the image exists locally before attempting to push and retrieves the manifest and layer descriptors necessary for the upload.

Step 4: Platform Resolution

The DefaultPlatform.resolve method consolidates any --arch, --os, or --platform flags into a concrete Platform value (line 61 of ImagePush.swift). This platform filter constrains which image variant(s) will be pushed, ensuring you only upload the specific architecture required rather than the entire multi-arch manifest.

Step 5: Progress Reporting

A ProgressBar from the TerminalProgress package is instantiated and wired to the push operation (lines 66-74 of ImagePush.swift). This provides real-time, blob-by-blob progress display as the CLI streams image layers to the remote registry.

Step 6: Streaming to the Registry

The actual upload occurs through image.push, which forwards the request to the ImagesService implementation. According to Sources/Services/ContainerImagesService/Server/ImagesService.swift (line 117), this service calls imageStore.push to stream image layers to the registry using the OCI distribution specification. The architecture maintains separation between the CLI layer, network layer, and storage layer, making each component testable in isolation.

Step 7: Result Output

After successful completion, the command prints the canonical reference of the pushed image (line 81 of ImagePush.swift). This output can be piped into scripts or CI/CD logs for verification and audit purposes.

Practical Push Examples

Push a single-platform image to a remote registry:

container image push registry.example.com/fido/web-test:latest

Push only the arm64 variant of a multi-arch image:

container image push --platform arm64 \
    registry.example.com/fido/web-test:latest

Push with explicit architecture and OS flags:

container image push --arch arm64 --os linux \
    registry.example.com/fido/web-test:latest

The progress bar displays by default, showing each blob being uploaded:

container image push registry.example.com/fido/web-test:latest

# → Progress bar shows blob upload status

Summary

  • The container image push command transfers OCI-compatible images from local storage to remote registries.
  • Platform filtering works via --platform, --arch, and --os flags, implemented through DefaultPlatform.resolve in ImagePush.swift.
  • Authentication leverages Docker config files or environment variables, with registry schemes auto-detected via Flags.Registry.
  • Progress tracking uses the TerminalProgress package to display real-time blob upload status.
  • Key source files include Sources/ContainerCommands/Image/ImagePush.swift for CLI logic and Sources/Services/ContainerImagesService/Server/ImagesService.swift for the actual streaming implementation.

Frequently Asked Questions

How do I push a specific architecture to a registry?

Use the --platform flag to specify the target architecture, or combine --arch and --os for explicit control. The DefaultPlatform.resolve method in ImagePush.swift processes these flags to filter the image manifest before pushing only the matching variant.

Where does the Apple Container CLI store registry credentials?

The tool authenticates using credentials stored in your Docker config file or via environment variables. The Flags.Registry component handles the connection scheme (HTTP/HTTPS) but relies on standard Docker credential stores for authentication headers.

Can I disable the progress bar when pushing images?

The source code shows that ProgressBar from TerminalProgress is wired into the push workflow by default (lines 66-74 of ImagePush.swift). While the command reference may offer a --quiet flag, the architecture supports progress reporting as the default behavior for all push operations.

What happens if the image doesn't exist locally?

The ClientImage.get method in Sources/Services/ContainerAPIService/Client/ClientImage.swift retrieves the image from the local store before initiating the push. If the image reference cannot be found locally, the command fails at this lookup stage before attempting any network connection to the registry.

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:

Share the following with your agent to get started:
curl -s "https://instagit.com/install.md"

Works with
Claude Codex Cursor VS Code OpenClaw Any MCP Client

Maintain an open-source project? Get it listed too →