LabHub

블로그

컨테이너 런타임 2026 완벽 가이드 - containerd · runc · Podman · CRI-O · Kata · gVisor · Firecracker · Wasm 심층 분석

한국어English日本語

들어가며 — 2026년 5월, 컨테이너 런타임은 "다층 격리의 시대"로 들어섰다

도커가 컨테이너의 동의어이던 시대는 끝났다. 2026년 5월 현재 Kubernetes 클러스터의 95% 이상은 containerdCRI-O 위에서 돈다. 로컬 개발 머신에서는 PodmanDocker Desktop이 비슷한 점유율을 두고 다투고, 서버리스 백엔드는 Firecracker가 사실상 표준이다. 그리고 Wasm 런타임이 컨테이너의 일부 자리를 잠식하기 시작했다. WasmEdge와 wasmtime이 runwasi라는 containerd-shim으로 K8s에 직접 꽂힌다.

이 글은 마케팅 비교가 아니라 "지금 프로덕션에서 어떤 런타임이 어디에 들어가는가"를 정직하게 다룬다. OCI 이미지 스펙, CRI, 저수준 런타임, 격리 강도, 이미지 빌드, 레지스트리, 서명, 취약점 스캔까지 풀 스택으로 짚는다.

컨테이너 스택의 5개 레이어 — OCI 이미지부터 커널까지

먼저 큰 그림을 보자. 2026년 표준 컨테이너 스택은 다음 5개 레이어로 분해된다.

  1. OCI 이미지 포맷(image spec): 매니페스트 + 레이어 tar + config JSON
  2. 레지스트리(distribution spec): ECR, GAR, Harbor, Quay 등이 같은 API
  3. 고수준 런타임(CRI/엔진): containerd, CRI-O, Docker Engine, Podman
  4. 저수준 런타임(OCI runtime): runc, crun, youki, kata-runtime, runsc(gVisor)
  5. 격리 메커니즘: namespaces + cgroups, 마이크로 VM, 사용자공간 커널, Wasm 샌드박스

이 레이어들은 OCI 이미지 스펙OCI 런타임 스펙이라는 두 표준으로 연결된다. 즉 어떤 빌더로 만든 이미지든 어떤 런타임에서든 동작해야 한다. 2026년 현재 이 약속은 거의 깨지지 않는다.

containerd — Kubernetes의 기본 CRI

containerd는 원래 도커 엔진에서 분리된 데몬으로, 2017년 CNCF로 졸업한 뒤 K8s의 사실상 표준 CRI 구현이 됐다. EKS, GKE, AKS, OpenShift 모두 기본은 containerd다. Docker Desktop도 내부적으로 containerd를 쓴다.

containerd의 구조는 단순하다.

containerd 2.0 라인업(2025년 말 GA)부터는 NRI(Node Resource Interface), 사용자공간 NRI 플러그인, Wasm shim(runwasi) 통합이 1급이다. nerdctl은 containerd의 도커 호환 CLI로, docker CLI와 거의 동일한 명령을 제공한다.

# nerdctl로 containerd 직접 다루기
sudo nerdctl pull alpine:3.20
sudo nerdctl run --rm -it alpine:3.20 sh
sudo nerdctl images
sudo nerdctl ps -a

# CRI 플러그인 상태 확인
sudo crictl info | jq '.config.containerd'
sudo crictl ps

runc · crun · youki — OCI 저수준 런타임 삼파전

OCI 런타임 스펙은 "config.json과 rootfs 디렉터리를 받아 컨테이너를 띄우라"는 인터페이스다. 이 인터페이스를 구현한 저수준 런타임이 세 개 있다.

세 런타임은 OCI 스펙을 따르므로 containerd runtimes 설정에서 바꿔 끼울 수 있다.

# /etc/containerd/config.toml 일부
[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.crun]
  runtime_type = "io.containerd.runc.v2"
  [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.crun.options]
    BinaryName = "/usr/bin/crun"

