セキュリティ
Show HN: Kern – 1.5MBのバイナリでデーモン不要なコンテナおよびリソースランタイム
Show HN: Kern – container and resource runtime in a 1.5 MB binary, no daemon (github.com)
要約
Kernは、1.5MBの単一バイナリで動作する軽量なコンテナおよびリソースランタイムです。デーモンプロセスを必要とせず、起動が高速(約3.5ミリ秒)で、rootless(非特権ユーザー)で実行可能です。OCIイメージのサポート、リソースプロファイル(CPU、メモリ、ディスク、デバイス)、Docker Composeのサポートなどを備えています。特に、信頼できないコードやAI生成コードのサンドボックス実行に焦点を当てており、セキュリティと効率性を両立させています。
全文翻訳
kern: A fast, rootless sandbox and virtual resource runtime for any workload, including untrusted and AI-generated code. A real, kernel-enforced container in ~3.5 ms, out of one 1.52 MB binary with no daemon. 0 RAM at rest · no daemon, no socket, nothing to start · one static binary, libc its only Rust dependency
# 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
No native Windows: use WSL2.
Install.
What kern is
One binary that manages resources, of which isolation is the first. That is why there is no single row for kern in a comparison table: it is a container runtime, a sandbox, a resource slicer and a stack runner at once, in 1.52 MB with no daemon.
A real container. Real OCI images: pull, build from a Dockerfile, commit, push, save/load. A box from an image starts in ~3.5 ms.
A sandbox, always rootless. User, PID, mount, network, UTS and IPC namespaces, an overlay or read-only root pivoted in, a deny-by-default seccomp allowlist and cgroup v2 limits. One flag, --security-profile untrusted, is the whole hardened bundle.
Resource profiles, not just isolation. CPU (vcpu:), memory, disk (vdisk:) and devices (vgpio:), declared once in a kern.toml and attached by name. kern run applies the same caps to a process on the host, with no sandbox at all. docs/RESOURCES.md
Stacks, in kern's own format or in Docker's. kern compose <file> up takes a kern-compose.toml ([box.NAME] tables, with the resource profiles above) or the docker-compose.yml you already have, read as written. One stack to one pod, services reaching each other by name.
The tools around them. ps, logs, exec, stats, inspect, wait, top (a live TUI), doctor, plus a Python and Node SDK and an MCP server for agents.
Its entire Rust dependency tree is libc: JSON and OCI manifests are parsed by hand, and pull shells out to the curl and tar already on the machine rather than linking a TLS stack. (1.52 MB is the size-optimized release build; a plain cargo install from source is 1.91 MB.)
What kern is not
Not a hypervisor. The boundary is the Linux kernel, so a kernel privilege-escalation bug is an escape. Docker and Podman share that condition, which is why gVisor and Firecracker exist. Read with the tagline, that is one line seen from both sides: untrusted and AI-generated code is what kern is FOR, because you chose to run it and own the blast radius (agent tool-calls, CI jobs, build steps, code cells). What it is not for is hostile code from strangers, multi-tenant, on a kernel you serve other tenants from.
kern does start rootless always, where Docker's is opt-in. Not free of the userns trade. Its isolation is built on an unprivileged user namespace, a fertile source of kernel LPE bugs. SECURITY.md states this before any claim.
Not a wall around what you mount in. -v $HOME:/host gives the box your home directory: a mount is a trust decision you make, not a boundary kern enforces. --net host and --privileged are opt-outs by name. (The one path kern refuses to bind is its own runtime registry.)
Not a Docker Engine reimplementation. It speaks Docker's formats, not its API: no overlay networks, no plugins, no Swarm. Matrix: docs/DOCKER-COMPAT.md.
Not a Kubernetes runtime. No CRI. Use containerd or CRI-O.
Not shipping GPU slices. On the roadmap, with no GPU code in this edition, so there is nothing here to trust or to attack yet.
What it does not know or does not do yet is in OPEN_ITEMS.md rather than left for you to find.
Install
kern needs a Linux kernel with unprivileged user namespaces and cgroup v2. It runs on Linux, WSL2 and ARM boards (Raspberry Pi · Jetson · Arduino UNO Q); there is no native Windows build, use WSL2 (kern ships a pre-baked WSL rootfs).
The quickest route is the release binary: one static file, no toolchain, and the script verifies its SHA256 before installing it.
curl -fsSL https://raw.githubusercontent.com/getkern/kern/main/install.sh | sh
It picks x86_64 or aarch64 for you, installs to ~/.local/bin (/usr/local/bin as root, or KERN_INSTALL_DIR), and refuses to install a download whose checksum does not match.
Verifying by hand instead is two lines:
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
From source is the other route, and the whole dependency tree is one crate (libc), so it is short: clone, build and install took 36 s on a desktop (i7-14700KF), longer on a small ARM board.
# 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
That puts kern in ~/.cargo/bin, which rustup adds to your PATH (open a new shell, or source "$HOME/.cargo/env", if kern is not found).
The release also ships an aarch64 binary, a Windows .exe shim and a pre-baked WSL rootfs, each with its own .sha256; the tag is GPG-signed and independently timestamped (provenance/).
kern doctor tells you whether boxes will run here before you try. Boards, WSL2 and the long form: docs/INSTALL.md. Common questions (Docker, bubblewrap, youki, E2B, Windows, the threat model): docs/FAQ.md.
Quickstart
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
Untrusted code, one flag for the bundle: kern box job --image python:3.12-slim --security-profile untrusted --memory 256m \
-v ./job:/w -- python3 /w/x.py --security-profile untrusted is the seccomp allowlist + --cap-drop ALL + --read-only in one opt-in flag (spell them out by hand if you prefer); add --require-limits to refuse to start unless the memory/pids caps are actually enforced. No network unless you ask, dangerous capabilities dropped, seccomp always on.
Ninety runnable examples, each doing one thing: examples/. Every read verb also answers in JSON, so nothing has to parse a table: kern ps --json | jq '.[] | select(.health == "unhealthy") | .name'
kern volume ls --json
Your Docker Compose stack, without Docker Desktop
kern speaks docker-compose.yml. Point it at the stack you already have and kern compose up runs it with no daemon and no Docker Desktop, the same on Linux, WSL2 and ARM boards.
# 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
Both official images start, web reaches db by service name, and the port is published to the host. Warm (images cached) the web tier serves in ~0.3 s, and the stack costs only what postgres and adminer actually use (~66 MB here) with zero daemon on top, where Docker Desktop is a background VM before your first container.
Official images that drop to a non-root user (postgres, redis, ...) want uidmap and a /etc/subuid line, and outbound image pulls want pasta; both are one apt install on a dev box, and kern doctor names either if it is missing. This is the local dev loop, not a production orchestrator: no Swarm, no overlay networks. Embed it: Python & Node Run agent or LLM-genera