self-hosted CI runner에는 곤란한 특성이 하나 있습니다. 모든 것을 기억한다는 점입니다. 캐시, 토큰, 누군가 지난봄에 "임시로" 추가한 배포 키까지요. 우리 브랜치라면 괜찮습니다. 문제는 한 번도 들어 본 적 없는 사람이 pull request를 보냈을 때, 혹은 아직 아무도 읽지 않은 패치를 우리 AI 에이전트가 작성했을 때 시작됩니다.
깔끔한 답은 실행마다 머신 한 대를 쓰는 것입니다. 클론하고, 설치하고, 테스트하고, 머신을 버립니다.
실행은 이렇게 진행됩니다
샌드박스는 Python 3.12, Node.js 22, git, curl을 갖추고 약 1초 만에 시작되는 Firecracker microVM입니다. 외부로 나가는 인터넷은 되므로 git clone과 pip install -r requirements.txt가 평소처럼 동작합니다. 들어오는 포트는 없습니다. 실행 중인 테스트 환경에 외부에서 접속할 수 없습니다.
CI 작업 입장에서는 전체가 짧은 스크립트 하나입니다. 어느 CI 작업에서나 호출할 수 있는 Python SDK 버전은 다음과 같습니다.
import os, sys
from eqvps import Sandbox
repo, ref = os.environ["REPO_URL"], os.environ["PR_SHA"]
with Sandbox.create(tariff="standard", ttl=1800) as sb:
sb.exec(f"git clone {repo} /root/app && cd /root/app && git checkout {ref}", timeout=55)
sb.exec("cd /root/app && pip install -r requirements.txt", timeout=55)
task = sb.exec("cd /root/app && python3 -m pytest -q", background=True)
result = task.wait(on_output=lambda out, err: print(out, end=""))
sys.exit(result.exit_code or 0)
토큰은 CI 시크릿에 EQVPS_API_KEY로 저장합니다. 배포 키나 클라우드 자격 증명 등 CI의 다른 것은 샌드박스에 들어가지 않습니다. with 블록이 끝나면 샌드박스가 삭제되며, 작업이 중간에 실패해도 마찬가지입니다.
테스트 실행 자체는 백그라운드 작업입니다. 동기 명령 하나는 55초에서 멈추기 때문입니다. 백그라운드 작업은 실행 중에 출력을 스트리밍하고 샌드박스의 TTL까지 계속될 수 있습니다. 여기서는 멈춘 테스트 때문에 요금이 불어나지 않도록 30분으로 설정했습니다.
실제로 마주칠 제한
이걸 솔직하게 알려 드리면 오후 한나절을 아낄 수 있습니다.
동시 실행. 계정은 샌드박스를 20개까지 가질 수 있지만, 동시에 실행되는 명령은 2개뿐입니다. CI에서는 진짜로 병렬로 도는 작업이 2개라는 뜻입니다. 한꺼번에 들어온 PR 10개는 대기열에 들어갑니다. 파이프라인이 테스트를 워커 16개로 나눈다면 메인 파이프라인에는 맞지 않는 도구입니다. 메인은 VPS의 자체 runner에 두고, 신뢰할 수 없는 레인에만 샌드박스를 쓰세요.
내부에서 컨테이너를 쓸 수 없습니다. 샌드박스에는 Docker가 없습니다. Postgres 컨테이너가 필요한 단위 테스트와 통합 테스트는 그대로는 동작하지 않지만, SQLite나 메모리 내 가짜 객체를 쓰는 테스트는 동작합니다.
파일. API를 통한 업로드와 다운로드는 파일당 최대 5 MB입니다. 압축 파일을 올리지 말고 샌드박스 안에서 git으로 코드를 받으세요.
비용
요금제의 vCPU와 RAM을 초 단위, 최소 60초로 선불 잔액에서 지불합니다. 구독은 필요 없습니다.
| 실행 | 요금제 | 대략적인 비용 |
|---|---|---|
| Lint + 단위 테스트, 1분 | small (0.5 vCPU, 1 GB) | $0.0006 |
| 전체 스위트, 3분 | standard (1 vCPU, 2 GB) | $0.0033 |
| 빌드 + 테스트, 10분 | plus (2 vCPU, 4 GB) | $0.022 |
이 가격대에서 중요한 질문은 비용이 아니라, 설정한 시간 안에 테스트가 끝나느냐입니다. 가장 느린 성공 실행보다 조금 여유 있게 TTL을 잡으세요.
합리적인 역할 분담
권장하는 방식은 이렇습니다. 신뢰할 수 있는 브랜치는 캐시가 있는 빠른 runner에 그대로 둡니다. 직접 작성하지 않은 모든 것, 즉 포크, 외부 기여자, 에이전트가 생성한 패치는 먼저 샌드박스를 거치게 합니다. 샌드박스 실행이 성공하고 사람이 diff를 확인했다면, 신뢰하는 파이프라인으로 올립니다.
이렇게 하면 속도와 캐시가 중요한 레인과 깨끗한 머신이 중요한 레인을 나눌 수 있고, 도구 하나에 두 역할을 억지로 맡기지 않아도 됩니다.
샌드박스 개요와 연결 가이드부터 시작하세요. 새 계정에는 샌드박스 사용 시간 $1이 제공되며, 짧은 테스트라면 수백 번 실행할 수 있습니다. 위에서 쓴 메서드는 모두 SDK 레퍼런스에, 정확한 과금 규칙은 샌드박스 제한과 과금에 있습니다.
관련 글: 코드 리뷰와 PR 검사를 위한 샌드박스, AI 에이전트용 샌드박스.
댓글
아직 댓글이 없습니다. 첫 번째가 되세요.