nanemu — минималистичная обертка для упрощения запуска на ядре Linux ELF-бинарников в QEMU.
Проект предназначен для:
- ⚙️ Запуск кода на ядре Linux с минимальной настройкой (нужен только путь к папке с бинарями)
- 🔬 Тестирования кода использующего низкоуровневые механизмы ОС, такие как eBPF, системные вызовы и т.п.
- 🧪 Отладки поведения кода, поведение которого зависит от архитектуры и версии ядра Linux
⚡ Субсекундное время запуска на хост-системах с аппаратной поддержкой виртуализации и минималистичным ядром Linux.
- Установите QEMU
Для Alpine / Debian / Ubuntu:
sudo apt install qemu-system qemu-user-staticОфициальная документация: QEMU installation guide
- Установите
nanemu
GOBIN=$GOPATH/bin go install github.com/ebirukov/nanemu/cmd/nanemu@latest- Скачайте ядро Linux (Опционально)
Например, для Alpine ARM64:
https://dl-cdn.alpinelinux.org/alpine/edge/releases/
🔧 **Запуск одиночного файла init:**default
nanemu rootfs/initnanemu -kernel kernel/arm64/linux-5.10.0-32-arm64 -arch arm64 rootfs/ init🖥 Запуск с кастомными параметрами:
QEMU_BIN=/usr/bin/qemu-system-amd64 \
KERNEL_ARGS="initrd=/mybin cma=0 audit=0 nowatchdog nosmp maxcpus=1 ipv6.disable=1 net.ifnames=0 lsm= acpi=off ima_appraise=off" \
nanemu \
-kernel kernel/amd64/linux-6.1.0-35-amd64 \
-arch arm64
-timeout 10s
build/amd64/initramfs| Флаг | Тип | Описание |
|---|---|---|
-kernel |
string |
Путь к образу ядра Linux (обязательный, либо ENV KERNEL_PATH) |
-arch |
string |
Целевая архитектура (по умолчанию: GOARCH) |
-timeout |
duration |
Максимальное время выполнения QEMU (по умолчанию: 30m) |
-loglevel |
string |
Уровень логирования при загрузке ядра (по умолчанию: 3) |
-initrd |
string |
Создать образ диска начальной файловой системы initramfs (в формате cpio) |
-memory |
string |
Размер памяти выделяемой QEMU |
-smp |
string |
Кол-во ядер процессора выделямых QEMU |
| Переменная | Описание |
|---|---|
QEMU_BIN |
Путь к исполняемому файлу QEMU (по умолчанию: qemu-system-$ARCH) |
QEMU_ARGS |
Дополнительные аргументы, передаваемые напрямую в QEMU |
KERNEL_ARGS |
Дополнительные параметры загрузки ядра |
- 🚀 Субсекундный запуск при использовании аппаратной поддержки виртуализации и минимальных ядрах
- 🏗 Автоматически создаёт временный образ диска с фалйовой системой
ext4(при наличии модуля ядра VIRTIO_BLK), либоinitramfs(в форматеcpio) - 🧼 Автоматическая очистка временных файлов после завершения
- 🛠 Поддержка архитектур
amd64иarm64
- Возьмем hello linux программу:
package main
import (
"fmt"
"os"
"syscall"
"unsafe"
)
func main() {
var uts syscall.Utsname
syscall.Uname(&uts)
osVersion := unsafe.String((*byte)(unsafe.Pointer(&uts.Release[0])), len(uts.Release))
fmt.Printf(
"Hello from process %d on linux kernel version: %s\n", os.Getpid(), osVersion)
syscall.Reboot(syscall.LINUX_REBOOT_CMD_POWER_OFF)
}- Скомпилируем под нужную архитектуру:
GOOS=linux GOARCH=arm64 go build -o build/hello-arm64 ./cmd/hello- Запускаем с помощью
nanemu:
nanemu \
-kernel https://dl-cdn.alpinelinux.org/alpine/edge/releases/aarch64/netboot/vmlinuz-virt \
-arch arm64 \
-loglevel 6 \
-initrd \
example/build/hello-arm64- Пример вывода:
2026/01/26 12:49:47 executing: /usr/bin/qemu-system-arm64 -serial mon:stdio -machine virt -cpu cortex-a53 -nographic -no-reboot -append rdinit=/hello-arm64 console=ttyAMA0 loglevel=6 -kernel kernel/vmlinuz-5.4.43-1-arm64 -initrd ./initramfs.cpio718173793
2026/01/26 12:49:47 process /usr/bin/qemu-system-arm64 started with pid: 2177874
[ 0.000000] Linux version 6.18.7-0-virt (buildozer@build-edge-aarch64) (cc (Alpine 15.2.0) 15.2.0, GNU ld (GNU Binutils) 2.45.1) #1-Alpine SMP PREEMPT_DYNAMIC 2026-01-26 12:49:47
[ 0.000000] Kernel command line: rdinit=/hello-arm64 console=ttyAMA0 loglevel=6
Hello from process 1 on linux kernel version: 6.18.7-0-virt
[ 0.558718] reboot: Power down
2026/02/22 14:15:02 exit with code: 0
Механизм extensions позволяет динамически расширять параметры запуска nanemu, добавляя собственные опции QEMU без изменения исходного кода.
Каждое расширение представляет собой отдельный файл в каталоге:
$HOME/.nanemu/extension/
Имя файла определяет флаг запуска, а содержимое файла — шаблон аргументов, добавляемых при выполнении QEMU.
При старте nanemu сканирует папку:
$HOME/.nanemu/extension/
Для каждого найденного файла создаётся дополнительный CLI-флаг.
При указании этого флага при запуске nanemu, его содержимое автоматически подставляется в параметры QEMU.
Пример:
файл console-unix создаёт флаг -console-unix.
Если при запуске nanemu указать этот флаг, в QEMU будут добавлены аргументы из содержимого файла.
-
Создайте каталог для расширений (если его ещё нет):
mkdir -p $HOME/.nanemu/extension -
Добавьте файл
console-unixсо следующим содержимым:# Подключение UNIX-сокета для консоли -chardev socket,path=%s,server=on,wait=off,id=unix0 -device virtio-serial-pci -device virtserialport,chardev=unix0,name=unix.sock -
Запустите
nanemu, указав новый флаг:nanemu \ -kernel ../vmlinuz-amd64 \ -rootfs ./build \ -console-unix /tmp/qemu.sock ...
👉 В результате
nanemuавтоматически добавит указанные строки в параметры запуска QEMU.
Каждый файл может содержать одну или несколько строк — шаблонов аргументов QEMU.
В шаблоне можно использовать подстановку %s — она будет заменена на значение, переданное через одноимённый CLI-флаг.
Пример:
файл $HOME/.nanemu/extension/port-fwd
# Проброс TCP-порта
-netdev user,id=net0,hostfwd=%s
-device virtio-net-pci,netdev=net0Запуск:
nanemu -kernel vmlinuz -rootfs build -port-fwd tcp::8080-:22Результат — в QEMU автоматически подставятся аргументы:
-netdev user,id=net0,hostfwd=tcp::8080-:22
-device virtio-net-pci,netdev=net0
-
Расширения можно создавать под разные архитектуры, добавив суффикс в имени файла. Например:
usernet-amd64 usernet-arm64В этом случае флаг
-usernetбудет активен только при запуске на соответствующей архитектуре. -
Комментарии внутри файла (
#или//) автоматически попадают в описание флага и отображаются при-h.
| Имя файла | Назначение |
|---|---|
console-unix |
Привязка консоли QEMU к UNIX-сокету хоста |
port-fwd |
Проброс TCP/UDP портов через -netdev user |
usernet |
Конфигурация встроенной NAT-сети QEMU (user mode) |