
Rootless-рантайм контейнеров и песочница, запускающая OCI-образы с принудительной изоляцией на уровне ядра за миллисекунды без демона, с профилями ресурсов, разрешающими списками seccomp и поддержкой compose для недоверенного и сгенерированного ИИ кода.
kern: быстрый sandbox без root и среда виртуальных ресурсов для любых нагрузок, включая недоверенный и ИИ-сгенерированный код.
Настоящий контейнер, обеспечиваемый ядром, за ~3,5 мс — из одного бинарника размером 1,52 МБ и без демона.
0 RAM в состоянии покоя · нет демона, нет сокета, нечего запускать · один статический бинарник, libc — его единственная Rust-зависимость
# install the release binary (static, 1.52 MB, checksum-verified by the script)
curl -fsSL https://raw.githubusercontent.com/getkern/kern/main/install.sh | sh
# a throwaway shell in a real OCI image: rootless, kernel-enforced, a few ms
kern box dev --image alpine -it -- sh
Нет нативной Windows: используйте WSL2. Установка.
Один бинарник, который управляет ресурсами, и изоляция — первая среди них. Поэтому в сравнительной таблице у kern нет отдельной строки: это одновременно container runtime, песочница, разделитель ресурсов и исполнитель стеков — в 1,52 МБ и без демона.
pull, build из Dockerfile, commit, push, save/load. Box из образа запускается за ~3,5 мс.--security-profile untrusted, — это весь укреплённый комплект.vcpu:), память, диск (vdisk:) и устройства (vgpio:), объявленные один раз в kern.toml и подключаемые по имени. kern run применяет те же ограничения к процессу на хосте и вовсе без песочницы. docs/RESOURCES.mdВсё дерево Rust-зависимостей — это libc: JSON и OCI-манифесты разбираются вручную, а pull обращается к уже установленным в системе curl и tar вместо того, чтобы линковать TLS-стек. (1,52 МБ — это оптимизированная по размеру release-сборка; обычный cargo install из исходников даёт 1,91 МБ.)
Не гипервизор. Граница — это ядро Linux, поэтому ошибка повышения привилегий в ядре означает побег. Docker и Podman находятся в том же положении, поэтому и существуют gVisor и Firecracker.
Если прочитать вместе с теглайном, это одна строка, видимая с двух сторон: недоверенный и ИИ-сгенерированный код — это то, ДЛЯ ЧЕГО kern создан, потому что вы сами решили его запускать и берёте на себя радиус поражения (вызовы инструментов агента, CI-задачи, шаги сборки, ячейки кода). Он не предназначен для враждебного кода от незнакомцев, в мультиарендном режиме, на ядре, с которого вы обслуживаете других арендаторов. kern всегда запускается без root, тогда как у Docker это опция.
Не свободен от компромисса userns. Его изоляция построена на непривилегированном пользовательском namespace — плодородном источнике LPE-багов ядра. SECURITY.md заявляет это раньше любых утверждений.
Не стена вокруг того, что вы монтируете внутрь. -v $HOME:/host отдаёт box ваш домашний каталог: монтирование — это решение о доверии, которое принимаете вы, а не граница, которую обеспечивает kern. --net host и --privileged — это отказ от защиты по собственному имени. (Единственный путь, который kern отказывается монтировать, — это его собственный runtime registry.)
Не переписанный Docker Engine. Он говорит на форматах Docker, а не на его API: нет overlay-сетей, плагинов и Swarm. Матрица: docs/DOCKER-COMPAT.md.
Не Kubernetes runtime. Нет CRI. Используйте containerd или CRI-O.
Не поставляет GPU-слайсы. Это в дорожной карте, и в этой версии нет GPU-кода, так что здесь пока нечему доверять и нечего атаковать.
То, чего kern пока не знает или не умеет, описано в OPEN_ITEMS.md, а не оставлено на ваше самостоятельное обнаружение.
kern требует ядро Linux с непривилегированными пользовательскими namespace и cgroup v2. Работает на Linux, WSL2 и ARM-платах (Raspberry Pi · Jetson · Arduino UNO Q); нативной сборки для Windows нет — используйте WSL2 (kern поставляет готовый WSL rootfs).
Самый быстрый путь — release-бинарник: один статический файл, без тулчейна, а скрипт перед установкой проверяет его SHA256.
curl -fsSL https://raw.githubusercontent.com/getkern/kern/main/install.sh | sh
Скрипт сам выбирает x86_64 или aarch64, устанавливает в ~/.local/bin (/usr/local/bin от root или в KERN_INSTALL_DIR) и отказывается устанавливать загрузку с несовпадающей контрольной суммой. Проверка вручную вместо этого — две строки:
curl -fsSLO https://github.com/getkern/kern/releases/latest/download/kern-x86_64-unknown-linux-musl.tar.gz{,.sha256}
sha256sum -c kern-x86_64-unknown-linux-musl.tar.gz.sha256 && tar xzf kern-x86_64-unknown-linux-musl.tar.gz
Из исходников — другой путь, и всё дерево зависимостей — это один крейт (libc), так что он короткий: clone, build и install заняли 36 с на десктопе (i7-14700KF), на небольшой ARM-плате дольше.
# if you do not have Rust yet
curl --proto '=https' --tlsv1.2 -sSf https://sh.rustup.rs | sh
cargo install --git https://github.com/getkern/kern getkern --locked
Это помещает kern в ~/.cargo/bin, который rustup добавляет в ваш PATH (откройте новую оболочку или выполните source "$HOME/.cargo/env", если kern не находится).
Релиз также включает aarch64-бинарник, Windows-шим .exe и готовый WSL rootfs, каждый со своим .sha256; тег подписан GPG и независимо заверен временной меткой (provenance/).
kern doctor сообщает, будут ли box работать здесь, ещё до попытки. Платы, WSL2 и подробная форма: docs/INSTALL.md. Частые вопросы (Docker, bubblewrap, youki, E2B, Windows, модель угроз): docs/FAQ.md.
kern box dev --image alpine -it -- sh # a throwaway shell in a real OCI image
kern run --memory 256M --cpus 0.5 -- ./crunch # cap a process, no sandbox
kern box svc --image nginx:alpine -d -p 8080:80 \ # a service: published, restarted, health-checked
--restart --health-cmd 'wget -qO- localhost:80' -- nginx -g 'daemon off;'
kern ps # what is running, with PORTS and HEALTH
kern exec svc -it -- sh # shell into it
kern stop svc # its signal, its grace, then the code it exited with
kern top # live TUI: boxes, CPU/RAM, profiles, volumes
kern compose stack.toml up # a multi-box stack (examples/) or a compose.yml
kern compose stack.toml down # and take it down again
Недоверенный код — один флаг для всего комплекта:
kern box job --image python:3.12-slim --security-profile untrusted --memory 256m \
-v ./job:/w -- python3 /w/x.py
--security-profile untrusted — это seccomp allowlist + --cap-drop ALL + --read-only в одном опциональном флаге (можете перечислить их вручную, если хотите); добавьте --require-limits, чтобы отказаться от запуска, если лимиты памяти/pids реально не применяются. Нет сети, пока не попросите, опасные capabilities сброшены, seccomp всегда включён. Девяносто запускаемых примеров, каждый делает одно дело: examples/.
Каждая команда чтения также отвечает в JSON, так что никому не нужно разбирать таблицу:
kern ps --json | jq '.[] | select(.health == "unhealthy") | .name'
kern volume ls --json # ps · images · stats · inspect · builds · pod ls · config list · diff
kern понимает docker-compose.yml. Укажите ему на уже имеющийся у вас стек, и kern compose up запустит его без демона и без Docker Desktop — одинаково на Linux, WSL2 и ARM-платах.
# compose.yaml - a real stack, unchanged
services:
db:
image: postgres:alpine
environment: { POSTGRES_PASSWORD: secret, POSTGRES_DB: app }
web:
image: adminer
ports: ["8080:8080"]
depends_on: [db]
kern compose compose.yaml up
Оба официальных образа запускаются, web обращается к db по имени сервиса, а порт публикуется на хосте. В тёплом режиме (образы закэшированы) веб-уровень отвечает за ~0,3 с, а стек стоит ровно столько, сколько реально потребляют postgres и adminer (~66 МБ здесь), с нулевым демоном сверху — тогда как Docker Desktop — это фоновая ВМ ещё до вашего первого контейнера.
Официальным образам, которые переходят на non-root пользователя (postgres, redis, ...), нужны uidmap и строка в /etc/subuid, а исходящим загрузкам образов нужен pasta; и то и другое — один apt install на dev-машине, и kern doctor назовёт недостающее. Это локальный цикл разработки, а не production-оркестратор: никакого Swarm и overlay-сетей.
Запускайте код, сгенерированный агентом или LLM, из своей программы с помощью kern-sandbox — тонкой обёртки без зависимостей поверх бинарника kern. Каждый вызов выполняется в свежем изолированном box: сеть отключена, лимиты памяти и pid, capabilities сброшены, выходные данные ограничены, плюс таймаут, который обеспечивает сама обёртка.
pip install kern-sandbox # PyPI · needs the `kern` binary above, on PATH or $KERN_BIN
npm install kern-sandbox # npm · same
from kern_sandbox import run_code
r = run_code("import platform; print(platform.python_version())")
print(r.stdout) # ran in a fresh box; a timeout / OOM / blocked escape is data on r.fault
Sandbox сохраняет рабочее пространство между вызовами, а тёплый kernel() держит один интерпретатор для ячеек на доли миллисекунды (более слабая изоляция — осознанный выбор).display() и фигуры matplotlib возвращаются в захваченном виде, как ячейка ноутбука.kern-mcp): сервер stdio без зависимостей, который даёт Claude Desktop, Cursor или любому MCP-клиенту локальный интерпретатор кода. Укажите на него клиенту:{ "mcpServers": { "kern": { "command": "kern-mcp" } } }
Инструменты: run_code (python/bash/node), write_file, read_file, list_files. Каждый вызов — свежий box без сети; файлы сохраняются между вызовами в рабочем пространстве на диске. Команда настройки, образ и остальные опции: bindings/python/README.md.
Полный API, Python и Node: bindings/python/README.md · bindings/node/README.md.
Слайс объявляется один раз в ~/.config/kern/kern.toml и подключается по имени — либо к песочнице box, либо к голому процессу, одним и тем же токеном.
Три вида: vcpu: (CPU и память), vdisk: (временный диск с ограничением размера) и vgpio: (узлы устройств). Два из них и якоря, из которых они выделяются:
[[cpu]] # the host budget a slice is carved from
id = "cpu:0"
cores = 8.0
[[vcpu]] # 1.5 cores and 512 MiB -> attach as vcpu:heavy
name = "heavy"
backend = "cpu:0"
cpus = 1.5
memory = "512m"
[[gpio]] # a controller anchor
id = "gpio:0"
[[vgpio]] # exactly one device node -> attach as vgpio:sensor
name = "sensor"
backend = "gpio:0"
i2c = ["/dev/i2c-1"]
kern validate ~/.config/kern/kern.toml # check it before anything runs
kern box train --image alpine vcpu:heavy vdisk:scratch -- ./train.sh
kern run vcpu:heavy -- ./train.sh # the same slice, no sandbox
kern box iot --image alpine vgpio:sensor -- ls /dev
Профили компонуются: несколько могут подключаться к одному box, и явный флаг переопределяет значение из профиля. Каждый ключ называется так же, как его CLI-флаг, поэтому cpus — это --cpus, а memory — это --memory. Если backend называет необъявленный пул, отказ происходит при чтении конфига, а не при запуске box. docs/RESOURCES.md содержит схему по полям.
vdisk: — это tmpfs на RAM, когда kern работает без root, независимо от того, что говорит backend, и образ ext4-on-loop с реальной квотой, когда он работает с привилегиями. kern сообщает, какой именно вариант вы получили, для каждого профиля, а не даёт вам предполагать; ограничение размера соблюдается в любом случае.
vgpio: работает на уровне чипа, а не отдельной линии. Запрос pins привязывает весь /dev/gpiochipN, и это символьное устройство открывает все линии контроллера. pins = [17] не ограничивает box линией 17: у ядра нет границы монтирования на уровне линии, поэтому список пинов — это кооперативная метаинформация, а не граница. Именование узла устройства, как i2c выше, предоставляет этот узел и ничего больше.
Intel i7-14700KF, Linux 7.0.0, release-бинарник; один скрипт, который вы можете запустить сами: python3 examples/benchmark.py. Ваши результаты будут отличаться в зависимости от CPU, ядра и файловой системы.
Три тысячи одновременно занимают ~2,2 с, а живой box стоит ~0,3 МБ памяти.
Две честные заметки. Никто не выигрывает вчистую по разовой задержке: нижняя граница для unshare + exec — 1–2 мс, так что весь верхний ярус находится в пределах собственного шума, а bubblewrap — это запускатель без образов, caps и жизненного цикла. Значимый разрыв — с движками, на два порядка выше.
Методика, разбивка по фазам, цифры для плат и все оговорки: BENCHMARKS.md.
Namespaces, pivot_root, 16 опасных capabilities сбрасываются до exec, всегда включённый seccomp allowlist по умолчанию (собственный фильтр moby по умолчанию за вычетом 35 escape-сисколлов kern, которые остаются жёстко убитыми; системный вызов вне проверенного набора возвращает ENOSYS, а более широкий denylist включается отказом через KERN_SECCOMP=denylist), лимиты cgroup v2 (--require-limits отказывается запускаться, если они не применяются) и /dev с запретом по умолчанию. Там, где граница кооперативна, а не обеспечивается ядром, SECURITY.md говорит об этом и называет способ обхода.
Вам не обязательно верить на слово: в pentest/ четыре adversarial-набора, которые проверяют эти границы против самого ядра, а не против собственной отчётности kern; они запускаются без учётной записи в registry и без сети.
sh pentest/run-with-local-registry.sh ./target/release/kern pentest/pentest-ports.sh
Сообщайте об уязвимостях конфиденциально через GitHub Security Advisories или [email protected].
Ядро готово. Всё, что описано выше, работает уже сегодня: 840 тестов на Rust, 78 на Python и 61 на Node, clippy-clean, cargo-deny-clean, на реальном железе: Linux, WSL2, Raspberry Pi 5, Jetson Orin Nano, Arduino UNO Q. v0.7.0 — первый опубликованный релиз. CLI и поверхность конфигурации ещё могут меняться, и об этом всегда сообщается в CHANGELOG.md.
Принимаются issues и pull request'ы. CONTRIBUTING.md содержит процесс и контрольные точки; вклад регулируется CLA.
Alex, @realexhub. Коммиты исходят от @getkerndev — коммит-личности проекта.
Коммиты не подписаны; подписан релизный ТЕГ. Проверять нужно именно его: git verify-tag v0.7.0 ключом из provenance/, чей отпечаток указан в SECURITY.md.
Apache-2.0. См. LICENSE и TRADEMARK.md.
kern compose <file> up принимает kern-compose.toml (таблицы [box.NAME] с профилями ресурсов выше) или уже имеющийся у вас docker-compose.yml, читаемый как есть. Один стек — один pod, сервисы находят друг друга по имени.ps, logs, exec, stats, inspect, wait, top (живой TUI), doctor, плюс Python- и Node-SDK и MCP-сервер для агентов.| kern | Docker | Podman |
|---|
| Демон | нет | да (dockerd + containerd) | нет |
| Без root | да, всегда | опционально | да |
| Холодный старт, голый box | ~2.3 ms | ~297 ms | ~293 ms |
| Холодный старт из OCI-образа | ~3.5 ms | ~297 ms | ~293 ms |
| Остановка сервиса (init обрабатывает SIGTERM) | ~1.9 ms | ~310 ms | ~380 ms |
| Резидентная память, ничего не запущено | 0 | 154 to 160 MB | 0 |
| Занимаемое место | один бинарник 1.52 MB | стек демона | установка из нескольких бинарников |
| OCI-образы, pull / build / push | да | да | да |
docker-compose.yml | да, читается как есть | да | частично |
| Overlay-сети, Swarm, CRI | нет | да | частично |
| GPU | в дорожной карте | да | да |
| kern | bubblewrap | runc | podman | docker |
|---|
| Холодный старт (голый box) | ~2.3 ms | ~2.3 ms | ~18.6 ms | ~293 ms | ~297 ms |
| 200 box параллельно | ~0.11 s | ~0.16 s | ~0.35 s | ~44.8 s | ~16.2 s |
| docs/INSTALL.md | установка на Linux, WSL2 и ARM-платы, из исходников |
| docs/DOCKER-COMPAT.md | что из Docker работает, что нет и где отличия |
| docs/RESOURCES.md · docs/CONFIG.md · docs/STORAGE.md · docs/EGRESS.md | модель двух глаголов, схема kern.toml, тома и egress |
| docs/THREAT_MODEL.md · SECURITY.md · OPEN_ITEMS.md | модель угроз (структурированно, затем по механизмам) и известные пробелы |
| BENCHMARKS.md · EDGE.md | измерения и работа на Pi, Jetson или UNO Q |
| examples/ · blog/ | девяносто запускаемых скриптов и подробные статьи |
| bindings/python/README.md · bindings/node/README.md | SDK kern-sandbox: встраивание kern в Python или Node |