[plugins."io.containerd.grpc.v1.cri".containerd.runtimes.youki]
  runtime_type = "io.containerd.runc.v2"
  [plugins."io.containerd.grpc.v1.cri".containerd.runtimes.youki.options]
    BinaryName = "/usr/local/bin/youki"

CRI-O — Kubernetes 전용 경량 CRI

CRI-O는 Red Hat이 주도하는 K8s 전용 CRI다. 도커 호환 기능을 가지지 않고, 오로지 kubelet과 OCI 런타임 사이의 다리만 한다. OpenShift의 기본 CRI이며, 노드의 메모리 점유와 표면적이 containerd보다 작다는 장점이 있다.

containerd와 CRI-O 중 어느 쪽을 선택해야 하느냐는 운영팀의 익숙함에 좌우된다. EKS·GKE 기본을 그대로 쓴다면 containerd, OpenShift 위라면 CRI-O다. 두 런타임의 격리 강도와 기능 차이는 2026년 시점에서 거의 없다.

Docker Engine — 데스크톱과 레거시 서버에 남은 자리

Docker Engine은 2026년에도 살아 있지만 역할이 좁아졌다. 데스크톱(Docker Desktop)과 일부 레거시 서버에서만 기본 엔진이고, K8s 노드에서는 거의 사라졌다. 도커 엔진 자체도 내부적으로 containerd를 쓰는 얇은 래퍼에 가깝다.

도커가 여전히 강한 영역은 개발자 UX다. docker compose로 멀티 컨테이너 개발 환경을 띄우는 흐름은 여전히 압도적이고, Buildx와 Docker Build Cloud가 빌드 속도를 끌어올렸다. 그래서 "프로덕션은 containerd, 개발은 Docker Desktop" 조합이 여전히 흔하다.

Podman + Buildah + Skopeo — rootless · daemonless 트리오

Podman은 도커 호환 CLI지만 데몬이 없다. 컨테이너 각각이 사용자 프로세스로 떠서 systemd가 lifecycle을 관리한다. 데몬이 없으니 root 권한도 필요 없다(rootless). Fedora·RHEL·CentOS Stream의 기본이고, Ubuntu LTS에서도 표준 패키지로 들어왔다.

이 셋은 Red Hat이 주도하지만 OCI 표준만 따르므로 다른 런타임·레지스트리와 자유롭게 섞인다.

# Podman rootless 컨테이너
podman run --rm -it --userns=keep-id alpine:3.20 id

# Buildah로 데몬 없이 빌드
buildah bud -t myapp:1.0 .
buildah push myapp:1.0 docker://registry.example.com/myapp:1.0

# Skopeo로 레지스트리 간 이미지 복사
skopeo copy --src-creds user:pass --dest-creds user:pass \
  docker://docker.io/library/nginx:1.27 \
  docker://harbor.example.com/library/nginx:1.27

Kata Containers 3.x — 경량 VM으로 강한 격리

Kata Containers는 컨테이너 인터페이스 뒤에 가벼운 VM을 띄워 커널을 분리한다. 호스트 커널 취약점이 컨테이너 탈출로 이어지지 않도록 막는다. 3.x 라인업(2024-2026)은 QEMU, Firecracker, Cloud Hypervisor를 하이퍼바이저로 골라 쓸 수 있고, 시작 시간이 1-2초대로 떨어졌다.

Kata는 containerd runtimeskata-qemu, kata-fc, kata-clh로 등록한다. K8s에서는 RuntimeClass로 워크로드별로 격리 수준을 다르게 줄 수 있다.

apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: kata-clh
handler: kata-clh
---
apiVersion: v1
kind: Pod
metadata:
  name: untrusted-workload
spec:
  runtimeClassName: kata-clh
  containers:
    - name: app
      image: registry.example.com/untrusted-app:1.0

gVisor — Google의 사용자공간 커널 샌드박스

gVisor(runsc)는 Google이 만든 사용자공간 커널 구현이다. 호스트 커널 syscall을 그대로 통과시키지 않고, runsc 안에서 자체 커널이 대신 처리한다. VM이 아니라 가볍지만, 호스트 커널 표면적을 극도로 줄인다.

