How to Expose Virtualization Capabilities to Containers for Nested Virtualization

Use the --virtualization flag when running or creating a container to expose hardware-assisted virtualization (KVM) from the host macOS system to the guest Linux VM, enabling nested virtualization for running VM-based workloads inside containers.

The apple/container project runs each container in a lightweight Linux virtual machine managed by macOS's Virtualization and vmnet frameworks. To enable nested virtualization—allowing containers to run their own VMs—you must explicitly request exposure of the host's virtualization device to the guest through the container's configuration.

Prerequisites for Nested Virtualization

Nested virtualization requires specific hardware and kernel configuration. According to the project documentation in docs/how-to.md (lines 518-520), you need an Apple Silicon M3 (or newer) Mac and a Linux kernel compiled with the appropriate virtualization options enabled, such as CONFIG_KVM.

Without these prerequisites, the guest VM cannot access the virtualization extensions even when exposed by the host, and the runtime will reject the request.

Enabling Virtualization with the --virtualization Flag

The container runtime exposes a dedicated CLI option to control virtualization capabilities. In Sources/Services/ContainerAPIService/Client/Flags.swift, the --virtualization flag is defined with the description "Expose virtualization capabilities to the container (requires host and guest support)" (lines 343-345).

When you include this flag in a container run or container create command, the runtime parses the option and stores it in the container's configuration structure.

container run \
    --name nested-vm-workload \
    --virtualization \
    --kernel /path/to/linux-kernel-with-kvm-support \
    ubuntu:latest \
    sh -c "dmesg | grep kvm"

The flag value is stored in the ContainerConfiguration struct defined in Sources/ContainerResource/Container/ContainerConfiguration.swift (lines 49-50), which contains a Boolean virtualization property that is encoded and decoded from the container's JSON/YAML manifest.

How the Configuration Propagates to the Runtime

When the container manager builds the VM configuration, it passes the virtualization setting through to the low-level runtime. In Sources/Services/RuntimeLinux/Server/RuntimeService.swift (line 993), the code assigns the configuration value to the VM config:

czConfig.virtualization = config.virtualization

This assignment propagates the request to Apple's Virtualization framework. If the host hardware and macOS version support nested virtualization, the framework forwards the virtualization-related capabilities—effectively exposing a KVM device—to the guest VM.

Verifying Virtualization Access Inside the Container

After launching a container with the --virtualization flag, you can verify that the guest Linux kernel detected the virtualization extensions. As documented in docs/how-to.md (lines 529-532), run the following command inside the container:

dmesg | grep kvm

If nested virtualization is successfully enabled, you should see output indicating the KVM driver has been detected, such as:


[    0.000000] kvm: nested=1
[    0.123456] kvm: hv_evtchn: using host event channel

This confirms that the container can access hardware-assisted virtualization to run nested VMs.

Handling Unsupported Hardware

If you attempt to use the --virtualization flag on hardware that does not support nested virtualization, the container runtime returns a specific error. As documented in docs/how-to.md (lines 525-529), the error message reads:


Error: unsupported: "nested virtualization is not supported on the platform"

This occurs when running on Apple Silicon chips older than the M3 series, or on macOS versions that lack the necessary Virtualization framework support. The runtime validates host capabilities before attempting to start the VM with virtualization extensions enabled.

Summary

  • Expose virtualization capabilities to containers using the --virtualization flag with container run or container create commands.
  • The flag is defined in Flags.swift and stored in ContainerConfiguration.swift before propagation to the runtime via RuntimeService.swift.
  • Hardware requirements include Apple Silicon M3 or newer and a Linux kernel with KVM support enabled.
  • Validation occurs at runtime; unsupported hardware produces the error "nested virtualization is not supported on the platform".
  • Verification inside the container uses dmesg | grep kvm to confirm the KVM driver is active.

Frequently Asked Questions

What hardware is required for nested virtualization with apple/container?

Nested virtualization requires an Apple Silicon M3 or newer Mac. The feature relies on hardware support in Apple's Virtualization framework that is only available on these newer chips. Additionally, you must use a Linux kernel compiled with CONFIG_KVM and related virtualization options.

How can I verify that virtualization is exposed to my container?

After starting a container with the --virtualization flag, run dmesg | grep kvm inside the container. If the output shows messages like kvm: nested=1 or references to the KVM driver initializing, the virtualization capabilities have been successfully exposed to the guest VM.

What happens if I use the --virtualization flag on unsupported hardware?

The container runtime will immediately return an error: "nested virtualization is not supported on the platform". This validation occurs in the runtime before the VM starts, preventing unnecessary resource consumption on incompatible systems.

Do I need to modify my container image to use nested virtualization?

No modifications to the container image are required, but you must provide a Linux kernel that supports KVM via the --kernel option. The container image itself should include userspace tools like QEMU or KVM utilities, but the critical requirement is that the kernel passed to the container must have virtualization support compiled in.

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 →