What Is the Purpose of `--init-image` in Apple Container?
The --init-image flag lets you replace the default vminit init filesystem image in the lightweight VM with a custom one, enabling you to execute boot-time logic before the OCI container’s first process starts.
The apple/container project provides a lightweight virtualization runtime for OCI containers that uses a minimal VM to host workloads. Understanding the --init-image flag is essential when you need to customize the initialization sequence that runs inside the VM but outside the container environment itself.
What Is the --init-image Flag?
The --init-image flag is a runtime option for the container run and container create commands. According to the command reference in docs/command-reference.md (line 57), this flag accepts a container image reference that overrides the default init filesystem image used by the lightweight VM.
By default, the VM launches a minimal init process called vminitd that only forwards signals and reaps orphaned processes. When you specify --init-image <image>, the runtime swaps this default image for your custom one, which can execute a wrapper binary before handing control to the standard vminitd.real.
Why Use a Custom Init Image?
Boot-Time Initialization
Custom init images allow you to add logic that executes before the container starts. This is useful for launching daemons, configuring eBPF filters, or applying custom security policies at the VM level.
Additional Services
You can run out-of-band services such as logging agents, network helpers, or debugging tools that must operate outside the container’s root filesystem but inside the VM boundary.
Debugging and Instrumentation
A custom init image enables you to instrument the early boot stage by emitting custom log messages or attaching debuggers to troubleshoot boot-time failures before the container entrypoint executes.
How the Init Image Fits Into the Boot Sequence
The init image runs inside the lightweight VM but outside the OCI container itself. This architectural separation means your custom init logic does not affect the container’s filesystem layout or user-space environment, yet it retains full control over the VM’s initialization sequence.
As implemented in apple/container, the init process executes after the VM kernel boots but before the OCI container’s entrypoint is launched. This timing is critical for setting up VM-level resources that the container will depend on.
Building and Running a Custom Init Image
The following examples demonstrate how to build a custom init image and use it with the Container CLI, based on the implementation details found in docs/how-to.md (lines 558-564).
First, create a Dockerfile that wraps the default vminitd binary with custom logic:
# Build a custom init image that wraps the default vminitd
FROM ghcr.io/apple/containerization/vminit:0.33.3 AS base
FROM ghcr.io/apple/containerization/vminit:0.33.3
COPY --from=base /sbin/vminitd /sbin/vminitd.real
COPY wrapper /sbin/vminitd
Build the image using the Container CLI:
container build -t local/custom-init:latest .
Run a container with your custom init image:
container run \
--name my-container \
--init-image local/custom-init:latest \
alpine:latest \
echo "hello world"
Verify that the custom init code executed by checking the VM boot logs:
container logs --boot my-container | grep custom-init
You can also use the flag with container create for containers that you start later:
container create \
--init-image local/custom-init:latest \
--name my-prepared-container \
ubuntu:latest
container start my-prepared-container
Testing and Validation
The CLI parsing and error handling for --init-image are validated in Tests/CLITests/Subcommands/Run/TestCLIRunInitImage.swift. This test file verifies that the flag correctly accepts image references and integrates with the command-line interface, ensuring proper behavior when users specify custom init images.
Summary
- The
--init-imageflag replaces the defaultvminitinit filesystem image in the lightweight VM that hosts the container. - Custom init images execute before the OCI container starts, enabling boot-time logic, out-of-band services, and debugging capabilities.
- The init process runs inside the VM but outside the container boundary, preserving container isolation while allowing VM-level customization.
- Implementation details are documented in
docs/how-to.mdanddocs/command-reference.md, with comprehensive tests inTests/CLITests/Subcommands/Run/TestCLIRunInitImage.swift.
Frequently Asked Questions
Does the custom init image replace the container's entrypoint?
No. The custom init image runs inside the VM before the OCI container's first process starts. It does not replace the container's entrypoint or modify the container's filesystem. The init image executes vminitd (or your wrapper) in the VM context, then the container runs normally with its standard entrypoint.
Can I use any container image as an init image?
While the image must conform to the expected format (containing a valid init binary at /sbin/vminitd), you can use any image that includes the necessary vminit components. The documentation in docs/how-to.md recommends starting from the official ghcr.io/apple/containerization/vminit base image to ensure compatibility with the expected path structure and binary names.
How do I debug issues with my custom init image?
Use the container logs --boot <container-name> command to view the VM boot logs, which include output from your custom init process. This allows you to see messages emitted during the init phase before the container's main process starts, making it easier to troubleshoot boot-time failures.
Is the --init-image flag available for both container run and container create?
Yes. The flag is supported by both container run and container create commands, as verified in Tests/CLITests/Subcommands/Run/TestCLIRunInitImage.swift. When used with container create, the init image is configured but only executes when you subsequently run container start.
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 →