# How to Use Custom Linux Kernels with the container run Command

> Learn to use custom Linux kernels with container run. Override the default kernel at runtime using the -k or --kernel flag for flexible container environments.

- Repository: [Apple/container](https://github.com/apple/container)
- Tags: how-to-guide
- Published: 2026-06-29

---

**Override the default Linux kernel at runtime by passing the `-k` or `--kernel` flag followed by the absolute path to your kernel binary when executing `container run`.**

The Apple Container runtime ships with a default Linux kernel that is automatically downloaded and cached for macOS virtualization. However, workloads requiring specific kernel features—such as nested virtualization (`CONFIG_KVM`), custom security modules, or hardware-specific drivers—can substitute a custom kernel binary directly at launch time.

## Override the Default Kernel with the `--kernel` Flag

When you supply the `--kernel <path>` argument (or `-k` for short), the CLI bypasses the default kernel download logic and forwards the specified binary path directly to the runtime service. The runtime loads the binary from disk, appends any kernel command-line arguments from the configuration, and boots the VM backing your container.

This override is **ephemeral** for that specific container invocation unless you configure it permanently using `container machine`.

## Architecture and Source Code Implementation

### ContainerSystemConfig and Kernel Configuration

The default kernel behavior is defined in [[`ContainerSystemConfig.swift`](https://github.com/apple/container/blob/main/ContainerSystemConfig.swift)](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ContainerSystemConfig.swift). This file contains a `kernel` struct with properties for `binaryPath` and `url` that determine which kernel binary to use and where to download it if missing.

When you specify `--kernel`, the CLI overrides the `binaryPath` field for that session only, preventing the `KernelService` from downloading or referencing the default kernel.

### RuntimeConfiguration and Validation

The kernel path flows through [[`RuntimeConfiguration.swift`](https://github.com/apple/container/blob/main/RuntimeConfiguration.swift)](https://github.com/apple/container/blob/main/Sources/Services/Runtime/RuntimeClient/RuntimeConfiguration.swift), which carries the `kernel` object to the low-level runtime during container creation. Before the VM boots, the runtime validates the binary using `MachineConfig.validateKernelPath`, ensuring:

- The file exists at the specified path
- The binary matches the host architecture (currently `arm64` for Apple Silicon)

If validation fails, the command returns an error before the VM initialization begins.

### KernelService and XPC Communication

The [[`KernelService.swift`](https://github.com/apple/container/blob/main/KernelService.swift)](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Server/Kernel/KernelService.swift) manages kernel installation into the managed `kernels/` directory and exposes the default kernel via XPC. When using a custom kernel path, this service is bypassed because the binary already exists on disk.

The [[`KernelHarness.swift`](https://github.com/apple/container/blob/main/KernelHarness.swift)](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Server/Kernel/KernelHarness.swift) handles the XPC messages that receive the custom kernel path from the CLI and forward it to the virtualization layer.

## Practical Examples

Run a container with a KVM-enabled kernel for nested virtualization:

```bash

# Use a custom kernel with KVM support

container run -k /opt/kernels/vmlinux-kvm \
              --virtualization \
              --name my-vm \
              ubuntu:22.04 \
              /bin/bash -c "uname -a && dmesg | grep kvm"

```

Combine with resource limits and volume mounts:

```bash
container run -k ./vmlinux-custom \
              --virtualization \
              -c 2 -m 4G \
              --volume /tmp/data:/data \
              alpine:3.18 \
              sh -c 'ls /data && cat /proc/cpuinfo'

```

## Persisting Kernel Configuration

To persist a custom kernel across multiple container runs, use the `container machine` subcommand. This stores the kernel path in the machine's [`boot-config.json`](https://github.com/apple/container/blob/main/boot-config.json).

Create a new machine with a permanent custom kernel:

```bash
container machine create --virtualization \
                         --kernel ./vmlinux-kvm \
                         my-machine

```

Reset to the default kernel by clearing the override:

```bash
container machine set -n my-machine kernel=

```

## Validation Requirements and Constraints

Before the runtime accepts a custom kernel:

- **Architecture matching**: The kernel must be compiled for `arm64` to match Apple Silicon hosts
- **File accessibility**: The path must point to an existing file readable by the current user
- **Virtualization flag**: The `--virtualization` flag is typically required when using custom kernels with the run command

## Summary

- Pass `--kernel <path>` or `-k <path>` to `container run` to override the default Linux kernel for a single invocation
- The [[`ContainerSystemConfig.swift`](https://github.com/apple/container/blob/main/ContainerSystemConfig.swift)](https://github.com/apple/container/blob/main/Sources/ContainerPersistence/ContainerSystemConfig.swift) defines the default kernel structure, while [[`RuntimeConfiguration.swift`](https://github.com/apple/container/blob/main/RuntimeConfiguration.swift)](https://github.com/apple/container/blob/main/Sources/Services/Runtime/RuntimeClient/RuntimeConfiguration.swift) transports custom paths to the runtime
- [[`KernelService.swift`](https://github.com/apple/container/blob/main/KernelService.swift)](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Server/Kernel/KernelService.swift) manages default kernels, but is bypassed when using `--kernel`
- Use `container machine create --kernel` to persist custom kernels across container restarts
- Custom kernels must target `arm64` architecture and pass `MachineConfig.validateKernelPath` validation

## Frequently Asked Questions

### Can I use any Linux kernel binary with container run?

No, the kernel must be compiled for the `arm64` architecture to match Apple Silicon hosts. The runtime validates the binary architecture through `MachineConfig.validateKernelPath` before booting the VM. Additionally, the kernel should support the virtualization features required by the Container runtime.

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

For ephemeral overrides, simply omit the `--kernel` flag on your next `container run` command. For persistent machine configurations, run `container machine set -n <machine-name> kernel=` to clear the custom path and revert to the default kernel managed by [[`KernelService.swift`](https://github.com/apple/container/blob/main/KernelService.swift)](https://github.com/apple/container/blob/main/Sources/Services/ContainerAPIService/Server/Kernel/KernelService.swift).

### Does the custom kernel path persist across container restarts?

Only if you configure it through `container machine create` or `container machine set`. The `--kernel` flag passed directly to `container run` applies only to that specific container instance and does not modify the underlying machine configuration stored in [`boot-config.json`](https://github.com/apple/container/blob/main/boot-config.json).

### What happens if the custom kernel binary is missing or invalid?

The CLI returns a validation error before attempting to create the VM. The `MachineConfig.validateKernelPath` routine checks file existence and architecture compatibility, failing fast with a descriptive error if the kernel binary cannot be used.