
Runtime de contêineres sem root e sandbox que inicia imagens OCI com isolamento imposto pelo kernel em milissegundos, sem daemon, com perfis de recursos, allowlists de seccomp e suporte a compose para código não confiável e gerado por IA.
kern: um runtime rápido e sem root para sandbox e recursos virtuais, para qualquer carga de trabalho, incluindo código não confiável e gerado por IA.
Um contêiner real, imposto pelo kernel, em ~3.5 ms, a partir de um único binário de 1.52 MB sem daemon.
0 RAM em repouso · sem daemon, sem socket, nada para iniciar · um único binário estático, com libc como única dependência 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
Sem Windows nativo: use WSL2. Instalação.
Um único binário que gerencia recursos, dos quais o isolamento é o primeiro. É por isso que não há uma linha única para o kern em uma tabela de comparação: é um runtime de contêineres, uma sandbox, um fatiador de recursos e um executor de stacks ao mesmo tempo, em 1.52 MB e sem daemon.
pull, build a partir de um Dockerfile, commit, push,
save/load. Uma box a partir de uma imagem inicia em ~3.5 ms.--security-profile untrusted, é todo o pacote endurecido.vcpu:), memória, disco (vdisk:) e dispositivos
(vgpio:), declarados uma vez em um kern.toml e anexados pelo nome. kern run aplica os mesmos limites
a um processo no host, sem sandbox alguma. docs/RESOURCES.mdToda a árvore de dependências Rust é libc: manifestos JSON e OCI são analisados manualmente, e pull
recorre ao curl e ao tar que já estão na máquina em vez de vincular uma pilha TLS. (1.52 MB
é o build de release otimizado para tamanho; um cargo install simples a partir do código-fonte tem 1.91 MB.)
Não é um hipervisor. A fronteira é o kernel do Linux, portanto uma falha de escalonamento de privilégios no kernel é uma fuga. Docker e Podman compartilham dessa condição, e é por isso que gVisor e Firecracker existem.
Junto com o slogan, essa é uma linha vista dos dois lados: código não confiável e gerado por IA é para isso que o kern serve, porque você escolheu executá-lo e assumir o raio de impacto (chamadas de ferramenta de agentes, jobs de CI, etapas de build, células de código). Para o que ele não serve é para código hostil de desconhecidos, multilocatário, em um kernel do qual você atende outros locatários. O kern sempre inicia sem root, enquanto no Docker isso é opcional.
Não está livre do trade-off do userns. Seu isolamento é construído sobre um namespace de usuário sem privilégios, uma fonte fértil de bugs de LPE no kernel. SECURITY.md declara isso antes de qualquer alegação.
Não é uma parede ao redor do que você monta. -v $HOME:/host entrega à box o seu diretório home: uma
montagem é uma decisão de confiança que você toma, não um limite que o kern impõe. --net host e --privileged
são exclusões (opt-outs) pelo próprio nome. (O único caminho que o kern se recusa a fazer bind é o seu próprio registry de runtime.)
Não é uma reimplementação do Docker Engine. Ele fala os formatos do Docker, não a sua API: sem redes overlay, sem plugins, sem Swarm. Matriz: docs/DOCKER-COMPAT.md.
Não é um runtime Kubernetes. Sem CRI. Use containerd ou CRI-O.
Não oferece fatias de GPU. No roadmap, sem código de GPU nesta edição, então não há nada aqui para confiar ou atacar ainda.
O que ele não sabe ou ainda não faz está em OPEN_ITEMS.md, em vez de ficar para você descobrir.
O kern precisa de um kernel Linux com namespaces de usuário sem privilégios e cgroup v2. Ele roda em Linux, WSL2 e placas ARM (Raspberry Pi · Jetson · Arduino UNO Q); não há build nativo para Windows, use WSL2 (o kern acompanha um rootfs WSL pré-construído).
O caminho mais rápido é o binário de release: um único arquivo estático, sem toolchain, e o script verifica o SHA256 antes de instalá-lo.
curl -fsSL https://raw.githubusercontent.com/getkern/kern/main/install.sh | sh
Ele escolhe x86_64 ou aarch64 para você, instala em ~/.local/bin (/usr/local/bin como root, ou
KERN_INSTALL_DIR) e se recusa a instalar um download cujo checksum não confere. Verificar manualmente,
em vez disso, são duas linhas:
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
A partir do código-fonte é o outro caminho, e toda a árvore de dependências é uma única crate (libc), então é
curto: clone, build e instalação levaram 36 s em um desktop (i7-14700KF), mais tempo em uma placa ARM pequena.
# 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
Isso coloca kern em ~/.cargo/bin, que o rustup adiciona ao seu PATH (abra um novo shell, ou
source "$HOME/.cargo/env", se kern não for encontrado).
O release também acompanha um binário aarch64, um shim .exe para Windows e um rootfs WSL pré-construído, cada um
com seu próprio .sha256; a tag é assinada via GPG e tem timestamp independente (provenance/).
kern doctor diz se as boxes vão rodar aqui antes de você tentar. Placas, WSL2 e a versão longa:
docs/INSTALL.md. Perguntas comuns (Docker, bubblewrap, youki, E2B, Windows, o
modelo de ameaças): 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
Código não confiável, uma flag para o pacote:
kern box job --image python:3.12-slim --security-profile untrusted --memory 256m \
-v ./job:/w -- python3 /w/x.py
--security-profile untrusted é a allowlist seccomp + --cap-drop ALL + --read-only em uma única
flag opt-in (escreva-as manualmente se preferir); adicione --require-limits para se recusar a iniciar a menos que os
limites de memória/pids estejam realmente aplicados. Sem rede a menos que você peça, capabilities perigosas removidas,
seccomp sempre ativo. Noventa exemplos executáveis, cada um fazendo uma coisa: examples/.
Cada verbo de leitura também responde em JSON, então nada precisa analisar uma tabela:
kern ps --json | jq '.[] | select(.health == "unhealthy") | .name'
kern volume ls --json # ps · images · stats · inspect · builds · pod ls · config list · diff
O kern fala docker-compose.yml. Aponte-o para a stack que você já tem e kern compose up a executa
sem daemon e sem Docker Desktop, o mesmo no Linux, WSL2 e placas 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
Ambas as imagens oficiais iniciam, web alcança db pelo nome do serviço, e a porta é publicada no host.
Com cache quente (imagens em cache) o tier web responde em ~0.3 s, e a stack custa apenas o que postgres e adminer
realmente usam (~66 MB aqui) com zero daemon por cima, enquanto o Docker Desktop é uma VM em segundo plano antes do seu
primeiro contêiner.
Imagens oficiais que mudam para um usuário não root (postgres, redis, ...) exigem uidmap e uma linha em /etc/subuid,
e pulls de imagem de saída exigem pasta; ambos são um único apt install em uma máquina de desenvolvimento, e kern doctor
indica qualquer um deles se estiver faltando. Este é o loop de desenvolvimento local, não um orquestrador de produção: sem Swarm, sem
redes overlay.
Execute código gerado por agente ou LLM a partir do seu próprio programa com
kern-sandbox, um wrapper fino e sem dependências sobre o binário kern.
Cada chamada roda em uma box isolada nova: rede desligada, limites de memória e pid, capabilities removidas,
saída limitada e um timeout aplicado pelo próprio binding.
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 mantém um workspace entre chamadas e
um kernel() aquecido mantém um interpretador para células de sub-milissegundo (isolamento mais fraco, por escolha).display() e figuras do matplotlib
voltam capturados, como uma célula de notebook.kern-mcp): um servidor stdio sem dependências que dá ao Claude Desktop,
Cursor ou qualquer cliente MCP um interpretador de código local. Aponte o cliente para ele:{ "mcpServers": { "kern": { "command": "kern-mcp" } } }
Ferramentas: run_code (python/bash/node), write_file, read_file, list_files. Cada chamada é uma
box nova sem rede; os arquivos persistem entre chamadas em um workspace no disco. Comando de setup, imagem e as
outras opções: bindings/python/README.md.
API completa, Python e Node: bindings/python/README.md · bindings/node/README.md.
Uma fatia é declarada uma vez em ~/.config/kern/kern.toml e anexada pelo nome, a uma box com sandbox ou a
um processo sem sandbox, com o mesmo token.
Três tipos: vcpu: (CPU e memória), vdisk: (um disco de scratch com limite de tamanho) e vgpio: (nós de
dispositivos). Dois deles, e as âncoras das quais são extraídos:
[[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
Perfis compõem: vários podem ser anexados a uma box, e uma flag explícita vence o valor do próprio perfil. Cada
chave é escrita como sua flag de CLI, então cpus é --cpus e memory é --memory. Um backend que nomeia
um pool não declarado é recusado quando a configuração é lida, não quando a box roda.
docs/RESOURCES.md tem o esquema campo a campo.
Um vdisk: é um tmpfs com suporte em RAM quando o kern roda sem root, diga o que disser seu backend, e uma
imagem ext4-on-loop com cota real quando roda com privilégios. O kern informa qual você obteve, por
perfil, em vez de deixar você supor, e o limite de tamanho é aplicado de qualquer forma.
vgpio: é granular por chip, não por linha. Pedir pins vincula o /dev/gpiochipN inteiro, e
esse dispositivo de caracteres expõe todas as linhas daquele controlador. pins = [17] não restringe a box
à linha 17: o kernel não tem uma fronteira de montagem por linha, então a lista de pinos é metadados cooperativos, não
uma fronteira. Nomear um nó de dispositivo, como i2c faz acima, concede esse nó e nada mais.
Intel i7-14700KF, Linux 7.0.0, o binário de release, um script que você pode executar:
python3 examples/benchmark.py. O seu vai variar conforme sua CPU, kernel e filesystem.
Três mil de uma vez levam ~2.2 s, e uma box ativa custa ~0.3 MB de memória.
Duas notas honestas. Ninguém vence a latência de execução única de forma absoluta: o piso para unshare + exec é
de 1 a 2 ms, então todo o topo da tabela está dentro do próprio ruído, e o bubblewrap é um lançador sem
imagens, caps ou ciclo de vida. A diferença que importa de verdade é para os engines, duas ordens de grandeza
acima.
Método, detalhamento por fase, números em placas e todas as ressalvas: BENCHMARKS.md.
Namespaces, um pivot_root, 16 capabilities perigosas removidas antes do exec, uma allowlist seccomp
sempre ativa por padrão (o filtro padrão do moby menos as 35 syscalls de fuga do kern, que permanecem
com hard-kill; uma syscall fora do conjunto verificado retorna ENOSYS, e a denylist mais ampla é a exclusão
via KERN_SECCOMP=denylist), limites de cgroup v2 (--require-limits se recusa a iniciar a menos que sejam aplicados),
e um /dev com negação por padrão. Onde uma fronteira é cooperativa em vez de imposta pelo kernel,
SECURITY.md diz isso e nomeia o bypass.
Você não precisa aceitar isso por confiança: pentest/ contém quatro suítes adversariais que validam essas fronteiras contra o kernel, e não contra o próprio relato do kern, e elas rodam sem uma conta de registry ou rede.
sh pentest/run-with-local-registry.sh ./target/release/kern pentest/pentest-ports.sh
Reporte uma vulnerabilidade de forma privada por meio do GitHub Security Advisories ou [email protected].
O núcleo está pronto. Tudo acima funciona hoje: 840 testes Rust, 78 Python e 61 Node,
clippy-clean, cargo-deny-clean, em hardware real: Linux, WSL2, Raspberry Pi 5, Jetson Orin Nano,
Arduino UNO Q. v0.7.0 é o primeiro release publicado. A superfície de CLI e configuração ainda pode
mudar, sempre anunciado em CHANGELOG.md.
Issues e pull requests são bem-vindos. CONTRIBUTING.md tem o fluxo de trabalho e os gates; as contribuições são cobertas pelo CLA.
Alex, @realexhub. Os commits vêm de @getkerndev, a identidade de commits do projeto.
Os commits não são assinados; a TAG do release é. É isso que deve ser verificado:
git verify-tag v0.7.0 contra a chave em provenance/, cuja impressão digital está em
SECURITY.md.
Apache-2.0. Veja LICENSE e TRADEMARK.md.
kern compose <file> up aceita um kern-compose.toml
(tabelas [box.NAME], com os perfis de recursos acima) ou o docker-compose.yml que você já tem,
lido como está. Uma stack para um pod, com serviços que se encontram pelo nome.ps, logs, exec, stats, inspect, wait, top (uma TUI ao vivo),
doctor, além de um SDK para Python e Node e um servidor MCP para agentes.| kern | Docker | Podman |
|---|
| Daemon | não | sim (dockerd + containerd) | não |
| Rootless | sim, sempre | opt-in | sim |
| Cold start, box pura | ~2.3 ms | ~297 ms | ~293 ms |
| Cold start, a partir de uma imagem OCI | ~3.5 ms | ~297 ms | ~293 ms |
| Parar um serviço (init lida com SIGTERM) | ~1.9 ms | ~310 ms | ~380 ms |
| Memória residente, nada em execução | 0 | 154 a 160 MB | 0 |
| Ocupação | um binário de 1.52 MB | stack de daemons | instalação multi-binário |
| Imagens OCI, pull / build / push | sim | sim | sim |
docker-compose.yml | sim, lido como está | sim | parcial |
| Redes overlay, Swarm, CRI | não | sim | parcial |
| GPU | no roadmap | sim | sim |
| kern | bubblewrap | runc | podman | docker |
|---|
| Cold start (box pura) | ~2.3 ms | ~2.3 ms | ~18.6 ms | ~293 ms | ~297 ms |
| 200 boxes em paralelo | ~0.11 s | ~0.16 s | ~0.35 s | ~44.8 s | ~16.2 s |
| docs/INSTALL.md | instalação no Linux, WSL2 e placas ARM, a partir do código-fonte |
| docs/DOCKER-COMPAT.md | o que do Docker funciona, o que não funciona e onde difere |
| docs/RESOURCES.md · docs/CONFIG.md · docs/STORAGE.md · docs/EGRESS.md | o modelo de dois verbos, o esquema kern.toml, volumes e egress |
| docs/THREAT_MODEL.md · SECURITY.md · OPEN_ITEMS.md | o modelo de ameaças (estruturado, depois por mecanismo) e as lacunas conhecidas |
| BENCHMARKS.md · EDGE.md | medições, e execução em um Pi, Jetson ou UNO Q |
| examples/ · blog/ | noventa scripts executáveis e artigos mais longos |
| bindings/python/README.md · bindings/node/README.md | o SDK kern-sandbox: incorpore o kern em Python ou Node |