How to Start the Apple Container System Service on macOS
To start the Apple Container system service, run container system start, which registers the container-apiserver launchd agent with macOS launchd and performs health checks to ensure the API server is responsive.
The Apple Container project provides a lightweight virtualization stack for macOS. Starting the system service initializes the container-apiserver daemon through launchd, enabling container operations across the platform. This guide explains the exact mechanism implemented in the apple/container repository, from configuration loading to service registration.
Configuration Loading
Before registering the service, the CLI loads system configuration from ContainerSystemConfig.swift. According to the source in Sources/ContainerCommands/System/SystemStart.swift (lines 82-86), the command reads app-root and install-root values to determine the init image (vminit) location and default kernel settings.
The configuration persists across reboots and defines where the service stores its plist, logs, and runtime data. If you run in a custom environment or CI pipeline, you can override these paths using command-line flags.
Launchd Registration Process
The container system start command orchestrates service registration through several discrete steps implemented in Sources/ContainerCommands/System/SystemStart.swift.
Binary Resolution and Plist Creation
First, the command resolves the real path of the container-apiserver binary (lines 93-96), dereferencing symlinks to ensure code signature validation succeeds. It then constructs a LaunchPlist struct (lines 15-22) with:
- Label:
com.apple.container.apiserver - Program path: The resolved binary path
- Environment variables:
APP_ROOT,INSTALL_ROOT, and optionalLOG_ROOT - Mach service entry: For XPC communication with other components
Service Registration
The ServiceManager.register(plistPath:) method in Sources/ContainerPlugin/ServiceManager.swift writes the plist to $APP_ROOT/apiserver/plist and executes /bin/launchctl to register the service with launchd (lines 29-31). This registration makes the service survive reboots and discoverable by the networking plugin and runtime components.
Health Verification
After launchd starts the daemon, the CLI performs two validation checks defined in SystemStart.swift:
- API Server Health Check (lines 33-40): Pings the
container-apiserverto confirm responsiveness. If the check fails, the command aborts with a descriptive error before returning control to the user. - Machine API Verification (lines 44-48): Validates reachability of the machine-API server, ensuring the virtualization layer is fully operational.
Optional Initialization Steps
Depending on your environment, container system start may perform additional setup:
Init Image Handling
If the vminit init image is missing from the configured app-root, the command automatically pulls it using container image pull logic (lines 53-55). The fallback mechanism references scripts/install-init.sh to build and load the image after a temporary stop/start cycle.
Kernel Installation
Unless disabled with --disable-kernel-install, the command checks for the recommended kernel and may prompt for download via KernelSet.downloadAndInstallWithProgressBar (lines 74-95). Use --enable-kernel-install to force installation without interactive prompts.
Command Examples
Run the service using the container CLI with various options:
# Basic start - registers launchd service and launches apiserver
container system start
# Custom roots for CI or isolated environments
container system start --app-root /tmp/container-app \
--install-root /opt/container-install \
--log-root /var/log/container
# Force kernel installation without prompts
container system start --enable-kernel-install
# Debug mode with verbose logging
container system start --debug
Verification and Troubleshooting
After execution, verify the service status using standard macOS tools:
# Check if the service is loaded in launchd
sudo launchctl list com.apple.container.apiserver
If the command fails during the health-check phase, review logs in the configured LOG_ROOT directory. Common failures include code signature validation errors (when binary paths contain unresolved symlinks) or missing init images that failed to download automatically.
Summary
container system startis the primary command to start the Apple Container system service, implemented inSources/ContainerCommands/System/SystemStart.swift.- The command creates a launchd plist with label
com.apple.container.apiserverand registers it viaServiceManager.register(plistPath:)inSources/ContainerPlugin/ServiceManager.swift. - Health checks verify API server responsiveness and machine-API reachability before the command exits successfully.
- Configuration is loaded from
ContainerSystemConfig.swift, determining paths for the init image (vminit) and default kernel. - Optional flags control kernel installation (
--enable-kernel-install,--disable-kernel-install) and debug logging.
Frequently Asked Questions
What is the container-apiserver launchd agent?
The container-apiserver is the system daemon managed by launchd that handles container operations in the Apple Container stack. When you run container system start, the CLI registers this agent with label com.apple.container.apiserver, making it persistent across reboots and available for XPC communication with other system components.
Why does the command check for symlinked binary paths?
The SystemStart implementation resolves symlinks when locating the container-apiserver binary (lines 93-96) to ensure macOS code signature validation succeeds. Launchd requires the actual binary path for proper entitlements checking, so dereferencing symlinks prevents signature validation failures during service registration.
How do I start the service without installing the kernel?
Use the --disable-kernel-install flag to skip kernel checks and installation prompts. This is useful in CI environments or when managing kernel versions separately: container system start --disable-kernel-install.
Where is the launchd plist stored?
The plist is written to $APP_ROOT/apiserver/plist as implemented in ServiceManager.swift. By default, this resides within your configured application root directory, but you can customize the location using the --app-root parameter when starting the service.
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 →