TL;DR
- 웜 스냅샷(warm snapshot)에서 시작하는 임시 마이크로VM(microVM) 러너를 쓰면, 매 작업마다 캐시를 복원하고 저장하는 대신 로컬 디스크에 빌드 상태가 준비된 환경으로 CI를 실행할 수 있음.
- 기존의 장기 실행 빌드 서버는 상태가 누적되고 빌드끼리 영향을 주는 문제가 있었지만, 이전 빌드의 Docker 레이어와 패키지가 디스크에 남는 장점도 있었음.
- GitHub Actions의 일반적인 Node 및 Docker 워크플로는
~/.npm, BuildKit 캐시 마운트, 이미지 레이어를 위한 세 종류의 캐시와 각각의 키·제한·설정 작업을 관리해야 함. - 예시상 웜 마이크로VM은 러너 시작 시간을 10~30초에서 1초 미만으로 줄이고, 전체 실행 시간을 약 2.5~4분에서 30~40초로 낮춤.
- 웜 러너는 작업별 격리와 자체 커널을 제공하며, 성공한 기본 브랜치 빌드의 상태를 다음 스냅샷에 반영하고 풀 리퀘스트는 스냅샷을 읽기만 하도록 구성할 수 있음.
익숙해진 복잡한 설정
- 장기 실행 빌드 서버는 상태가 쌓이고 빌드끼리 영향을 주어 유지 관리가 번거로웠지만, 이전 빌드의 Docker 레이어와 패키지가 디스크에 남아 항상 준비된 상태였음.
- 격리와 재현성을 높이고 관리 부담을 줄이기 위해 GitHub Actions와 GitLab이 관리하는 임시 러너로 옮겼지만, 모든 작업이 깨끗한 머신에서 시작하면서 환경을 매번 처음부터 다시 구축해야 함.
- 일반적인 Node 앱은
npm ci실행, 테스트, Docker 이미지 빌드로 구성되며, 적절히 캐시를 적용한 GitHub Actions 워크플로에는 여러 설정이 들어감. actions/setup-node는~/.npm을 캐시함.- BuildKit 캐시 마운트를 보존하려면 별도의 캐시 설정과
reproducible-containers/buildkit-cache-dance같은 서드파티 액션이 필요함.RUN --mount=type=cache만으로는 새 러너에서 캐시가 유지되지 않기 때문임. cache-from과cache-to는 이미지 레이어를 캐시함.- 결과적으로 세 종류의 캐시 각각에 키, 제한, 고유한 동작 방식을 관리해야 하며, 캐시를 작업 시작 때 네트워크에서 내려받고 종료 때마다 다시 올려야 함.
발상: 머신 전체를 캐시로 사용
- 최신 마이크로VM은 메모리와 디스크 스냅샷에서 1초 미만에 시작할 수 있음. 빈 이미지에서 출발해 캐시를 복원하는 대신, Docker와 이미지 레이어,
~/.npm, pip 캐시, 빌드 도구가 로컬 디스크에 있는 웜 스냅샷으로 새 러너를 시작하는 방식임. - 각 러너는 여전히 일회용이며 재사용되지 않지만, 부팅 기준이 되는 스냅샷이 상태를 이어받음.
- 기본 브랜치에서 빌드가 성공할 때마다 그 환경이 다음 스냅샷이 되어 CI 실행이 거듭될수록 환경이 따뜻해짐.
- 풀 리퀘스트는 최신 기본 브랜치 스냅샷으로 부팅하지만 스냅샷에 변경 사항을 기록하지 않으므로, 문제가 있는 브랜치가 다른 작업의 캐시를 오염시키지 않음.
- 웜 러너에서는
npm ci,npm test,docker build,docker push같은 일반 명령으로 워크플로를 구성함. ~/.npm이 이미 디스크에 있어npm ci에서 내려받을 항목이 거의 없음.- 기본 이미지, Docker 레이어, 캐시 마운트가 로컬에 있어 변경된 애플리케이션 코드에 해당하는 레이어만 다시 빌드함.
- 캐시 키, Buildx 설정, 캐시 전달용 액션이 필요하지 않음. 일반 머신에서 두 번째 실행이 빠른 것과 같은 이유로 캐시가 이미 준비되어 있으며, 아직 없는 항목은 보통의 머신에서처럼 내려받거나 빌드함.
- 캐시 관리는 워크플로 로직이 아니라 인프라가 담당하며, 워크플로는 임시 머신의 캐시를 관리하는 방법 대신 빌드할 대상을 설명함.
실행 시간은 어디에 쓰이는가
- 다음 수치는 일반적인 Node 서비스의 예시이며 벤치마크 결과가 아님.
- 러너 시작: 깨끗한 러너와 캐시 구성 10~30초, 웜 마이크로VM 1초 미만.
- 네트워크를 통한 캐시 복원: 20~60초, 웜 마이크로VM은 이미 디스크에 있어 0초.
npm ci: 30초, 웜 마이크로VM 10초.- 애플리케이션 코드만 바뀐
docker build: 60~90초, 웜 마이크로VM 10~15초. - 캐시 저장: 15~40초, 웜 마이크로VM은 작업 뒤 스냅샷이 생성되므로 0초.
- 총 실행 시간: 깨끗한 러너와 캐시 구성 약 2.5~4분, 웜 마이크로VM 약 30~40초.
- 가장 큰 이점은 특정 한 단계의 속도가 아니라, 추가하는 캐시가 많아질수록 커지는 복원·저장 오버헤드가 완전히 사라진다는 점임.
실제 가상 머신의 이점
- 속도 외에도 마이크로VM은 자체 커널을 갖춘 실제 가상 머신이며, 오랫동안 이어진 CI의 여러 불편을 해결함.
- 실제 격리: 각 작업이 공유 커널이 아니라 하드웨어 가상화 경계 뒤에서 실행됨. 테스트 대상 코드가 AI 에이전트가 작성한 코드일 때 중요성이 커짐.
- Docker-in-Docker 불필요: 러너가 자체 Docker 데몬을 사용하므로 권한 있는 컨테이너, 소켓 마운트, Kubernetes 러너의 DinD 사이드카가 필요하지 않음.
- 일반적인 Linux 환경:
systemd와 일반적인 방식으로 시작하는 PostgreSQL, Redis 등의 서비스가 작동하며, 머신 전체를 전제로 하는 다른 도구도 사용할 수 있음. - 필요한 상태 유지: 상태가 여러 캐시 키 더미가 아니라 스냅샷에 저장됨.
지금 중요한 이유
- AI 도구는 팀이 수작업으로 만든 것보다 더 많은 코드를 더 작고 빈번한 변경으로 생성하며, 각각의 변경은 CI를 거침.
- 코딩 에이전트는 CI 결과를 기다리고 수정한 뒤 다시 푸시하는 방식으로 CI를 반복 활용함. 느린 CI가 개발자의 커피 한 잔 시간만 소모하던 때와 달리, 이제는 전체 반복 과정의 병목이 됨.
- CI를 더 빠르게 해야 할 뿐 아니라 테스트, 보안 검사, 엔드투엔드 점검도 늘려야 함. 사람이 한 줄씩 작성하지 않은 코드가 더 많기 때문임.
- 실행의 기본 비용을 거의 0에 가깝게 낮춰야 추가 검사를 감당할 수 있으며, 웜 러너는 그 비용 여유를 되돌려 줌.
다음 단계
- 실제 워크플로 하나를 웜 스냅샷에서 부팅한 마이크로VM 러너로 실행하고, 모든 캐시 단계를 삭제한 뒤 측정하는 간단한 실험을 진행 중임. 실제 수치를 공개할 예정임.
- 더 큰 구상은 새로운 CI 시스템을 만드는 것이 아님. GitHub Actions, GitLab CI, Buildkite가 계속 워크플로를 실행하고, 그 아래 계층만 바뀌는 방식임.
- GitHub Actions에는 이미 이를 위한 연결 지점이 있음. 작업이 대기열에 들어오면 제공 업체가 최신 웜 스냅샷에서 마이크로VM을 부팅하고, 해당 작업 하나만을 위한 JIT 러너로 등록한 뒤 작업이 끝나면 폐기할 수 있음.
- 개발자 입장에서는
runs-on: ubuntu-latest를runs-on: warm-runner로 바꾸고 더는 필요하지 않은 캐시 단계를 삭제하면 됨. - 마이크로VM 인프라를 직접 구축하고 운영하고 싶지는 않으며, Boxd, Daytona, Modal 같은 제공 업체가 빠른 부팅, 스냅샷, 대규모 격리의 어려운 부분을 이미 해결하고 있음.
- 남은 부분은 GitHub 조직 연결, 스냅샷 승격 시점 선택,
runs-on설정을 이어 주는 통합임. 해당 플랫폼을 구축하는 이들이라면 기대하는 통합임.
댓글 (0)
로그인하면 이 기사에 내 생각을 남길 수 있어요