AI가 짠 코드를 내 서버에서 그냥 돌리면 위험하다. 그렇다고 매번 진짜 VM을 띄우면 수 초가 걸린다. CubeSandbox는 진짜 가상머신(하드웨어 격리)이면서 컨테이너보다 빠른 중간 지점을 노린다.
컨테이너는 같은 건물 안의 칸막이 사무실이다. 벽은 있지만 천장(커널)은 공유한다. 옆 칸 사람이 천장을 뚫으면 끝이다.
전통 VM은 별도의 건물이다. 안전하지만 새 건물을 짓는 데 몇 초가 걸리고 관리비(메모리)도 많이 든다.
CubeSandbox의 마이크로VM은 공장에서 미리 다 지어놓고 크레인으로 내려놓는 조립식 건물이다. 진짜 독립 건물(전용 커널·하드웨어 격리)인데, 미리 만든 스냅샷을 복사해 쓰기 때문에 설치가 60ms다.
2025~2026년 코딩 에이전트가 폭발하면서 모두가 같은 벽에 부딪혔다. 에이전트에게 셸을 주려면 그 셸이 격리돼 있어야 한다. 그런데 에이전트는 사람과 달리 초당 수십 개씩 세션을 만들고 버린다. 이 두 요구는 정면으로 충돌한다.
README의 비교표를 그대로 옮기면 이렇다. (모두 저장소가 주장하는 자체 측정치이며 제3자 검증은 아니다.)
| 방식 | 부팅 속도 | 메모리 오버헤드 | 격리 수준 |
|---|---|---|---|
| Docker 컨테이너 | 약 200ms | 낮음 | 낮음 (커널 공유 + 네임스페이스) |
| 전통 VM | 초 단위 | 높음 (풀 OS) | 높음 |
| CubeSandbox | <60ms | <5MB | 매우 높음 (전용 커널 + eBPF) |
저장소의 벤치마크 문서(docs/blog/posts/2026-06-01-cubesandbox-perf-benchmark.md)는 텐센트 클라우드 BMI5 베어메탈(96코어 / 375GiB)에서 잰 수치를 공개한다. 마케팅 숫자만 보지 말고 동시성이 올라갈 때의 꼬리 지연(P95/P99)을 보는 게 핵심이다.
| 동시 생성 수 | 평균 생성 시간 | P95 | 처리량 |
|---|---|---|---|
| 1 | 47.8ms (최소 43.5ms) | 57.4ms | — |
| 10 | 88.7ms | — | — |
| 20 | 98.1ms | — | 180.9개/초 (최고점) |
| 50 | 276.1ms | 508ms | 하락 |
동시성 20에서 처리량이 정점(180.9개/초)을 찍고, 50에서는 평균이 276ms로 5배 이상 늘어난다. 즉 이 시스템의 스위트스팟은 "노드당 동시 생성 20개 내외"이고, 그 이상은 노드를 늘려야 한다. 벤치마크 표를 볼 때는 항상 어떤 부하에서 잰 숫자인가를 먼저 확인하는 습관이 중요하다.
같은 문서를 끝까지 읽으면 더 정직한 숫자가 나온다. 2GiB 스펙 샌드박스를 100개 띄우면 VM당 실제 소비 메모리는 약 21.5MB, 1000개를 띄우면 약 25.7MB로 수렴한다. "5MB"는 VMM 프로세스 자체의 오버헤드이고, 실제로는 게스트 커널·에이전트가 쓰는 메모리가 더해진다.
보통은 VM 수가 늘수록 개당 오버헤드가 커진다. 여기서 수렴하는 이유는 CoW(Copy-on-Write) + 온디맨드 메모리 할당 때문이다. 1000개 VM이 같은 템플릿 스냅샷에서 복제됐다면, 실제로 쓰기가 발생한 페이지만 물리 메모리를 차지한다. 2GiB를 "할당"받았어도 실제로 만진 건 25MB뿐인 것이다.
흥미롭게도 저장소는 E2B를 경쟁자로 공격하지 않고 "완전 호환"을 내세운다. 문서에는 이렇게 쓰여 있다 — "E2B Cloud에서 Cube Sandbox로 옮기는 것은 API URL 같은 환경변수를 교체하는 것만큼 간단하다."
이건 흔한 "호환 계층으로 시장 진입" 전략이다. 새 API를 배우게 하는 대신, 이미 E2B를 쓰는 사람이 공짜로 갈아탈 수 있게 만든다. 대신 셀링포인트를 "셀프호스팅 가능 + 더 빠름 + 클라우드 종속 없음"으로 잡는다. Postgres 호환을 내세운 수많은 DB들이 쓴 것과 같은 수법이다.
단, 실제 코드 실행 데몬(envd)을 E2B 저장소에서 컴파일해 쓴다는 점은 양날의 검이다. 호환성은 완벽하지만, 상류 프로젝트에 대한 의존이 구조적으로 남는다.
저장소 전체를 grep 해도 이 이름들은 나오지 않는다. 비교 대상은 오직 Docker·"전통 VM"·E2B뿐이다. 즉 표에 있는 우위는 "레포가 주장하는 차별점"이지 "제3자가 검증한 우위"가 아니다. 특히 벤치마크는 전부 자사 하드웨어에서 잰 자사 측정치다.
이 프로젝트의 첫인상은 "언어를 왜 이렇게 섞었지?"다. 하지만 배치를 보면 규칙이 명확하다 — 커널·하드웨어에 가까울수록 Rust, 오케스트레이션·클러스터에 가까울수록 Go, 트래픽 라우팅은 Lua.
| 언어 | 파일 수 | 총 라인 수 | 주 담당 영역 |
|---|---|---|---|
| Go | 1,041 | 225,521 | 클러스터 오케스트레이션, 노드 에이전트, eBPF 로더 |
| Rust | 398 | 217,259 | 하이퍼바이저, containerd shim, 게스트 에이전트, API, CoW 엔진 |
| Python | 120 | 21,178 | SDK, 예제 |
| TS/JS | 99 | — | Node SDK, WebUI |
| eBPF C | 5 | — | 커널 내 네트워크 데이터플레인 |
Cargo.toml을 열면 정체가 바로 드러난다. 패키지명은 cube-hypervisor v28.0.0이지만 authors = ["The Cloud Hypervisor Authors"], homepage도 원본 URL 그대로다. 워크스페이스 멤버 25개(api_client, arch, devices, vmm, virtio-devices, vm-migration, tpm…)가 Cloud Hypervisor 원본 구조와 동일하다.
edition 2021 / MSRV 1.77.0 — 이 컴포넌트만 오래된 Rust에 묶여 있다.
마이크로VM 안에서 PID 1로 뜨는 프로세스다. authors = ["The Kata Containers community"]. 주요 의존성이 곧 역할 설명이다:
tokio-vsock — 호스트↔게스트 통신 채널 (네트워크 없이 VM 경계를 넘는 소켓)nix 0.23, capctl — 네임스페이스·capability 조작rtnetlink, netlink-packet-route — 게스트 안에서 네트워크 인터페이스 설정cgroups-rs, rustjail — 게스트 안에서 다시 OCI 컨테이너 격리ttrpc — gRPC의 경량 버전 (임베디드용)저장소 전체는 Apache-2.0인데 이 크레이트만 Cargo.toml에 license = "MIT"로 따로 박혀 있다. XFS의 FICLONE ioctl로 O(1) 스냅샷/클론을 구현한다. 의존성은 단출하다 — dashmap(락프리 맵), uuid, thiserror 2.
axum 0.7 (+ WebSocket), tower/tower-http — CORS·트레이싱·타임아웃sqlx 0.8.6 (MySQL) — 컴파일 타임 SQL 검증governor — 토큰 버킷 레이트 리밋utoipa — 코드에서 OpenAPI 스펙 자동 생성bcrypt + aes-gcm — 비밀번호 해시 + 자격증명 암호화panic="abort" + lto="fat" (바이너리 크기·성능 최적화)| 컴포넌트 | Go 버전 | 핵심 라이브러리 | 역할 |
|---|---|---|---|
| CubeMaster | 1.25.7 | gin-gonic, gorm, k8s client, containerd, grpc | 클러스터 스케줄러·상태 관리 |
| Cubelet | 1.24.8 | cilium/ebpf, containerd, cri-api | 노드 로컬 에이전트 (k8s의 kubelet 대응) |
| network-agent | 1.24.8 | cilium/ebpf, vishvananda/netlink | eBPF 프로그램 로딩·맵 관리 |
| cube-lifecycle-manager | 1.25.7 | go-redis, zap | 유휴 샌드박스 자동 일시정지/재개 |
cubevs)docker/Dockerfile.builder를 보면 RUST_TOOLCHAIN_HYPERVISOR=1.77.2, RUST_TOOLCHAIN_E2BAPI=1.85, RUST_TOOLCHAIN_AGENT=1.89로 같은 저장소 안에서 세 개의 Rust 버전을 rustup으로 병행 관리한다. 포크한 상류 코드(hypervisor)는 옛 MSRV에 묶여 있고, 새로 짠 코드는 최신 기능을 쓰고 싶을 때 쓰는 실전 기법이다. "모노레포는 언어 버전이 하나여야 한다"는 편견을 깨는 사례.
다이어그램에서 가장 중요한 건 화살표가 두 갈래로 갈라진다는 점이다.
envd. "이 코드를 실행해" 같은 실제 작업이 흐른다.호텔에 비유하면, 컨트롤 플레인은 프런트 데스크(체크인·방 배정·체크아웃)이고 데이터 플레인은 엘리베이터(투숙객이 실제로 방을 오가는 통로)다. 손님이 방에 들어간 뒤 물을 마실 때마다 프런트에 전화하지 않는다. 마찬가지로, 샌드박스가 만들어진 뒤의 코드 실행 트래픽은 CubeAPI를 거치지 않고 CubeProxy를 통해 곧장 간다.
이렇게 나누는 이유는 부하 특성이 완전히 다르기 때문이다. 컨트롤 플레인은 초당 수백 건이지만 데이터 플레인은 초당 수만 건이 될 수 있다. 섞어두면 코드 실행 트래픽이 스케줄러를 마비시킨다.
이 프로젝트에서 가장 오해하기 쉬운 부분이다. 격리가 두 겹이다.
왜 VM 안에 또 컨테이너를 넣을까? 두 경계가 막는 것이 다르기 때문이다.
| 경계 | 막는 것 | 구현 위치 |
|---|---|---|
| KVM (1차) | 다른 사용자의 샌드박스·호스트로의 탈출 | hypervisor/, CPU 가상화 확장 |
| rustjail (2차) | 같은 샌드박스 안에서 사용자 코드가 cube-agent 자체를 장악하는 것, 자원 폭주 | agent/rustjail/ |
실제 코드 위치는 이렇다:
agent/src/namespace.rs — Namespace 구조체가 unshare(CloneFlags)로 IPC/UTS/PID 네임스페이스를 만들고 /var/run/sandbox-ns에 퍼시스턴트 마운트agent/rustjail/src/seccomp.rs — init_seccomp(scmp: &LinuxSeccomp)가 OCI 런타임 스펙의 seccomp 프로필을 적용. get_unknown_syscalls()로 커널이 모르는 syscall을 걸러낸다agent/rustjail/src/cgroups/ — fs·systemd 두 드라이버 + notifierhypervisor/vmm/src/cpu.rs에서 vCPU 스레드마다 get_seccomp_filter(&self.seccomp_action, Thread::Vcpu, ...) → seccompiler::apply_filter를 호출한다. 즉 게스트가 하이퍼바이저를 뚫었다 해도, 하이퍼바이저 프로세스 자체가 최소 syscall 화이트리스트에 갇혀 있다. "심층 방어(defense in depth)"의 교과서적 구현이다.
60ms 부팅의 진짜 비밀은 하이퍼바이저가 빨라서가 아니라 "부팅을 안 하기 때문"이다.
템플릿이 만들어지는 과정은 3단계다 (docs/guide/templates.md):
노트북 절전모드(하이버네이션)와 같다. 전원을 껐다 켜면 부팅에 1분이 걸리지만, 절전모드에서 깨우면 3초다. CubeSandbox는 "Python 인터프리터까지 다 켜놓은 상태"를 절전모드로 저장해두고, 요청이 올 때마다 그 절전 상태를 복사해서 깨운다.
그리고 FICLONE 덕분에 그 "복사"조차 실제 복사가 아니다. 1000개의 샌드박스가 같은 스냅샷 파일 블록을 공유하다가, 각자 파일을 수정하는 순간에만 그 블록이 갈라진다.
CubeCoW가 내세우는 두 가지 특징:
soft-dirty 커널 기능으로 변경된 익명 페이지만 저장한다스냅샷 메타데이터 구조체(CubeShim/shim/src/hypervisor/snapshot.rs)도 살펴볼 가치가 있다:
struct SnapshotInfo {
kernel_version, // 게스트 커널 버전
image_version, // rootfs 이미지 버전
ch_version, // Cloud Hypervisor 버전
vm_res, // VmRes { cpu, cpu_max, memory, disks, pmems }
memory_vol_url,
...
}
커널·이미지·하이퍼바이저 버전을 메타데이터에 기록해두면, 구버전 하이퍼바이저로 찍은 스냅샷을 신버전이 복원하려 할 때 즉시 거부할 수 있다. 메모리 스냅샷은 CPU 레지스터 상태까지 담고 있어서 버전이 안 맞으면 조용히 망가진다 — 이런 건 런타임에 크래시로 발견하면 이미 늦다. 직렬화된 상태를 저장하는 모든 시스템(캐시·세션·체크포인트)에 적용되는 원칙이다.
샌드박스가 수천 개면 네트워크 규칙도 수천 개다. 전통적인 iptables는 규칙을 선형 탐색하므로 규칙이 늘수록 패킷당 지연이 커진다(이른바 "rule explosion"). CubeVS는 이걸 eBPF로 우회한다.
eBPF 프로그램 3개가 각각 다른 지점에 붙는다:
| 파일 | 프로그램명 | 부착 지점 | 역할 |
|---|---|---|---|
mvmtap.bpf.c | from_cube | TAP 디바이스 TC ingress | 샌드박스에서 나가는 패킷 (SNAT·정책 평가) |
nodenic.bpf.c | from_world | 호스트 NIC TC ingress | 외부에서 들어오는 패킷 (DNAT·세션 매칭) |
localgw.bpf.c | from_envoy | cube-dev TC egress | 프록시에서 나가는 패킷 |
Go 컨트롤플레인(CubeNet/cubevs/)이 BPF 맵을 관리한다 — egress_sessions, snat_iplist, allow_out_v2, dns_allow 등. iptables·리눅스 브리지·OVS를 전혀 쓰지 않는다.
docs/architecture/overview.md가 정리한 6개 방어층:
에이전트가 GitHub API를 호출해야 한다고 하자. 보통은 샌드박스 안에 토큰을 넣어준다. 그러면 LLM이 그 토큰을 읽어 로그나 응답에 흘릴 수 있다.
CubeEgress는 대신 이렇게 한다: 샌드박스는 토큰 없이 요청을 보내고, TPROXY로 가로챈 CubeEgress가 나가는 길에 Authorization 헤더를 붙인다. 샌드박스는 토큰을 본 적이 없다. 이게 가능한 이유는 CubeEgress가 발급한 루트 CA가 샌드박스 템플릿에 미리 심어져 있어 TLS 인스펙션(중간자)이 가능하기 때문이다.
docs/architecture/overview.md — 전체 그림. 여기부터 시작 안 하면 길을 잃는다CubeAPI/src/routes.rs — 시스템이 "무엇을 할 수 있는가"의 전체 목록CubeShim/shim/src/hypervisor/cube_hypervisor.rs — VM 라이프사이클의 실제 호출 흐름cubecow/ — 크기가 작고 독립적이라 혼자 읽기 좋다. FICLONE 학습에 최적CubeNet/*.bpf.c — eBPF 실전 코드. 3개 파일뿐이라 부담 없다21만 줄 Rust 중 대부분이 여기 있고, 거의 전부가 Cloud Hypervisor 원본 코드다. CubeSandbox 고유의 기여를 보려면 CubeShim/, cubecow/, CubeNet/, CubeAPI/를 봐야 한다. 상류 포크 저장소를 읽을 때는 git log로 "이 조직이 실제로 건드린 파일"부터 찾는 게 훨씬 빠르다.
이 저장소의 가장 큰 교훈은 성능 문제를 "더 빠르게 만들기"가 아니라 "안 하기"로 푼다는 것이다. 부팅이 느리면 부팅을 최적화하는 대신, 부팅 결과를 저장해두고 복원한다.
이 패턴은 도처에 있다 — JVM의 AppCDS, Android의 Zygote 프로세스, Python의 fork() 기반 프리로더, Node.js의 스냅샷. 공통 구조는 이렇다:
실습 아이디어: 무거운 초기화(대형 모델 로딩, DB 커넥션 풀)를 하는 파이썬 프로세스를 만들고, fork() 기반 프리포크 서버로 바꿔 요청당 지연이 얼마나 줄어드는지 측정해보라.
FICLONE은 Rust나 C가 아니어도 실험할 수 있다. 리눅스에서 XFS(reflink 활성) 또는 Btrfs 위에서 cp --reflink=always를 써보면 즉시 체감된다.
# 10GB 파일을 만들고 두 방식으로 복사해 시간 비교
dd if=/dev/zero of=big.img bs=1M count=10240
time cp big.img copy1.img # 수십 초
time cp --reflink=always big.img copy2.img # 밀리초
df -h . # 디스크 사용량이 안 늘어난다
실습 아이디어: reflink 복사본을 만든 뒤 한쪽 파일 일부를 수정하고, filefrag -v로 extent가 어떻게 갈라지는지 관찰해보라. CoW가 "언제" 실제 복사를 하는지 눈으로 볼 수 있다.
CubeNet의 파일 3개는 eBPF 입문 교재로 훌륭하다. TC(Traffic Control) 훅에 붙는 eBPF는 XDP보다 다루기 쉽고 활용 범위가 넓다.
실습 아이디어: cilium/ebpf(Go) 또는 aya(Rust)로 "특정 포트로 나가는 패킷만 카운트하는" 최소 TC 프로그램을 작성해보라. 그다음 BPF 맵에서 그 카운터를 사용자공간으로 읽어오는 것까지 하면 CubeVS의 축소판이 된다.
Kubernetes(API 서버 ↔ 워크로드 트래픽), Envoy(xDS ↔ 프록시), Kafka(주키퍼/KRaft ↔ 브로커) 모두 같은 구조다. 이 분리를 못 하면 시스템은 부하가 올라갈 때 항상 같은 방식으로 죽는다 — 제어 명령이 데이터 트래픽에 밀려 타임아웃되고, 그러면 재시도가 몰려 더 죽는다.
실습 아이디어: 자기가 만든 API 서버에서 "관리용 엔드포인트"와 "고빈도 엔드포인트"를 다른 포트/다른 프로세스로 분리해보라. 부하 테스트로 격리 효과를 측정하면 체감이 온다.
이 저장소는 "어디까지 빌리고 어디부터 만들 것인가"의 판단 사례집이다.
| 영역 | 선택 | 이유(추정) |
|---|---|---|
| VMM | Cloud Hypervisor 포크 | 직접 만들면 수년 + 보안 리스크. 성숙한 것을 쓴다 |
| 게스트 에이전트 | Kata Containers 포크 | 동상 |
| 코드 실행 데몬 | E2B의 envd 그대로 | SDK 호환성이 목적 자체 |
| 스토리지 CoW | 직접 개발 (CubeCoW) | 기존 것(qcow2 체인)의 구조적 한계를 피하고 싶었음 |
| 네트워크 | 직접 개발 (CubeVS) | iptables/OVS로는 규모에서 안 됨 |
| PVM | 직접 개발 | 중첩 가상화 없는 클라우드 VM 지원 = 사업적 차별점 |
규칙이 보인다 — "성숙하고 표준적인 것은 빌린다. 자기 제품의 차별점이 되는 부분만 만든다." README도 이를 명시한다: "made tailored modifications... original in-file copyright notices are preserved."
x86_64 또는 aarch64 리눅스 + /dev/kvm가 필수다. 그리고 root 권한이 필요하다. 노트북에서 가볍게 시험할 수 있는 종류의 프로젝트가 아니다.
docs/guide/quickstart.md)| 용도 | CPU | RAM | 디스크 |
|---|---|---|---|
| 기능 체험용 (최소) | ≥4코어 | ≥8GB | ≥50GB (XFS 필수, /data/cubelet) |
| 권장 | 32코어 | 64GB | ≥200GB |
| 템플릿 다수 빌드 시 | — | — | 200GB+ |
CubeCoW가 FICLONE에 의존하므로 ext4에서는 핵심 기능이 동작하지 않는다. 게다가 XFS를 만들 때 reflink 옵션이 켜져 있어야 한다(xfsprogs ≥ 5.0에서는 기본값). 설치 전에 xfs_info /data로 reflink=1을 확인할 것.
| 방식 | 대상 | 비고 |
|---|---|---|
| PVM · 클라우드 VM | 일반 클라우드 인스턴스 | 공식 권장. x86_64 전용 |
| 베어메탈 | 물리 서버 | 최고 성능. KVM 직접 사용 |
| dev-env (QEMU) | 로컬 개발 | README가 "비권장·저성능"이라 명시 |
추가 배포 자산: deploy/one-click/에 systemd 서비스 + docker-compose(webui, cubeproxy, coredns, cube-lifecycle-manager), deploy/terraform/tencentcloud/에 TKE+CVM 자동 배포(v0.5.0 신규), deploy/kubernetes/chart에 Helm 차트.
Helm 차트는 있지만, README 로드맵에서 진짜 쿠버네티스 네이티브 통합은 미완으로 표시돼 있다. 현재 차트는 그 전 단계 지원으로 보인다(추정).
bare-metal-deploy.md에 따르면, 일부 구형 aarch64 호스트는 KVM이 게스트에 PMUv3(성능 카운터)를 노출하지 않는다. 마이크로VM은 정상 부팅하되 하드웨어 성능 카운터 없이 동작한다. 기능상 문제는 아니지만 프로파일링이 제한된다.
이 프로젝트의 핵심 주장("드롭인 교체")이 진짜인지 코드로 확인한다. 서버를 안 띄워도 된다.
examples/code-sandbox-quickstart/exec_code.py를 열어보라. 실제 내용은 이렇다:
from e2b_code_interpreter import Sandbox
with Sandbox.create(template=template_id) as sandbox:
print(sandbox.run_code("print('hello cube')",
on_stdout=lambda data: print(data)))
주목할 점: import 하는 패키지가 cubesandbox가 아니라 E2B의 e2b_code_interpreter다. 바뀌는 건 E2B_API_URL 환경변수 하나뿐이다.
과제: 저장소 안 SDK 3종(sdk/python, sdk/node, sdk/go)이 자체 API를 제공하는데도 예제가 E2B SDK를 쓰는 이유를 설명해보라. 두 SDK는 각각 언제 쓰는 게 맞는가?
CubeSandbox를 안 띄우고 그 핵심 원리만 재현한다. 리눅스(XFS reflink 또는 Btrfs)만 있으면 된다.
cp와 cp --reflink=always의 소요 시간·디스크 사용량 비교dd conv=notrunc)df로 디스크 사용량이 얼마나 늘었는지 확인 — 1GB가 아니라 100MB만 늘어야 한다filefrag -v로 두 파일의 extent 공유 상태 관찰확장: 사본 100개를 만들고, 각각 다른 위치를 조금씩 수정한 뒤 총 디스크 사용량을 계산해보라. CubeSandbox가 "1000개 VM에서 VM당 25.7MB로 수렴"하는 이유를 수치로 이해하게 된다.
KVM 가능한 리눅스 서버(≥4코어/8GB/50GB XFS)에서 deploy/one-click/으로 설치한다.
xfs_info로 reflink=1 확인, ls /dev/kvm 확인cubemastercli tpl create-from-image)핵심 질문: 내 환경 숫자가 문서(96코어 베어메탈)와 얼마나 다른가? 차이의 원인을 CPU·디스크·네트워크 중 무엇으로 설명할 수 있는가? 벤치마크를 읽을 때 "환경 의존성"을 체감하는 게 이 과제의 진짜 목적이다.
CubeNet/*.bpf.c를 읽고 축소판을 직접 구현한다.
mvmtap.bpf.c(from_cube)를 정독 — TC ingress 훅에서 패킷을 어떻게 파싱하고 맵을 어떻게 조회하는지cilium/ebpf(Go) 또는 aya(Rust)로 최소 TC 프로그램 작성: "허용 목록에 없는 목적지 IP는 드롭"목표: "iptables rule explosion"이 마케팅 문구가 아니라 측정 가능한 현상임을 자기 손으로 확인하는 것.
"60ms"가 실제로 어디서 소비되는지 코드와 프로파일로 분해한다.
CubeShim/shim/src/hypervisor/cube_hypervisor.rs에서 restore_vm()과 resume_vm_cube_with_config()의 호출 그래프를 그린다snapshot.rs의 SnapshotInfo 버전 체크를 일부러 실패시켜 방어 로직이 작동하는지 검증발전 과제: 동시성 50에서 평균이 276ms로 튀는 원인을 위 분해로 설명할 수 있는가? 디스크 I/O인가, 락 경합인가, vCPU 스케줄링인가?
| 주차 | 주제 | 학습 내용 | 산출물 |
|---|---|---|---|
| 1주 | 리눅스 격리 기초 | namespace 7종, cgroup v2, capability, seccomp-bpf. unshare·nsenter 명령 직접 사용 | 200줄짜리 "미니 컨테이너 런타임"(C 또는 Go) |
| 2주 | OCI 스펙 | runtime-spec의 config.json 구조, image-spec 레이어, containerd 아키텍처 | agent/rustjail/이 OCI 스펙의 어느 필드를 구현하는지 매핑 표 |
| 3주 | 가상화 원리 | Intel VT-x/AMD-V, EPT, KVM API(KVM_CREATE_VM, KVM_RUN), virtio 반가상화 | KVM ioctl만으로 "hlt만 실행하는" 최소 VM 부팅시키기 |
| 4주 | 마이크로VM 실전 | Firecracker와 Cloud Hypervisor 비교, 장치 모델 축소, 스냅샷/복원 API | Firecracker로 VM 스냅샷 찍고 복원하는 스크립트 |
| 5주 | 파일시스템 CoW | XFS reflink, Btrfs subvolume, overlayfs, qcow2 백킹 체인의 문제점 | 실습 2번 확장판 + "flat snapshot이 왜 나은가" 정리 문서 |
| 6주 | eBPF | verifier 동작 원리, 맵 종류, XDP vs TC 훅, cilium/ebpf 또는 aya | 실습 4번 (미니 CubeVS) |
| 7주 | Rust 시스템 프로그래밍 | nix/rustix로 syscall 호출, unsafe 경계 설계, tokio 비동기, ttrpc/vsock | agent/src/namespace.rs를 읽고 주석 달기 |
| 8주 | 분산 시스템 설계 | 컨트롤/데이터 플레인 분리, 스케줄러 설계, 상태 저장소(Redis) 활용 패턴 | CubeMaster의 스케줄링 로직 분석 문서 |
8주는 이 저장소를 "읽을 수 있게" 되는 시간이지 "기여할 수 있게" 되는 시간이 아니다. 시간이 부족하다면 우선순위는 1주(격리) → 3주(KVM) → 5주(CoW)다. 이 셋만 알아도 아키텍처 문서가 이해되기 시작한다.
반대로 당장 써먹을 것만 원한다면 실습 1·2번만 하고 넘어가도 된다. 이 프로젝트의 설계 교훈(스냅샷 패턴, 플레인 분리, 빌릴 것과 만들 것의 구분)은 가상화를 몰라도 자기 코드에 적용할 수 있다.
| 용어 | 뜻 |
|---|---|
| microVM | 불필요한 가상 장치를 제거한 초경량 가상머신. 빠른 부팅과 낮은 메모리 오버헤드가 목표 |
| KVM | Kernel-based Virtual Machine. 리눅스 커널에 내장된 하이퍼바이저 기능. /dev/kvm으로 접근 |
| VMM | Virtual Machine Monitor. 가상 장치를 흉내내고 게스트를 관리하는 사용자공간 프로그램. 여기선 CubeHypervisor |
| Cloud Hypervisor | Rust로 작성된 오픈소스 VMM. CubeSandbox가 포크한 원본 |
| Kata Containers | 컨테이너를 VM 안에서 돌리는 프로젝트. CubeSandbox의 게스트 에이전트가 이걸 포크 |
| PVM | Pagetable-based VM. 중첩 가상화 지원 없이 페이지테이블만으로 KVM 능력을 제공하는 텐센트 자체 기술. x86_64 전용 |
| CoW | Copy-on-Write. 복사할 때 실제로 복사하지 않고, 수정이 일어나는 순간에만 그 부분을 복사 |
| reflink / FICLONE | XFS·Btrfs의 파일 수준 CoW 복사. 데이터 블록을 공유하는 새 파일을 O(1)에 만든다 |
| flat snapshot | 스냅샷들이 사슬로 엮이지 않는 모델. 중간 스냅샷을 삭제해도 다른 스냅샷이 깨지지 않는다 |
| dirty page | 마지막 저장 이후 수정된 메모리 페이지. 스냅샷 시 이것만 저장하면 증분 저장이 된다 |
| seccomp | 프로세스가 호출할 수 있는 시스템콜을 화이트리스트로 제한하는 리눅스 기능 |
| namespace | PID·네트워크·마운트 등을 프로세스 그룹별로 분리해 "각자 자기만의 세상"을 보게 하는 커널 기능 |
| cgroup | CPU·메모리·I/O 사용량에 상한을 거는 커널 기능 |
| rustjail | Kata Containers의 Rust 기반 컨테이너 격리 라이브러리. 게스트 VM 안에서 2차 격리를 담당 |
| eBPF | 커널 안에서 검증된 작은 프로그램을 안전하게 실행하는 기술 |
| TC (Traffic Control) | 리눅스 네트워크 스택의 큐 제어 계층. eBPF 프로그램을 ingress/egress에 붙일 수 있다 |
| BPF 맵 | 커널 eBPF 프로그램과 사용자공간이 공유하는 자료구조. 정책 갱신 통로 |
| SNAT / DNAT | Source/Destination NAT. 패킷의 출발지/목적지 주소를 바꿔치기하는 것 |
| TPROXY | 리눅스의 투명 프록시 기능. 클라이언트가 모르게 트래픽을 프록시로 우회 |
| containerd Shim v2 | containerd가 컨테이너 런타임과 통신하는 표준 인터페이스. CubeShim이 이걸 구현해 VM을 컨테이너처럼 다루게 한다 |
| ttrpc | gRPC의 경량 버전. 임베디드·저자원 환경용. HTTP/2 대신 단순 프로토콜 사용 |
| vsock | 호스트와 게스트 VM 사이의 소켓 통신 채널. 네트워크 스택을 거치지 않는다 |
| envd | E2B가 만든 샌드박스 내부 데몬. 실제 코드 실행을 담당. CubeSandbox가 소스에서 컴파일해 사용 |
| E2B | AI 에이전트용 클라우드 샌드박스 상용 서비스. CubeSandbox가 API·SDK 호환 대상으로 삼음 |
| OpenResty | nginx + Lua 스크립팅. CubeProxy·CubeEgress가 이걸로 만들어짐 |
| Buildkit | Docker의 차세대 이미지 빌더. 템플릿 rootfs 빌드에 사용 |
| MSRV | Minimum Supported Rust Version. 이 저장소는 컴포넌트별로 1.77 / 1.85 / 1.89를 따로 관리 |
| DCO | Developer Certificate of Origin. 커밋에 Signed-off-by를 요구하는 기여 정책. CI에서 검사 |
docs/architecture/overview.md(전체 구조), docs/guide/quickstart.md(설치), docs/guide/templates.md(템플릿 3단계), docs/blog/posts/2026-06-01-cubesandbox-perf-benchmark.md(벤치마크 원본)openapi.yml — REST API 전체 스펙examples/ — 17개 예제 (code-sandbox, browser-sandbox, RL training, pi-agent-integration, e2b-dev-sidecar 등)hypervisor/의 원본agent/·rustjail의 원본envd의 출처rustjail이 구현하는 표준