Atlantis vs Spacelift, 1년 굴려보고 우리 팀이 내린 결론

작년 이맘때 Terraform 협업 도구를 새로 고르느라 한참 헤맸다. 그동안은 GitHub Actions 위에 얇은 래퍼 스크립트로 plan/apply를 돌렸는데, 모듈이 80개를 넘어가면서부터는 한계가 보였다. PR 코멘트에 plan 결과가 뒤죽박죽 붙고, 누가 언제 apply를 눌렀는지 추적이 안 되고, 가끔 두 사람이 같은 워크스페이스에 동시에 apply를 날려서 state lock 충돌이 나기도 했다.
결국 후보를 Atlantis와 Spacelift로 좁혔다. 둘 다 후보로 올린 이유는 단순했다. Atlantis는 공짜고 자체 운영이 익숙했고, Spacelift는 영업 미팅 한 번 했을 때 "이 정도면 우리 페인 포인트는 다 풀리겠다" 싶은 인상을 받았기 때문이다. 1년이 지난 지금 시점에서 솔직하게 비교해 보려고 한다.
우리가 봤던 것들
처음 비교할 때 정리한 표는 사실 별 의미가 없었다. 기능 매트릭스를 그려서 "Atlantis에 없는 게 7개, Spacelift에 없는 게 2개" 같은 식으로 보면 답은 뻔하다. 근데 그게 우리 팀에 진짜 중요한가는 다른 얘기다. 실제로 운영하면서 체감되는 차이만 추리면 이 정도였다.
드리프트 감지. Atlantis는 기본적으로 PR 이벤트 기반이라 누가 콘솔에서 리소스를 손대도 모른다. 별도 cron job으로 plan을 돌려서 diff를 확인하는 잡을 만들어 둘 수는 있는데, 우리도 그렇게 했었다. 문제는 알람이 너무 시끄러워서 결국 다들 무시했다는 것. Spacelift는 nightly drift detection이 빌트인이고, drift가 감지되면 별도 task로 분리해서 보여준다. 이 UX 차이가 운영자 입장에서 생각보다 컸다.
Policy-as-Code. Atlantis에서도 conftest를 plan 단계에 끼워 넣을 수는 있다. 우리도 그렇게 썼다. 근데 OPA 정책을 중앙에서 버전 관리하고, 어떤 stack에 어떤 정책 세트를 적용할지 매핑하는 건 또 직접 만들어야 한다. Spacelift는 이걸 정책 타입(plan policy, push policy, approval policy 등)으로 분리해서 제공한다. 처음에는 "이게 그렇게 중요한가" 싶었는데, 보안팀에서 "S3 버킷 public access 차단" 정책을 전체에 강제하라고 요구했을 때 차이가 확 드러났다.
워크스페이스 자체의 추상화. Atlantis는 atlantis.yaml에 적은 디렉토리가 곧 워크스페이스다. Spacelift는 stack이라는 개념이 있고, stack 위에 dependencies, contexts, runtime config 같은 게 얹힌다. 모듈을 다른 모듈의 output에 묶을 때, Atlantis에서는 remote state data source로 직접 참조해야 하고, Spacelift에서는 stack 간 trigger와 output 공유를 UI에서 묶을 수 있다. 이건 취향 영역이라고 생각한다.
우리는 어디서 결정이 갈렸나
표면적인 기능 비교에서 Spacelift가 우세하긴 했다. 그런데 결정의 무게추를 옮긴 건 다른 두 가지였다.
하나는 비용 구조다. 우리는 stack이 100개를 넘어가는데, 사용자 시트 기준이 아니라 worker 시간 + concurrent run 기준 과금이라 견적이 생각보다 빠르게 올라갔다. Atlantis는 EC2 한 대 + EFS + ALB 묶음으로 운영하면 월 100달러 안쪽이다. 1년이면 차이가 수만 달러 단위로 벌어진다.
다른 하나는 우리가 정말로 GitOps 워크플로우를 따르고 있느냐였다. Spacelift는 push/tag 기반 워크플로우도 강하게 지원한다. 근데 우리 팀은 PR 리뷰 → comment로 plan → 승인 → comment로 apply라는 흐름이 너무 익숙했고, 그 흐름이 우리 보안팀이 감사하기에도 편했다. 변경 요청-승인-적용이 PR 안에 한 줄로 박혀 있는 게 좋았다.
결국 우리가 고른 것
Atlantis로 갔다. 1년 굴려본 지금도 큰 후회는 없다. 다만 그동안 한 일들을 적어보면:
- conftest로 policy gate를 plan 단계에 박았다. 처음에 100% 시간이 들었다.
- 드리프트 감지용으로 별도 GitHub Actions cron을 만들어 매일 새벽에 전체 모듈을 plan만 돌렸다. 결과는 Slack으로 보내는데, 진짜 의미 있는 drift만 필터링하는 데도 시간을 좀 썼다.
- Atlantis 자체를 멀티 리전으로 띄우는 건 포기했다. EFS 백업과 EBS 스냅샷, 그리고 state는 S3 + DynamoDB lock이므로 Atlantis 자체가 잠시 죽어도 작업이 영구 손실되지는 않는다.
- TFE/HCP 기반의 "공식 도구"로 가지 않은 가장 큰 이유는 우리 stack 중 일부가 외부 망에 못 나가서다. self-hosted 가능성이 가장 컸다.
만약 우리가 보안팀 인력이 더 적고 policy를 만들 여력이 없었다면 Spacelift로 갔을 거다. 정책 프레임워크를 직접 짜는 노동이 만만치 않다. 반대로 우리처럼 이미 OPA 경험이 어느 정도 있고, 비용에 민감하고, PR 중심 흐름을 좋아한다면 Atlantis도 여전히 합리적인 선택이다.
올해 2분기쯤에 OpenTofu 1.10 LTS로 한 번 마이그레이션을 하려고 한다. Atlantis는 OpenTofu도 지원하니 그쪽은 큰 변수는 아닐 것 같다. 그때 새로 정리한 내용이 또 생기면 다음 글로 써보려고 한다.
다른 팀들은 어떻게 결정했는지 궁금하다. 비슷한 규모인데 Spacelift나 Scalr로 갔다는 분 있으면 후기 좀 들려주시면 좋겠다.