How to Use Container System Properties for Default Configurations in apple/container

Container system properties in apple/container are defined in config.toml and decoded into the ContainerSystemConfig class, allowing you to override hard-coded defaults for build, container, DNS, and registry settings without modifying source code.

The apple/container repository provides a Swift-based containerization framework that relies on hierarchical configuration management. By leveraging container system properties, developers can customize default behaviors for virtual machine resources, network settings, and image registries through declarative TOML files rather than hard-coding values throughout the application.

Understanding Container System Configuration

The configuration system reads global defaults from config.toml files and decodes them into the ContainerSystemConfig struct defined in Sources/ContainerPersistence/ContainerSystemConfig.swift. This approach separates environment-specific settings from application logic, enabling portable deployments across development machines and CI pipelines.

Configuration Hierarchy and Loading Order

The framework implements a layer-by-layer loading strategy that merges configuration files in precedence order. Files are read from user-provided paths, system-wide directories, and bundled defaults, with later values overriding earlier ones. Any missing key falls back to the struct’s initialization-time defaults, ensuring the system remains functional even with partial configuration files.

Default Values and Fallback Behavior

When the TOML decoder encounters missing fields, it automatically substitutes hard-coded defaults defined directly in the Swift structs. These defaults cover critical runtime parameters:

  • Build settings: Rosetta emulation (true), CPU count (2), memory (2048mb), and builder image references
  • Container resources: CPU allocation (4) and memory limits (1g) for new containers
  • Network configuration: Optional DNS domains and subnet allocations
  • Kernel binaries: Path mappings and remote URLs for Kata Containers kernels
  • Registry endpoints: Default domain (docker.io) for unqualified image references

Loading Container System Properties Programmatically

Access container system properties in your Swift code using the asynchronous loading methods provided by the framework.

Using the Application Helper

The recommended entry point for CLI commands resides in Sources/ContainerCommands/Application.swift:

import ContainerPersistence

let systemConfig = try await Application.loadContainerSystemConfig()

This method handles file discovery, validation, and decoding automatically, returning a fully populated ContainerSystemConfig instance.

Direct Configuration Loading

For specialized use cases or custom command implementations, access the loader directly from Sources/ContainerPersistence/ConfigurationLoader.swift:

import ContainerPersistence

let systemConfig = try await ConfigurationLoader.load()

Both approaches parse the TOML hierarchy and instantiate the configuration hierarchy with appropriate fallback values.

Inspecting Loaded Defaults

Once loaded, inspect specific container system properties to determine runtime behavior:

func printDefaults() async throws {
    let cfg = try await Application.loadContainerSystemConfig()

    print("Builder CPUs:   \(cfg.build.cpus)")
    print("Builder RAM:    \(cfg.build.memory)")
    print("Container CPUs: \(cfg.container.cpus)")
    print("Container RAM:  \(cfg.container.memory)")
    print("Default DNS:    \(cfg.dns.domain ?? "none")")
    print("Kernel URL:     \(cfg.kernel.url)")
}

Customizing Default Configurations

Override container system properties by creating a custom config.toml file in the appropriate configuration directory.

Creating a Custom config.toml

Place your overrides at ~/.config/container/config.toml or specify an alternative path using the --config <path> CLI flag:

[container]
cpus = 2
memory = "2g"

[registry]
domain = "myregistry.example.com"

With this configuration, any container run command that omits --cpus or --memory inherits the specified values (2 CPUs and 2GB RAM). Image references without explicit registries automatically resolve to myregistry.example.com instead of the standard docker.io.

Configuration Precedence

The loading mechanism respects the following priority order:

  1. User-specified configuration file (via --config)
  2. User directory config (~/.config/container/config.toml)
  3. System-wide configuration
  4. Bundled default settings
  5. Hard-coded struct defaults

This layering ensures that development environments can override production defaults while maintaining safe fallbacks for undefined properties.

Key Configuration Sections

The ContainerSystemConfig struct organizes container system properties into logical domains:

Build Configuration

Controls the builder VM characteristics used during image compilation:

let defaultImage = cfg.build.image      // Builder shim image URL
let rosettaEnabled = cfg.build.rosetta  // Apple Silicon emulation

Defaults include Rosetta support for non-native images, 2 CPUs, 2048MB memory, and the official builder shim from ghcr.io/apple/container-builder-shim.

Container Resource Limits

Defines default compute allocations when running containers:

  • cpus: 4 (overridden by --cpus flag)
  • memory: 1g (overridden by --memory flag)

Kernel and VM Initialization

Specifies the Kata Containers kernel binary path (opt/kata/share/kata-containers/vmlinux-6.18.15-186) and download URL, along with the vminit boot image (ghcr.io/apple/containerization/vminit).

Network and DNS

Configure default subnets and domain suffixes for container hostnames. The DNS domain property defaults to nil unless explicitly configured.

Registry Settings

The registry.domain property determines where unqualified image names resolve, defaulting to docker.io for standard Docker Hub compatibility.

Summary

  • Container system properties are managed through config.toml files decoded into ContainerSystemConfig structs
  • Configuration loading occurs via Application.loadContainerSystemConfig() or ConfigurationLoader.load() in Sources/ContainerPersistence/
  • Default values are hard-coded in Swift structs (e.g., BuildConfig.defaultCPUs, ContainerConfig.defaultMemory) and serve as fallbacks
  • Precedence ordering allows user configs to override system settings while maintaining safe defaults
  • Key sections include build parameters, container resources, kernel paths, network settings, and registry domains

Frequently Asked Questions

Where does apple/container look for config.toml files?

The framework searches multiple locations in descending priority: first checking paths specified with --config, then user configuration directories (~/.config/container/config.toml), followed by system-wide locations, and finally bundled defaults. Any missing values fall back to the hard-coded defaults defined in ContainerSystemConfig.swift.

How do I override default CPU and memory limits for new containers?

Create a config.toml file containing a [container] section with cpus and memory keys. These values apply when running container run or container create without explicit --cpus or --memory flags. For example, setting cpus = 2 and memory = "2g" allocates 2 CPU cores and 2 gigabytes of RAM by default.

Can I change the default container registry from Docker Hub?

Yes. Set the domain property under the [registry] section in your config.toml to your private registry URL. Once configured, image references without explicit registry prefixes (such as myimage:latest instead of docker.io/myimage:latest) automatically resolve to your specified domain.

What happens if a configuration value is missing from my TOML file?

The decoder automatically falls back to the default values defined in the struct initializers within ContainerSystemConfig.swift. This design ensures that partial configuration files remain valid—you only need to specify values that differ from the built-in defaults, keeping your configuration files concise and maintainable.

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 →