
AWS Lambda MicroVMs: VM 수준의 격리를 통해 관리 인프라 없이 신뢰할 수 없는 코드를 실행하기
요약
AWS가 Firecracker 기반의 Lambda MicroVMs를 출시하여 VM 수준의 격리와 즉각적인 실행 성능을 동시에 제공합니다. 이를 통해 신뢰할 수 없는 코드를 최대 8시간 동안 상태를 유지하며 안전하게 실행할 수 있는 새로운 서버리스 환경을 구축할 수 있습니다.
핵심 포인트
- Firecracker 기반의 VM 수준 격리 제공
- 최대 8시간 동안 실행 상태(state) 유지 가능
- 컨테이너의 속도와 VM의 보안성을 결합한 새로운 프리미티브
- AI 에이전트 코드 실행 및 멀티 테넌트 환경에 최적화
AWS가 방금 Lambda MicroVMs를 출시했습니다. 이는 Firecracker를 기반으로 각 사용자 또는 세션에 **VM 수준의 격리된 샌드박스 (sandbox)**를 제공하며, 즉각적인 실행과 최대 8시간 동안 상태가 유지되는 (state preserved) 새로운 서버리스 프리미티브 (primitive)입니다. 이것이 무엇인지, 일반적인 Lambda Function 대신 언제 사용해야 하는지, 그리고 이를 기반으로 어떻게 아키텍처를 설계하는지에 대해 알아보겠습니다.
🇧🇷 포르투갈어로 읽기.
상황을 하나 가정해 보겠습니다. 당신은 직접 작성하지 않은 코드를 실행해야 합니다. 사용자가 당신의 플랫폼에 붙여넣은 스크립트일 수도 있고, AI 에이전트가 방금 생성하여 실행하고자 하는 코드 조각일 수도 있습니다. 그러면 멀티 테넌트 (multi-tenant) 환경에서 작업하는 모든 이들을 밤잠 설치게 만드는 질문이 떠오릅니다. '낯선 사람에게 집 열쇠를 넘겨주지 않고 어떻게 이 코드를 실행할 수 있을까?'
지난주까지는 세 가지 경로가 있었지만, 각각에는 문제점이 있었습니다. VM은 강력한 격리 (isolation)를 제공하지만 부팅하는 데 몇 분이 걸립니다. 컨테이너 (container)는 몇 초 만에 시작되지만 커널 (kernel)을 공유하므로, 신뢰할 수 없는 코드를 실행하려면 엄청난 수준의 하드닝 (hardening) 작업이 필요합니다. 그리고 Lambda Function은 짧은 요청-응답 (request-response)을 위해 구축되었으며, 한 상호작용과 다음 상호작용 사이에 라이브 상태 (live state)를 유지해야 하는 세션을 위한 것이 아닙니다 (데이터를 DynamoDB로 외부화하는 것은 데이터를 저장하는 것이지, 실행 중인 런타임(running runtime), 즉 실행 중인 프로세스, 로드된 패키지, 메모리를 유지하는 것이 아닙니다). 결국 당신은 성능과 격리 사이에서 하나를 선택해야만 했습니다. 피할 수 없는 선택이었습니다. 하지만 이제 방법이 생겼습니다.
컨테이너, VM, 또는 Lambda: 그 어느 것도 단독으로는 해결하지 못한 트레이드오프 (trade-off)
이러한 패턴은 흔해졌습니다: AI 코딩 어시스턴트, 대화형 코드 환경, 분석, 취약점 스캐너, 플레이어 스크립트를 실행하는 게임 서버 등. 이들은 모두 동일한 것을 필요로 합니다: 팀이 작성하지 않은 코드를 안전하고 지연 없이 실행할 수 있도록 각 사용자에게 고유한 환경을 제공하는 것입니다.
문제는 진정한 격리(isolation)와 낮은 지연 시간(low latency)이 서로 반대 방향을 향하고 있다는 점입니다. 보안 측면에서는 테넌트(tenant) 간의 강력한 경계가 필요합니다 (Well-Architected Framework의 보안 기둥: 신뢰할 수 없는 것을 격리하십시오). 반면 사용자 경험 측면에서는 사용자가 나타나는 즉시 환경이 준비되기를 원합니다. 이 두 가지를 조화시키는 것이 비용이 많이 드는 작업이었습니다.
그리고 이 이야기에는 흥미로운 아이러니가 있습니다. 우리는 수년 동안 상태가 없는(stateless) 앱을 구축하는 법을 배웠는데, 이제는 다시 상태(state)가 요구 사항이 되었습니다.
미래를 위한 해결책은 과거 속에 숨겨져 있었다.
친구가 대화 중에 툭 던진 이 한마디는 그 이후로 제 머릿속을 떠나지 않았습니다. 그런 기분을 느껴본 적이 있나요? 저는 그랬습니다. 그리고 이것이 대략 Lambda MicroVMs가 하는 일입니다. 즉, 완전한 VM의 무게를 지우지 않으면서 상태(state)를 다시 가져오는 것입니다.
Lambda MicroVMs란 무엇인가
Lambda MicroVMs는 바로 그 간극을 메우기 위해 Lambda 내부에 구축된 새로운 프리미티브(primitive)입니다. 각 MicroVM은 단일 사용자 또는 세션에 대해 빠르게 부팅되고, 전체 세션 동안 메모리와 디스크를 유지하며, 사용자가 자리를 비울 때 저렴한 비용으로 일시 중지(pause)되는 고유한 격리 환경을 제공합니다.
이 마법은 이미 매달 15조 회 이상의 Lambda 호출에서 실행되고 있는 것과 동일한 경량 가상화 기술인 Firecracker에서 나옵니다. 이것은 완전히 새로운 기술이 아니라, 새로운 방식으로 노출된 Lambda 자체의 성숙한 기반입니다.
모델은 이미지 생성 후 실행(image-then-launch) 방식입니다:
**이미지(image)**를 한 번 빌드하면 됩니다 (AWS가 Dockerfile을 실행하고, 앱을 초기화하며, 메모리와 디스크의 스냅샷을 찍습니다). 그 후, 실행되는 모든 MicroVM은 콜드 부팅(cold-booting) 대신 해당 스냅샷에서 재개(resume)됩니다. 이것이 수 기가바이트 규모의 세션에서도 실행(launch)과 재개(resume)가 거의 즉각적인 이유입니다.
이것이 실제로 무엇을 위한 것인가 (당신이 알 만한 예시와 함께)
핵심적인 단서는 다음과 같습니다: 이것은 오직 여러분이 제3자 코드(third-party code)를 실행하는 플랫폼을 구축할 때만 고려 대상이 됩니다. 만약 여러분의 앱이 외부 코드를 실행하지 않는다면, 이것은 필요하지 않습니다. 이것은 다음과 같은 제품을 만드는 사람들을 위한 빌딩 블록(building block)입니다:
- Replit, CodeSandbox, "브라우저 내 VS Code": 사용자가 브라우저에서 코드를 입력하면, 탭이 열려 있는 동안 상태(state)를 유지하며 사용자별로 격리되어 실행됩니다. 그 "격리되어 실행되는 것"이 바로 MicroVM입니다.
- 코드 인터프리터 (ChatGPT나 Claude의 것과 같은): 사용자가 "이 CSV를 그래프로 그려줘"라고 요청하면, AI는 Python 코드를 작성하고 답변을 위해 그 코드를 실행합니다. 대화별로 격리되어 생성된 코드를 실행하는 런타임(runtime)이 바로 이 사용 사례에 해당합니다.
- CI/CD 러너 (및 관련 도구들): 정의상 신뢰할 수 없는, 즉 아무 낯선 이의 포크(fork)에서 올 수 있는 Pull Request의 코드를 실행하는 작업(job)이 있습니다. 따라서 작업당 격리되고 일회성인 러너(runner)가 필요합니다. 같은 계열로는 의심스러운 바이너리를 실행하는 스캐너, 코딩 인터뷰 플랫폼 (지원자의 코드가 격리되어 실행됨), 셸 명령어를 실행하는 AI 에이전트 등이 있습니다.
이 모든 것을 관통하는 실마리는 다음과 같습니다: 각 사용자, 세션 또는 작업은 자신만의 격리된 환경이 필요하며, 그곳에서 실행되는 코드는 여러분이 작성한 코드가 아닙니다. 이것이 Lambda Function 대신 MicroVM을 사용해야 하는 신호입니다.
Lambda Function인가, Lambda MicroVM인가?
이 둘은 경쟁 관계가 아니라 서로를 보완하는 관계입니다. 공식적인 비교는 다음과 같습니다:
| Lambda Functions | Lambda MicroVMs | |
|---|---|---|
| 최적의 용도 | 요청-응답(request-response) 또는 이벤트 기반 (API, 데이터 처리, 자동화) | 사용자 또는 AI가 생성한 신뢰할 수 없는 코드를 실행하는 지속적인 환경 |
| ... |
가장 흔한 혼동은 사람들이 실행 시간(duration)이 Lambda와 같을 것이라고 가정하는 것입니다. 시작(startup) 방식은 유사하지만 (둘 다 스냅샷에서 재개됨), Function은 15분 후에 종료되는 반면, MicroVM은 상태를 유지한 채 최대 8시간 동안 세션을 유지합니다. 실제 설계 방식은 이렇습니다: 여러분의 앱은 이벤트 기반의 중추(backbone) 역할을 위해 Lambda Functions를 유지하고, 격리된 환경에서 신뢰할 수 없는 코드를 실행해야 하는 단계에서만 MicroVM을 호출합니다.
실제 작동 방식: 엔드포인트부터 오케스트레이션까지
처음에 사람들이 흔히 혼동하는 세 가지 요소가 있습니다.
엔드포인트에는 상태(status)가 있습니다. run-microvm을 호출하면 해당 MicroVM에 대한 ID와 전용 HTTPS 엔드포인트(endpoint)를 받게 됩니다. 하지만 즉시 준비되는 것은 아닙니다. 실행(launch) 단계부터 RUNNING 상태(약 2초 소요)까지 상태 변화를 거치며, 유휴(idle) 상태가 되면 일시 중단(suspended) 상태로 전환되었다가 재개(resume) 시 다시 돌아옵니다. 엔드포인트는 MicroVM별, 세션별로 생성됩니다.
하나의 이미지로 여러 개의 MicroVM 생성. 이미지는 한 번만 빌드(create-microvm-image)하며, 각 MicroVM은 run-microvm을 통해 생성됩니다. 두 개가 필요하다면? 두 번 호출하면 됩니다. 그러면 두 개의 독립적인 인스턴스를 얻게 됩니다. 유휴 동작은 idle-policy에 의해 제어됩니다: maxIdleDurationSeconds(X초 유휴 후 일시 중단) 및 autoResumeEnabled(다음 요청 시 수동 재시작 없이 약 1초 내에 MicroVM이 자동으로 깨어남)가 있습니다. 작업이 완료되면 terminate-microvm을 통해 모든 자원을 해제합니다.
당신이 오케스트레이터(orchestrator)가 됩니다. 엔드포인트가 세션별로 존재하기 때문에, 언제 실행하고 어디로 라우팅할지를 결정할 무언가가 필요합니다. 일반적으로 백본(backbone)에 있는 Lambda Function이 이 역할을 수행합니다. 이 함수는 session -> MicroVM 매핑(운영 환경에서는 DynamoDB와 같은 저장소 사용)을 유지하며, 사용자의 첫 접속 시 RunMicrovm을 호출하고, ID와 엔드포인트를 저장하며, CreateMicrovmAuthToken으로 수명이 짧은 토큰을 발행한 뒤, X-aws-proxy-auth 헤더와 함께 요청을 MicroVM의 엔드포인트로 프록시(proxy)합니다. 만약 인스턴스가 일시 중단된 상태이고 autoResume이 활성화되어 있다면, 요청 자체가 인스턴스를 깨웁니다. 여기에 고립된(orphan) MicroVM을 종료하는 루틴을 추가하면 기본 골격이 완성됩니다. 백본 코드는 이 시리즈의 다음 포스트에서 다룹니다. 그리고 이것을 Step Functions와 혼동하지 마세요. MicroVM은 실행 환경(execution environment)이고, Step Functions는 오케스트레이터(orchestrator)로, 서로 다른 계층(layer)입니다.
비용, 제한 사항, 그리고 아직 부족한 점
비용은 세부 사항이 아니라 결정 사항입니다. Werner Vogels는 비용이 청구서에서 나중에 발견하게 되는 숫자가 아니라, 아키텍처 요구 사항이라는 점을 **Frugal Architect (검소한 아키텍트)**를 통해 계속해서 강조하고 있습니다. 일시 중단(suspend) 기능은 실제로 바로 그 점을 실현합니다. VM 수준의 격리(isolation)를 위해 많은 비용을 지불하지만, 사용자가 활성 상태일 때만 비용이 발생합니다. 사용자가 떠나면 MicroVM은 일시 중단되어 상태(state) 손실 없이 비용이 감소합니다. 의도적으로 idle-policy를 설계하는 것은 비용에 관한 결정입니다. 공식 표에 따른 모델은 다음과 같습니다: 실행 중인 컴퓨팅 초당으로 비용을 지불하며, 일시 중단된 동안에는 스냅샷 스토리지(snapshot storage) 비용만 지불합니다. 단가는 Lambda pricing page에서 확인할 수 있습니다.
제한 사항: MicroVM당 ARM64, 최대 16 vCPU, 32GB 메모리, 32GB 디스크를 지원하며, 총 실행 시간은 최대 8시간입니다. 프로비저닝(Provisioning)은 유연합니다. 기준선(baseline)을 설정하고 피크 시 최대 4배까지 버스트(burst)할 수 있으며, 실행 중에는 기준선에 대해서만 비용을 지불합니다.
IaC (Infrastructure as Code): 콘솔, CloudFormation, 그리고 CDK를 사용할 수 있습니다.
왜 미리 빌드된 ECR 이미지가 아니라 Dockerfile + zip을 사용하나요? Aidan Steele이 이를 심층 분석했습니다: Lambda는 Graviton 3용과 Graviton 4용으로 이미지의 두 가지 복사본을 빌드하므로, 재컴파일을 위한 소스(source)가 필요합니다. 베이스(base)는 ECR Public에서 가져오지만, 프라이빗 ECR에서 미리 빌드된 이미지를 아티팩트(artifact)로 푸시하는 방식은 권장되는 경로가 아닙니다. 컨테이너를 사용하던 사람들이 혼란스러워하는 한 가지는 다음과 같습니다: ECR이 당신의 삶에서 떠나지 않는다는 점입니다. ECR을 통해 MicroVM 이미지를 **전달(deliver)**하는 것이 아니라, 실행 중인 MicroVM 내부에서 Docker를 실행하고 런타임에 프라이빗 ECR 이미지를 docker pull 할 수 있습니다. ECR은 이미지 자체를 전달하기 위한 것이 아니라, 내부에서의 소비를 위한 것입니다.
네트워킹 및 리전: 구성 가능한 포트(HTTP/2, gRPC, WebSockets)를 통한 인바운드 트래픽, 서비스 제공 JWE 인증, 인터넷 또는 VPC로의 아웃바운드 트래픽을 지원합니다. 현재까지는 US East (N. Virginia, Ohio), US West (Oregon), Europe (Ireland), 그리고 Asia Pacific (Tokyo)에서만 사용할 수 있습니다.
사용하지 말아야 할 때
워크로드가 상태(state)가 없는 짧은 요청-응답(request-response) 형태라면, 그것은 Lambda Function으로 남습니다. 그 상황에서 MicroVM을 사용하는 것은 모기를 잡기 위해 대포를 사용하는 격입니다. 또한, 단지 본인의 (신뢰할 수 있는) 코드로 15분 이상의 실행 시간이 필요할 뿐이라면, MicroVM 역시 과잉 사양(overkill)입니다. 긴 작업이 필요하다면 Fargate를, 다단계 워크플로우(multi-step workflow)가 필요하다면 Lambda Durable Functions(표에 표시된 대로 최대 1년까지 가능)를 살펴보세요. MicroVM은 단순히 15분을 넘기는 것이 목적이 아니라, 신뢰할 수 없는 코드(untrusted code)를 격리하는 것이 차별점일 때 사용해야 합니다.
AWS 스스로도 경고하는 주의 사항이 하나 있는데, 이는 결정론(determinism)에 관한 논의와 맥을 같이 합니다. MicroVM은 사전 초기화된 스냅샷(Aidan Steele이 테스트를 통해 확인한 바와 같이 Lambda SnapStart와 동일한 방식)으로부터 부팅되기 때문에, 초기화(init) 시점에 고유한 콘텐츠를 생성하거나, 연결을 열거나, 휘발성 데이터(ephemeral data)를 로드하는 앱은 결과가 달라질 수 있습니다. 스냅샷은 특정 순간을 동결한 것이므로, 세션마다 새로워져야 하는 요소들은 스냅샷과 함께 동결될 수 없습니다. 이에 대한 해결책은 **라이프사이클 훅(lifecycle hooks)**이라 불리며, 각 MicroVM이 생성될 때 무작위성(randomness)을 재초기화하는 역할을 합니다. 그냥 잘 작동할 것이라고 가정하기 전에 이 부분을 먼저 설계하십시오.
컨테이너를 대체하는가?
아니요, 그리고 그 이유는 훨씬 더 좋습니다.
이번 주의 화두는 "컨테이너는 구식이다"라는 것입니다. 하지만 그렇지 않습니다. 오히려 그 반대입니다. Aidan Steele는 테스트를 통해 OS 기능이 활성화된 상태로 MicroVM 내부에서 Docker를 실행할 수 있음을 확인했습니다. 따라서 MicroVM은 컨테이너를 없애는 것이 아니라, 더 격리된 환경을 제공하며 여전히 그 내부에서 컨테이너를 실행합니다. 솔직한 결론은 이렇습니다. 신뢰할 수 없는 코드를 격리된 상태로 실행해야 하는 특정한 지점, 즉 컨테이너를 수동으로 강화(harden)하고 싶지 않은 영역에서는 MicroVM이 승리합니다. 그 외의 모든 곳에서는 여전히 컨테이너가 왕입니다.
문서에서 생략된 세부 사항들
Aidan Steele는 출시 당일에 해당 서비스를 파헤치며 공식 문서에는 없는 매우 흥미로운 사실들을 발견했습니다.
저도 이를 읽어보았고, 이곳에 소개할 가치가 있다고 판단했습니다:
- MicroVM에 쉘(shell) 접속이 가능합니다.
CreateMicrovmShellAuthTokenAPI를 통해 pty를 일급 시민(first-class citizen)으로 지원하며 접속할 수 있습니다 (Lambda Functions는 이를 지원하지 않습니다). 이는 IDE 및 코딩 에이전트(coding-agent) 사용 사례에 매우 유용합니다. - 아웃바운드 UDP(Outbound UDP)는 기본적으로 차단되어 있으며, DNS는 로컬 스텁(local stub)입니다. 따라서 컨테이너 내부의 DNS는 8.8.8.8로 폴백(fallback)되어 실패하게 됩니다. 해결 방법은 Lambda의 DNS를 사용하여 실행하는 것입니다:
docker run --dns 169.254.169.253, 또는 VPC를 통해 연결하는 것입니다. - Lambda 네트워크 커넥터(Lambda network connectors): 자체적인 생명주기(lifecycle)를 가진 구체화된(reified) VPC 설정(서브넷, 보안 그룹, ENI를 위한 IAM 역할)입니다. 네트워크 팀이 이를 생성하면, 개발자는 이를 단순히 소비하기만 하면 됩니다.
- 성능 (그의 테스트 결과): 이미지 빌드에 2~3분;
RunMicrovm호출 후 RUNNING 상태까지 약 2초, 서비스 제공까지 추가 2초; 일시 중단(suspend) 및 재개(resume)에는 각각 약 1초가 소요됩니다.
핵심 요약 (What you take away)
AI 자동 생성 콘텐츠
본 콘텐츠는 Dev.to AI tag의 원문을 AI가 자동으로 요약·번역·분석한 것입니다. 원 저작권은 원저작자에게 있으며, 정확한 내용은 반드시 원문을 확인해 주세요.
원문 바로가기