gVisor의 단점은 네트워크·파일 I/O가 일부 워크로드에서 느려진다는 점이다. 그래서 신뢰할 수 없는 코드 실행(서버리스 함수, CI 빌드 러너, AI 추론 사용자 코드)에 잘 맞고, DB 같은 I/O 헤비 워크로드에는 잘 안 맞는다. Google Cloud Run, GKE Sandbox가 내부적으로 gVisor를 쓴다.

# Docker에 runsc 등록 후 실행
sudo runsc install
sudo systemctl restart docker
docker run --rm --runtime=runsc alpine:3.20 uname -a
# 출력의 커널 버전이 호스트가 아닌 runsc가 시뮬레이션한 값으로 찍힌다

Firecracker — AWS 마이크로 VM

Firecracker는 AWS가 만든 KVM 기반 마이크로 VM 모니터다. Lambda, Fargate, App Runner의 격리 단위가 Firecracker microVM이다. VM 한 대가 5MB 미만의 메모리 오버헤드로 125ms 안에 부팅된다. Rust로 작성됐고, 디바이스 모델을 가능한 한 잘라내 보안 표면을 줄였다.

Firecracker는 REST API를 통해 vCPU, 메모리, 커널 이미지, rootfs, 네트워크 인터페이스를 설정한 뒤 인스턴스를 시작한다.

{
  "boot-source": {
    "kernel_image_path": "/var/lib/firecracker/vmlinux",
    "boot_args": "console=ttyS0 reboot=k panic=1 pci=off"
  },
  "drives": [
    {
      "drive_id": "rootfs",
      "path_on_host": "/var/lib/firecracker/rootfs.ext4",
      "is_root_device": true,
      "is_read_only": false
    }
  ],
  "machine-config": {
    "vcpu_count": 2,
    "mem_size_mib": 512,
    "smt": false
  }
}

Cloud Hypervisor — Intel·AWS·Microsoft 공동 마이크로 VM

Cloud Hypervisor는 Intel이 시작해 AWS, Microsoft, Tencent 등이 합류한 공동 프로젝트다. Firecracker와 비슷한 KVM 기반 VMM이지만 더 풍부한 디바이스 모델과 ARM·x86 양쪽을 지원한다. Kata Containers의 kata-clh 백엔드, Azure Confidential Containers, AWS의 일부 컨테이너 격리에 쓰인다. 2026년 시점에서 마이크로 VM 진영은 Firecracker와 Cloud Hypervisor 양분이라고 봐도 무방하다.

Wasm 런타임 — K8s에 진입한 새로운 격리 단위

WebAssembly는 컨테이너의 일부 자리를 빠르게 잠식하고 있다. WasmEdge, wasmtime, wasmer, lunatic 등의 런타임은 시작 시간이 마이크로초 단위이고, 메모리 오버헤드가 컨테이너보다 한 자릿수 작다. CNCF는 runwasi라는 containerd-shim을 통해 Wasm을 K8s pod로 직접 실행하도록 표준화했다.

K8s에서 Wasm 워크로드를 띄우는 가장 흔한 흐름은 runwasi를 containerd에 등록하고 RuntimeClass로 분기시키는 것이다.

apiVersion: node.k8s.io/v1
kind: RuntimeClass
metadata:
  name: wasmedge
handler: wasmedge
---
apiVersion: v1
kind: Pod
metadata:
  name: hello-wasm
spec:
  runtimeClassName: wasmedge
  containers:
    - name: hello
      image: registry.example.com/hello-wasm:1.0
      command: ['/hello.wasm']

WASI · Wasm Component Model — 호환성 표준

Wasm을 컨테이너의 대체재로 만드는 핵심은 WASI(WebAssembly System Interface)다. preview 1에서 시작해 2024년 preview 2가 안정화됐고, 2025년 말 component model이 GA에 가까워졌다. component model은 언어 간 ABI를 통일해, Rust로 만든 Wasm 모듈이 Go·JS·Python 호스트에서 그대로 동작한다.

