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:
- User-specified configuration file (via
--config) - User directory config (
~/.config/container/config.toml) - System-wide configuration
- Bundled default settings
- 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--cpusflag) - memory:
1g(overridden by--memoryflag)
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.tomlfiles decoded intoContainerSystemConfigstructs - Configuration loading occurs via
Application.loadContainerSystemConfig()orConfigurationLoader.load()inSources/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:
curl -s "https://instagit.com/install.md" Maintain an open-source project? Get it listed too →