Kern은 1.52MB짜리 정적 바이너리 하나로 작동하는 데몬 없는 루트리스(rootless) 컨테이너·샌드박스 런타임입니다. 실제 OCI 이미지 기반 컨테이너를 약 3.5ms에 구동하며, 신뢰할 수 없는 코드와 AI 생성 코드 실행을 주 용도로 설계되었습니다. Rust 의존성이 libc뿐이라는 초경량 구현이 핵심 특징입니다.
번역된 본문
kern: 모든 워크로드—신뢰할 수 없는 코드와 AI 생성 코드 포함—를 위한 빠르고 루트리스(rootless)인 샌드박스 및 가상 리소스 런타임. 하나의 1.52MB 바이너리에서 데몬 없이 약 3.5ms 만에 실제 커널 강제 적용 컨테이너를 구동합니다. 정지 상태에서 RAM 0 사용 · 데몬 없음, 소켓 없음, 시작할 것 없음 · 정적 바이너리 하나, Rust 의존성은 libc뿐
kern이란 무엇인가
리소스를 관리하는 하나의 바이너리이며, 그중 첫 번째가 격리입니다. 그래서 비교 표에 kern의 한 줄이 없는 것입니다. 컨테이너 런타임이자 샌드박스, 리소스 분할기, 스택 러너를 데몬 없이 1.52MB 하나로 겸합니다.
진짜 컨테이너. 진짜 OCI 이미지: pull, Dockerfile로 빌드, commit, push, save/load. 이미지에서 박스가 약 3.5ms에 시작됩니다.
항상 루트리스인 샌드박스. 사용자, PID, 마운트, 네트워크, UTS, IPC 네임스페이스, 오버레이 또는 읽기 전용 루트 pivot 적용, 기본 거부(default-deny) seccomp 허용 목록, cgroup v2 제한. 플래그 하나 --security-profile untrusted로 강화 번들 전체 적용.
격리뿐 아닌 리소스 프로파일. CPU(vcpu:), 메모리, 디스크(vdisk:), 장치(vgpio:)를 kern.toml에 한 번 선언하고 이름으로 연결. kern run은 샌드박스 없이 호스트의 프로세스에 동일한 상한을 적용합니다. (docs/RESOURCES.md)
kern 자체 형식 또는 Docker 형식의 스택. kern compose up은 kern-compose.toml([box.NAME] 테이블 + 위 리소스 프로파일) 또는 기존 docker-compose.yml을 변환 없이 그대로 받습니다. 스택 하나가 파드 하나로, 서비스들이 이름으로 서로 통신합니다.
그 주변 도구들. ps, logs, exec, stats, inspect, wait, top(라이브 TUI), doctor, 그리고 Python·Node SDK와 에이전트용 MCP 서버.
Rust 의존성 트리 전체가 libc뿐입니다. JSON과 OCI 매니페스트는 직접 파싱하고, pull은 TLS 스택을 링크하는 대신 시스템에 이미 있는 curl과 tar을 호출합니다. (1.52MB는 크기 최적화 릴리스 빌드이며, 소스에서 cargo install로 빌드하면 1.91MB입니다.)
kern이 아닌 것
하이퍼바이저가 아님. 경계는 리눅스 커널이므로 커널 권한 상승 버그는 곧 탈출입니다. Docker와 Podman도 같은 조건이며, 그래서 gVisor와 Firecracker가 존재합니다. 태그라인과 함께 읽으면, 같은 한 줄을 양쪽에서 본 것입니다: 신뢰할 수 없는 코드와 AI 생성 코드가 kern의 용도(FOR)입니다. 그것을 실행하기로 선택하고 폭발 반경을 스스로 감당하기 때문입니다(에이전트 도구 호출, CI 작업, 빌드 단계, 코드 셀). 용도가 아닌 것은 다른 테넌트에게 커널을 제공하는 멀티테넌트 환경에서 낯선 사람의 악성 코드를 돌리는 것입니다. kern은 항상 루트리스로 시작하는 반면 Docker는 옵트인입니다.
userns 트레이드오프에서 자유롭지 않음. 격리가 비특권 사용자 네임스페이스 위에 구축되어 있는데, 이는 커널 LPE 버그의 비옥한 원천입니다. SECURITY.md가 어떤 주장보다 먼저 이를 명시합니다.
마운트한 것을 둘러싼 벽이 아님. -v $HOME:/host는 박스에 홈 디렉터리를 그대로 줍니다. 마운트는 kern이 강제하는 경계가 아니라 당신이 내리는 신뢰 결정입니다. --net host와 --privileged는 이름 그대로의 옵트아웃입니다. (kern이 바인드를 거부하는 유일한 경로는 자체 런타임 레지스트리입니다.)
Docker Engine 재구현이 아님. Docker의 API가 아닌 형식을 다룹니다. 오버레이 네트워크, 플러그인, Swarm 없음. 매트릭스: docs/DOCKER-COMPAT.md
쿠버네티스 런타임이 아님. CRI 없음. containerd나 CRI-O를 사용하세요.
GPU 분할은 미탑재. 로드맵에 있으며 이번 판에는 GPU 코드가 없어 아직 신뢰하거나 공격할 대상도 없습니다.
모르거나 아직 하지 않는 것은 사용자가 직접 발견하게 두는 대신 OPEN_ITEMS.md에 적어두었습니다.
설치
kern은 비특권 사용자 네임스페이스와 cgroup v2를 지원하는 리눅스 커널이 필요합니다. Linux, WSL2, ARM 보드(라즈베리파이 · Jetson · Arduino UNO Q)에서 동작하며, 네이티브 Windows 빌드는 없으니 WSL2를 사용하세요(kern이 미리 구운 WSL rootfs를 제공합니다). 가장 빠른 방법은 릴리스 바이너리입니다. 정적 파일 하나, 도구...
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, with no conversion step. 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 # ps · images · stats · inspect · builds · pod ls · config list · diff 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