2026년 현재 WASI/component model을 가장 활발히 쓰는 곳은 에지 컴퓨팅(Cloudflare Workers, Fastly Compute), 플러그인 시스템(Envoy, OpenPolicyAgent, Istio), AI 추론(WasmEdge + ONNX, GGUF)이다.

격리 강도 비교 — 무엇을 언제 쓰는가

런타임을 고를 때 가장 중요한 축은 격리 강도와 시작 시간이다. 2026년 5월 시점의 대표 조합을 정리하면 다음과 같다.

표면적인 격리 강도만 보면 마이크로 VM과 Kata가 가장 강하고, Wasm은 그보다 약하지만 컨테이너 탈출 종류의 위협 모델이 다르다. runc는 가장 약하지만 가장 빠르고 호환된다.

OCI 이미지 빌드 — BuildKit·kaniko·buildah·jib·ko·Buildpacks

이미지를 만드는 도구는 2026년에도 다양하다. 어떤 도구를 쓸지는 환경(빌더에 도커 데몬이 있는지, K8s 안에서 빌드하는지)과 언어 스택에 달렸다.

BuildKit + 캐시 마운트의 전형적 멀티 스테이지 Dockerfile은 다음과 같다.

# syntax=docker/dockerfile:1.7
FROM golang:1.23 AS builder
WORKDIR /src
COPY go.mod go.sum ./
RUN --mount=type=cache,target=/go/pkg/mod \
    go mod download
COPY . .
RUN --mount=type=cache,target=/root/.cache/go-build \
    --mount=type=cache,target=/go/pkg/mod \
    CGO_ENABLED=0 go build -o /out/app ./cmd/server

FROM gcr.io/distroless/static-debian12:nonroot
COPY --from=builder /out/app /app
USER nonroot:nonroot
ENTRYPOINT ["/app"]

OCI 이미지 포맷 · 매니페스트 v2 · index

OCI 이미지 스펙은 세 가지 객체로 이뤄진다. 매니페스트(레이어와 config 참조), config JSON(엔트리포인트, 환경 변수, history), 레이어(tar.gz 또는 zstd 압축). 멀티 아키텍처는 이미지 인덱스(매니페스트 리스트)로 묶는다.

2026년 들어 표준화가 끝난 변화로는 OCI image-spec 1.1의 zstd 레이어, OCI artifacts(이미지가 아닌 데이터도 같은 형식으로 푸시), referrer API(OCI 1.1 dist-spec)가 있다. 이 덕분에 cosign 서명, SBOM, attestation을 같은 레지스트리에 사이드카로 올린다.

OCI Distribution · 레지스트리 풀스택

레지스트리도 OCI distribution spec 한 가지로 통일됐다. 어느 클라우드 레지스트리든 같은 API를 쓴다.

이미지 서명 — cosign · notation(Notary v2)

이미지 출처 보증은 2024년부터 표준이 정착됐다.

K8s에서는 admission controller(Sigstore Policy Controller, Kyverno, OPA Gatekeeper)로 서명되지 않은 이미지의 배포를 막는다.

# cosign keyless 서명과 검증
cosign sign --yes registry.example.com/myapp:1.0
cosign verify \
  --certificate-identity-regexp 'https://github.com/myorg/.*' \
  --certificate-oidc-issuer 'https://token.actions.githubusercontent.com' \
  registry.example.com/myapp:1.0

취약점 스캔 — Trivy · Grype · Snyk · Clair

빌드 또는 푸시 단계에서 이미지 취약점을 스캔하는 도구도 표준화됐다.

2026년 시점에 가장 많이 보이는 조합은 GitHub Actions/GitLab CI에서 Trivy로 차단, Harbor·ECR이 푸시 후 자동 스캔, K8s admission이 cosign 서명 + Trivy 보고서를 같이 검증하는 흐름이다.

rootless · userns · cgroups v2 — 2026년의 기본

리눅스 호스트 수준의 격리 표준도 정착했다.

