한 달에 빌드 천 번 — 그런데 한 번도 돈이 들지 않아요 ⚙️
먼저 정정할 게 있어요. 이 글의 첫 버전은 GitHub 빌드 시간이 다 떨어져서 Pro 계정으로 올릴 수밖에 없었다고 썼어요. 그건 틀렸어요. 문서를 한 번만 봤어도 풀렸을 일이에요. 공개 저장소에서는 GitHub 빌드 시간이 무료예요. 아티팩트와 캐시도요. 저희 저장소는 5월 말부터 공개였으니, 단 1분도 돈을 낸 적이 없고 앞으로도 낼 일이 없어요. 글을 슬쩍 고치는 대신 새로 쓰고, 측정으로 실제로 드러난 걸 알려 드리고 싶어요. 틀린 버전보다 훨씬 더 흥미로운 이야기거든요.
먼저 추측하고, 나중에 확인했어요. 계기는 어느 저녁이었어요. 다 만든 풀 리퀘스트가 브라우저에 떠 있는데 검사가 하나도 시작되지 않았어요. 초록 체크도 없이 조용하기만 했죠. 저희는 가장 뻔한 설명인 “할당량 소진”을 떠올리고 Pro 계정을 샀어요. 그 뒤로 다시 다 돌아가서 가설이 맞는 것 같았어요. 아니었어요. 조용했던 데는 다른 이유가 있었어요(그 순간 GitHub가 메인 브랜치와 깔끔하게 병합할 수 없는 풀 리퀘스트는 검사를 시작하지 않아요). 그 뒤로 모든 실행의 청구 데이터를 하나하나 조회했어요. 모든 실행, 모든 운영체제에서 답은 같았어요. 청구 대상 시간 = 0밀리초. 구독으로 플랫폼을 응원하는 건 얼마든지 좋은 일이에요. 하지만 이 저장소의 설명으로는 맞지 않아요.
사실인 것: 기계가 커졌어요. 풀 리퀘스트마다 작은 공장이 돌아가요. 서버 전체를 빌드하고 테스트 묶음을 돌리고, 린터와 코드 분석이 살펴보고, CodeQL이 보안 구멍을 찾고, 게임 서버, 포털, WorldHost, AI 백엔드용 Docker 이미지를 만들어요. 릴리스에는 클라이언트의 Windows, Linux, macOS 빌드와 브라우저 게임용 WebGL 버전이 더해져요. 5월 말부터 모두 합하면 빌드 실행 1,723번이고, 그중 1,092번이 7월 한 달에만 있었어요. 4주 동안 병합된 풀 리퀘스트가 131개였어요. 그리고 네, 최근의 급증은 정말로 AI와 관련이 있어요 😉. 이 프로젝트는 100% AI의 도움으로 개발되고, 더 큰 구독 덕분에 더 많은 일이 동시에 일어나요. 다만 그 대가는 돈이 아니라 기다리는 시간이에요.
기다리는 시간은 어디로 갈까요. 8일 동안 측정했더니 일반 검사 실행(CI)이 379분, CodeQL 보안 분석이 230분, 릴리스 빌드가 126분이고, 나머지는 잔돈이에요. 릴리스 하나에 컴퓨팅 시간이 약 110분 들고, WebGL(31.6), Docker 이미지(19.4), macOS(13.7), Linux(13.7), 큰 테스트 관문(12.1), Windows(10.9), 패키징(7.2)으로 나뉘어요. “완성”에서 “여러분이 설치할 수 있는 상태”까지 걸리는 시간이에요.
그리고 정말로 부족한 것은 캐시예요. 빌드가 매번 처음부터 시작하지 않도록 GitHub는 중간 결과를 저장해 주는데, 이건 저장소가 아무리 공개여도 저장소당 10GB까지예요. 저희는 지금 63개 항목에 5.3GB를 쓰고 있어요. 문제는 분포예요. 약 3분의 2가 매 실행마다 다시 올라가는 Docker 중간 레이어이고, 그 때문에 가장 도움이 될 것들이 밀려나요. 이게 진짜 병목이고, 어떤 구독으로도 해결할 수 없어요.
가장 반가운 발견은 진짜 버그였어요. 빌드할 때 Unity는 거대한 중간 폴더(Library)를 만드는데, 이걸 재사용하면 몇 분을 아껴요. 측정해 보니 Windows, Linux, macOS에서는 그 폴더가 한 번도 저장되지 않았어요. 빌드는 열심히 복원하려 했지만 아무도 써 놓은 적이 없었어요. 그리고 Windows 빌드만 플랫폼 표시가 없는 캐시 키를 썼어요. 그래서 1.7GB의 WebGL 중간 상태를 내려받았고, Unity는 그걸 성실하게 버리고 전부 다시 가져왔어요. 로그에 흑백으로 그대로 나와요. 따뜻한 캐시에서는 85초인 에셋 가져오기가 257초였어요. 릴리스마다 거의 9분을 낭비한 셈이에요. 키에 단어 하나가 빠져서요.
그 밖에 나온 것들. 저희 테스트 묶음은 배포되는 커밋 하나당 세 번 돌아요(풀 리퀘스트에서, 병합 뒤에, 릴리스에서 다시요). CodeQL은 필수 검사도 아닌데 풀 리퀘스트마다 세 가지 언어를 검사해요. .NET 패키지용 캐시는 아예 없어요. 하나의 아키텍처용으로만 빌드하는데 다른 프로세서 아키텍처 에뮬레이터를 설치해요. 그리고 7.4GB의 오래된 빌드 아티팩트가 기본 90일 보관 기간으로 남아 있어요. 어느 것도 극적이진 않지만, 합치면 꽤 큰 수명 한 덩어리예요.
교훈은 저희 서버가 가르쳐 준 것과 같아요. 그때는 차지한 메모리의 절반이 게임이 아니라 Docker와 모니터링에 쓰이고 있다는 걸 재서 알았어요. 이번에는 더 민망해요. 존재하지도 않는 청구서를 가정하고 확인하기도 전에 돈부터 냈으니까요. 추측하지 말고 재 보세요. 이 말은 진짜 몸에 밸 때까지는 계속 필요한 것 같아요. 정리 작업은 계획돼 있지만 아직 하지 않았어요. 돌리고 나면 얼마나 아꼈는지 알려 드릴게요. 🚀
댓글