How to Save and Load Container Images as TAR Archives Using the Apple Container Tool
The container CLI provides image save and image load subcommands to export and import OCI images as tar archives, using XPC communication with the Container API service to stream data without external runtime dependencies.
The apple/container repository provides a native Apple ecosystem implementation for managing OCI-compliant container images. When you need to transfer images between environments or create offline backups, you can save and load container images as tar archives using the built-in command-line interface and Swift API.
Architecture of the Save and Load System
The export and import workflow operates through a distributed architecture involving command-line parsers, XPC clients, and a dedicated image service.
CLI Entry Points
The user-facing commands are implemented in Sources/ContainerCommands/Image/:
- ImageSave.swift – Handles the
container image savecommand, gathering image references, optional platform selectors, and output paths - ImageLoad.swift – Implements
container image load, accepting tar file paths or stdin input with an optional--forceflag for invalid archives
Both commands utilize ArgumentParser with @Option, @Flag, and @OptionGroup decorators to expose CLI parameters.
XPC Client Communication
The commands delegate to ClientImage.swift (Sources/Services/ContainerAPIService/Client/), which builds an XPC client via newXPCClient to communicate with the container-core-images service (ClientImage.serviceIdentifier). Requests are encoded as XPCMessage objects and dispatched through XPCClient.send.
Server-Side Archive Processing
The actual tar creation and extraction occurs in ImagesService.swift (Sources/Services/ContainerImagesService/Server/):
- For save operations, the service iterates over requested references, resolves OCI descriptors, streams layer blobs into a temporary directory, then tars the directory
- For load operations, the service receives the tar file, validates members (rejecting invalid ones unless
--forceis set), and unpacks images into the content store
Saving Container Images as TAR Archives
To export images to a portable archive format, use the image save command.
Saving to a File
Specify the output path with the --output flag:
container image save alpine:latest --output alpine.tar
If you omit --output, the archive streams to stdout, enabling compression or direct piping:
container image save alpine:latest | gzip > alpine.tar.gz
Platform-Specific Exports
The ImageSave command supports platform selection through DefaultPlatform.resolve (defined in DefaultPlatform.swift). Use --os, --arch, or --platform flags, or set the CONTAINER_DEFAULT_PLATFORM environment variable:
container image save alpine:latest --platform linux/amd64 --output alpine-amd64.tar
Loading Container Images from TAR Archives
Import previously saved archives using the image load command.
Loading from a File
Specify the input path with the --input flag:
container image load --input alpine.tar
Loading from Standard Input
When --input is omitted, the command reads from stdin:
cat alpine.tar | container image load
Handling Invalid Archives
Use the --force flag to load archives containing invalid members that would otherwise be rejected:
container image load --input corrupted.tar --force
After successful loading, the command prints loaded image references to stdout, making it easy to script subsequent operations.
Direct Piping Between Save and Load
You can pipe the output of save directly into load to transfer images without touching the filesystem:
container image save busybox:latest | container image load
This streams the tar archive through a temporary file in FileManager.default.temporaryDirectory while the ProgressBar (from ProgressBar.swift) provides visual feedback for both operations.
Programmatic API Usage
The Swift API exposed in ClientImage.swift allows programmatic access to save and load functionality.
Saving Images Programmatically
import ContainerAPIClient
import Foundation
let refs = ["alpine:latest"]
let outPath = "/tmp/alpine.tar"
try await ClientImage.save(
references: refs,
out: outPath,
platform: nil, // Uses current platform
containerSystemConfig: .default
)
Loading Images Programmatically
let result = try await ClientImage.load(
from: outPath,
force: false
)
for img in result.images {
print("Loaded image:", img.reference)
}
The ImageLoadResult struct (defined in ImageLoadResult.swift) contains the list of loaded images and any rejected members.
Implementation Details
Progress Reporting
Both commands instantiate a ProgressBar (configured with ProgressConfig) to display task progress while streaming archives to and from the server.
Temporary File Handling
When reading from stdin (ImageLoad) or writing to stdout (ImageSave), the system creates temporary tar files in FileManager.default.temporaryDirectory. Data is processed in 4 KB chunks using FileHandle operations.
Error Handling
Errors are wrapped in ContainerizationError and surfaced via the CLI's log.error mechanism and Application.exit, providing consistent error reporting across the tool.
Summary
- Use
container image saveto export OCI images as tar archives to files or stdout - Use
container image loadto import archives from files or stdin into the content store - Both commands support pipeline operations for efficient image transfer without intermediate files
- The Swift API through
ClientImage.save()andClientImage.load()provides programmatic access for automation - Server-side processing in
ImagesService.swifthandles the actual archive creation and extraction, operating entirely within the Apple container subsystem without external runtimes
Frequently Asked Questions
Can I save multiple images to a single tar archive?
Yes. The ImageSave command accepts multiple image references as arguments and bundles them into a single archive. The server-side implementation in ImagesService.swift iterates over all references and includes their resolved OCI descriptors and layer blobs in the output tar.
How does the tool handle platform-specific images?
The DefaultPlatform.resolve method in DefaultPlatform.swift processes --os, --arch, and --platform arguments, falling back to the CONTAINER_DEFAULT_PLATFORM environment variable if set. This allows you to export images for specific architectures even when running on a different host platform.
What happens if a tar archive contains invalid members during load?
By default, the load operation validates archive members and rejects invalid ones. However, you can use the --force flag (handled in ImageLoad.swift) to override this behavior and force the loading of archives containing invalid members. The ImageLoadResult will indicate which members were rejected even when forcing the load.
Is external software required to create or extract the archives?
No. The container tool manages the entire OCI image lifecycle internally. The ImagesService.swift implementation handles tar creation and extraction directly without invoking external container runtimes or command-line tools like docker or tar.
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 →