Kubernetes RuntimeClass와 멀티 런타임 노드

K8s RuntimeClass는 노드에 등록된 여러 런타임 중 어떤 것을 쓸지 워크로드별로 고르는 표준 API다. 한 클러스터 안에 신뢰 워크로드는 runc, 사용자 코드 실행은 gVisor, 멀티테넌트는 Kata, 에지 함수는 Wasm으로 분리하는 그림이 흔하다.

노드 풀을 런타임별로 나누는 것이 운영적으로 단순하지만, 같은 노드에 여러 런타임을 등록해 admission으로 분기시키는 패턴도 늘었다. 클라우드 매니지드 K8s에서는 GKE Sandbox(gVisor), AKS Confidential Containers(Kata + Cloud Hypervisor), EKS on Fargate(Firecracker)가 각각의 길을 간다.

빌드 캐시와 결정론적 빌드

2026년 빌드 캐시는 사실상 필수다. BuildKit과 buildah는 레지스트리에 캐시 매니페스트를 푸시하는 inline·registry 캐시를 지원한다. Bazel rules_oci, ko, jib는 결정론적 빌드(같은 입력 → 같은 다이제스트)를 보장한다. 결정론적 빌드는 reproducible build 운동과 SLSA 보증의 토대다.

CI에서 가장 큰 절약은 BuildKit의 캐시 마운트와 외부 캐시(Buildx의 --cache-to type=registry)를 함께 쓰는 것이다.

한국 사례 — Naver Container Engine과 쿠팡의 컨테이너 런타임 흐름

한국은 자체 런타임을 만드는 것이 아니라 표준을 깊이 사용하는 쪽으로 성숙했다.

일본 사례 — Mercari의 containerd 이주, LY Verda 컨테이너

일본도 OSS 표준을 빠르게 채택한 쪽이다.

마이그레이션 패턴 — 도커 엔진에서 containerd로

레거시 환경에서 가장 흔한 마이그레이션은 도커 엔진 → containerd다. K8s 1.24에서 dockershim이 제거된 뒤 EKS·GKE·AKS·OpenShift 모두 자동으로 옮겼지만, 자체 운영 K8s는 여전히 일부 이주가 남아 있다.

이주 과정의 핵심은 (1) 노드의 컨테이너 런타임 교체, (2) 모니터링과 로깅 에이전트의 소켓 경로 변경(/var/run/docker.sock → /run/containerd/containerd.sock), (3) 사내 빌드 파이프라인이 도커 엔진에 의존하지 않도록 BuildKit·kaniko·buildah로 분리하는 것이다.

비용 · 운영 관점 — 어떤 조합을 고를까

2026년 5월 현재 추천 조합은 워크로드 성격에 따라 다음과 같다.

보안 베스트 프랙티스 — 2026년판 체크리스트

런타임 단위가 아니라 풀스택으로 챙겨야 할 항목이다.

마무리 — 컨테이너의 다음 10년

컨테이너는 끝나지 않았다. 그러나 "도커 컨테이너"라는 단일 모델은 끝났다. 2026년 5월 현재 컨테이너 인터페이스 뒤에는 namespaces+cgroups부터 마이크로 VM, 사용자공간 커널, Wasm 샌드박스까지 다섯 종류가 넘는 격리 메커니즘이 들어가 있다. OCI 표준이 그 다층을 연결한다.

앞으로 10년의 변화는 두 방향이다. 첫째, Wasm이 컨테이너의 일부 영역을 잠식한다. 에지, 플러그인, AI 추론에서 시작해 일반 백엔드로 확장될 가능성이 있다. 둘째, 컨피덴셜 컴퓨팅(AMD SEV-SNP, Intel TDX, ARM CCA) 기반 격리가 멀티테넌트·규제 워크로드의 표준이 된다. 두 흐름 모두 OCI와 K8s 표준 위에서 일어난다. 표준을 깊이 이해해 둔 팀이 가장 빠르게 적응한다.

References

댓글

아직 댓글이 없습니다.

로그인하면 댓글을 쓸 수 있습니다