How to Use Custom Kernels and Enable Nested Virtualization in Container Machine

To run nested virtual machines inside Container Machine, enable the virtualization flag and provide a custom Linux kernel built with KVM support, then apply these settings via the CLI or TOML configuration.

Container Machine, part of the apple/container repository, runs Linux containers inside a lightweight VM on macOS. By default, it uses a generic kernel without nested virtualization support. This guide explains how to use custom kernels and enable nested virtualization using the KernelConfig and MachineConfig structures defined in the source code.

Understanding Kernel Configuration

The runtime determines which kernel to load by reading two primary configuration structures.

Default Kernel Settings (ContainerSystemConfig.swift)

The KernelConfig struct in [Sources/ContainerPersistence/ContainerSystemConfig.swift](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ContainerSystemConfig.swift#L67-L86) defines the default kernel download URL and binary path. These fields are used when the runtime installs a fresh kernel archive.

Per-Machine Overrides (MachineConfig.swift)

Individual machine settings, including the virtualization boolean and optional kernelPath, are stored in [Sources/ContainerPersistence/MachineConfig.swift](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/MachineConfig.swift#L55-L88). The decoder sets virtualization to false when the flag is omitted.

Enabling Nested Virtualization

Nested virtualization requires Apple Silicon M3 or later and macOS 15 or newer. When you pass the --virtualization flag, the runtime sets virtualization=true in the machine configuration, which exposes /dev/kvm inside the VM.

Configuring a Custom Kernel

To override the default kernel, provide a path to a KVM-enabled kernel binary compiled with CONFIG_KVM=y. You can specify this via the --kernel CLI flag or the kernel field in the configuration file. Setting kernel= (empty) reverts to the default.

Step-by-Step Implementation

Create a new machine with a custom kernel and virtualization enabled:

container machine create \
    --virtualization \
    --kernel /path/to/vmlinux-kvm \
    --name kvm-dev \
    alpine:latest

Verify that KVM is exposed inside the VM:

container machine run -n kvm-dev -- ls -l /dev/kvm

Enable nested virtualization on an existing machine:

container machine set -n dev virtualization=true kernel=/path/to/vmlinux-kvm
container machine stop dev
container machine run -n dev -- ls -l /dev/kvm

Reset to the default kernel:

container machine set -n dev kernel=

Configuration File Options

Persist these settings in config.toml under the [machine] table:

[machine]
virtualization = true
kernel = "/opt/kernels/vmlinux-kvm"

Documentation for these flags appears in docs/container-machine.md and the command reference in docs/command-reference.md.

Summary

Frequently Asked Questions

What hardware is required for nested virtualization?

Nested virtualization requires Apple Silicon M3 or later and macOS 15 or newer. The runtime checks these requirements when you enable the virtualization flag.

How do I revert to the default kernel after using a custom one?

Set the kernel path to an empty value using container machine set -n <name> kernel= or remove the kernel line from your config.toml. This causes the runtime to fall back to the default KernelConfig binary.

Where are the default kernel URLs defined?

The default kernel download URL and binary path are defined in the KernelConfig struct within [Sources/ContainerPersistence/ContainerSystemConfig.swift](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ContainerSystemConfig.swift#L67-L86).

Can I use nested virtualization without a custom kernel?

No. The default Kata Containers kernel shipped with Container Machine does not include CONFIG_KVM=y. You must provide a custom kernel binary that includes KVM support to expose /dev/kvm inside the virtual machine.

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 →