찾고 계신 답
- GitHub Actions macOS runner가 느리거나
Queued에서 멈춤 - iOS CI 빌드 실패 또는 retry 반복
- Xcode build는 CI에서 타임아웃인데 로컬에서는 통과
- Cloud Mac vs GitHub Actions, 무엇을 선택할지
- CI pipeline 결과가 불안정하고 재현되지 않음
GitHub Actions나 macOS self-hosted Runner를 운영 중이라면, 2026년에 듣는 불만은 꽤 구체적입니다: 대기열이 길어지고, Xcode 컴파일 시간이 들쭉날쭉하며, 같은 PR에서 retry가 반복되고, CI가 초록과 빨강을 오갑니다. 이 글은 네 층으로 풉니다—먼저 그런 증상에 이름을 붙이고, Agent가 CI를 어떻게 「루프화」하는지, 마지막으로 Cloud Mac이 어디에 맞는지. 제목의 「CI는 죽었다」는 말미 FAQ에서 다룹니다. 본문은 지금 팀이 겪는 장애 현상부터 시작합니다.
1 · 1층: 2026년 GitHub Actions가 「느려지고, 흔들리고, flaky해지는」 이유
최근 반년 VPSSpark가 접한 iOS / Flutter / macOS 팀 피드백은 놀랄 만큼 겹칩니다. 문제는 「CI 개념이 낡았다」가 아니라, 아래 네 가지가 동시에 늘었다는 점입니다.
1.1 macOS runner 대기열(Queue)
호스팅 macos-latest에서는 Queued 시간이 실제 빌드 시간보다 길어지는 경우가 흔합니다. job 타임라인을 열면 대기 40분·실행 12분인데, 팀은 xcodebuild 인자를 계속 손댑니다. 진단 공식은 여전히 wait time >> run time입니다. 절차는 macOS runner 대기열 Runbook을 참고하세요. 2026년에 queue가 길어진 배경에는 macOS 동시 실행 cap 대비 repo job 수가 못 따라온 점, 그리고 Archive 같은 무거운 job이 슬롯을 점유해 PR 빠른 피드백까지 끌어들이는 점이 있습니다.
1.2 Xcode 빌드 시간 편차
같은 commit을 재실행해도 CI의 Xcode 컴파일은 18분일 때와 31분일 때가 있습니다. 로컬 Mac은 15분 전후로 안정적인 패턴입니다. 겹치는 요인은 runner cold start, DerivedData 미스, CocoaPods 재 resolve, 러너 이미지의 Xcode 패치와 로컬 불일치. 단독으로는 「캐시 설정 문제」로 보이지만, retry마다 cold 환경이면 편차가 「CI를 믿을 수 없다」는 체감으로 증폭됩니다.
1.3 retry 횟수 폭주
workflow의 retry-on-failure 외에 암묵적 retry가 늘고 있습니다. Agent나 bot이 로그를 읽고 patch를 내고 push한 뒤 Actions를 다시 띄웁니다. 한 PR이 「사람이 2번 push」에서 「머신이 8번 push」로 바뀌고, minutes 요금과 queue 압력이 함께 오릅니다. flaky 테스트 탓으로 보이지만 실상은 같은 PR에 대해 CI가 서로 다른 코드로 여러 바퀴 돌고 있는 것입니다.
1.4 Flaky CI: 초록·빨강이 섞이고 재현 안 됨
고전적 flaky는 테스트 간헐 타임아웃, 시뮬레이터 기동 실패, 서명 키체인 일시 잠금입니다. 2026년에는 한 겹 더:Agent가 라운드마다 내는 diff가 다릅니다. 「테스트가 flaky한가, Agent가 다른 걸 망쳤나」를 가르기 어렵습니다. 릴리스 담당이 가장 아픈 한마디: 「어젯밤 CI는 초록이었는데, 오늘 아침 같은 tag가 빨강이다.」
| 화면에 보이는 것 | 흔한 오해 | 먼저 볼 것 |
|---|---|---|
| Job이 오래 Queued | GitHub 장애 | macOS 병렬도, Archive가 PR에 들어갔는지 |
| Xcode 시간 편차 | 프로젝트 비대화 | 캐시, 이미지 Xcode 버전, cold start |
| 같은 PR 여러 run | 개발자 난 push | Agent / bot retry, concurrency 미설정 |
| 초록·빨강 교차 | 테스트 품질 문제 | 라운드마다 commit 일치 여부, 환경 드리프트 |
2 · 2층: 원인은 「CI가 나빠진 것」이 아니라 CI가 루프화된 것
위 네 가지는 queue만, 캐시만, 테스트만 고쳐도 한 바퀴 분량입니다. 나란히 보면 공통 실마리가 보입니다: CI가 일회성 검증이 아니라 「실패 → 수정 → 재실행」 루프가 됐다는 점. Agent 이전에는 그 루프가 엔지니어 머릿속(고치고 push)에 있었습니다. 지금은 인프라에 박혔습니다—모델이 로그를 읽고 patch를 내고 workflow를 자동 트리거합니다.
현장에서 이미 흔한 체인은 다음과 같습니다.
- PR 오픈 → CI 빨강(테스트 / 컴파일)
- Agent가 Actions 로그 읽기 → fix commit 생성
- push → 새 workflow → 다시 빨강 가능 → 재 fix
- 초록이 되거나, human이 멈추거나, token 소진까지
이름은 GitHub Actions / CI 그대로인데, 행동은 이미 Agent retry loop입니다. 여기서 다루는 건 「한 번의 build 실패」가 아니라 여러 라운드가 겹친 뒤의 확률적 결과—그래서 1층 증상이 납니다. queue는 다중 job으로 막히고, Xcode 시간은 라운드마다 cold start로 흔들리고, flaky는 코드·환경 조합이 매번 바뀌기 때문입니다.
조금 추상적이지만 실무에 쓰이는 표현이 있습니다. 고전 CI는 결정적(deterministic)을 가정합니다—같은 commit·같은 환경이면 결과가 재현돼야 합니다. Agent 루프 이후 경로는 확률적(probabilistic)—몇 번째에 초록이 되는지, 중간에 몇 버전 코드를 거쳤는지, Archive를 실수로 밟았는지에 무작위성이 실립니다. 당장 플랫폼을 갈아엎으라는 뜻이 아니라, 「캐시만 더하면 된다」가 전부를 못 고치는 이유를 설명합니다.
| 차원 | 전통 CI(단발 검증) | 루프화 CI(Agent retry loop) |
|---|---|---|
| 트리거 횟수 | 사람 push 주도, 적음 | 실패 시 자동 재실행, ×N |
| 코드 버전 | PR HEAD 고정 | 루프 중 commit 연속 변화 |
| 실패 의미 | 현재 코드에 문제 | 「아직 시도가 부족」일 수 있음 |
| 비용 | minutes × 단가 | minutes + token + 환경 cold start |
GitHub는 workflow, runner, 캐시를 계속 개선합니다—대상은 단발 결정적 job입니다. repo가 이미 Agent loop를 기본으로 쓰면 그 개선도 유효하지만, 「job 수 × retry 횟수」의 곱셈 효과는 막기 어렵습니다. 제목이 「GitHub는 아직 모른다」고 하는 지점이 여기입니다. 제품 서사는 CI/CD인데, 쓰임은 자동 수리 루프 장치로 드리프트하고 있습니다.
3 · 3층: 구조 변화—CI 파이프라인에서 retry loop + 실행 기반으로
1층 증상과 2층 원인을 맞추면 구조 변화는 한 문장입니다: CI가 직선 파이프라인에서 피드백 고리가 있는 실행 시스템으로 바뀌었다.
그림 1 · 루프화 CI: Agent 판단 + Runner 실행 + 피드백 고리
옛 모델: Code → Build → Test → Result. 한 단계 실패면 라인 전체 정지. 새 모델: Code → Agent → Modify → Execute → Retry → … → Result. 실패는 끝이 아니라 고리의 일부. GitHub의 초록 체크는 여전히 안심 요소지만 의미는 바뀌었습니다—4번째 시도에서야 초록이고, 중간 commit은 이미 다를 수 있습니다.
여기서 실무 용어: execution substrate(실행 기반). Agent는 코드를 아무리 바꿔도 컴파일·서명·업로드는 안정적이고 재현 가능한 macOS 실행면에 떨어져야 합니다. Serverless job은 너무 짧아 상태를 못 넘깁니다. 로컬 Mac은 sleep하고 Xcode가 올라갑니다. 호스팅 runner는 queue되고 스펙이 드리프트합니다. Cloud Mac이 메우는 게 이 층—원격 데스크톱이 아니라 retry loop 안에서 가능한 한 deterministic하게 유지해야 할 유일한 층입니다.
실행 권한도 이동합니다. 예전엔 사람이 workflow를 쓰고 머신이 따랐습니다. 지금은 사람이 경계를 씁니다(PR에 무엇을 넣을지, Archive를 어디서 허용할지, retry 상한), Agent가 경계 안에서 경로를 시도하고 사람이 최종 결과를 받아들입니다. macOS / iOS 팀이 가장 민감한 건 서명과 Archive를 retry 고리에서 무한 반복하면 안 된다는 점—초록이 나와도 배포 가능을 뜻하지 않습니다.
4 · 4층: Cloud Mac으로 실행면 고정(지금 할 수 있는 것)
GitHub narrative가 바뀌길 기다릴 필요 없습니다. Actions를 버릴 필요도 없습니다. 루프화 CI에 대해 VPSSpark 쪽에서 반복 검증된 네 가지—Cloud Mac이 호스팅 runner와 갈라지는 지점입니다.
4.1 풀 분리: retry 피해 반경 제한
PR에서는 L0/L1만(analyze, 단위 테스트, 시뮬레이터 빌드), Archive는 PR에 넣지 않음. 릴리스·IPA·공증은 main / tag 전용 격리 풀만. Agent 루프가 거칠어도 35분 Archive가 fast 풀을 점유해 전원 Queued 되지 않습니다. 하드 룰과 사례는 CI Hard Rules, Flutter 이중 풀 토폴로지는 Cloud Mac 2대 fast / archive 분리를 참고하세요.
4.2 Warm environment: retry마다 cold start 금지
PUB_CACHE, DerivedData, Pods 다운로드 캐시를 영속화. Runner는 기동 시 자동 등록, 7×24 온라인. Agent 2번째 retry에서 15분 pod install을 다시 할 이유가 없어야 합니다—그렇지 않으면 Xcode 시간 편차가 「프로젝트가 무거워졌다」로 오독됩니다. Cloud Mac에서 사는 건 환경 유지 비용이지 단발 CPU 분만이 아닙니다.
4.3 macOS execution substrate: 툴체인 버전 고정
이미지나 fvm으로 Flutter / Xcode 메이저를 pin. Archive 머신과 fast 풀은 물리 분리, DerivedData 공유 금지. retry 각 라운드는 같은 Distribution 인증서, 같은 CLT에서 돌아야—iOS CI 감사 가능의 전제입니다. self-hosted 경계는 GitHub 공식 문서 참고.
4.4 Retry isolation: 루프에 상한
workflow에서 concurrency로 동일 PR의 옛 run 취소. Agent 트리거 전용 timeout과 최대 push 횟수 설정. 서명 머신은 release 풀만 접근. 문법은 workflow 레퍼런스 참고. 목표는 Agent를 없애는 게 아니라 루프를 통제 가능한 경계 안에서 돌리는 것입니다.
macos-fast 빠른 풀을 세우고 Archive는 호스팅 runner에 둡니다. 3일간 P95 queue와 Xcode wall time 분산을 관찰. 빠른 풀이 안정되면 2대째 Archive 머신 추가—「2대 스타트」 시리즈와 같은 동기에서 queue 대응을 Agent retry 대응으로 확장합니다.
5 · FAQ
「CI는 죽었다」는 과장 아닌가요?
제목은 과장이지만 가리키는 현상은 실제입니다. pipeline은 초록이고 PR도 머지되는데—「같은 코드·같은 체크인데 돌릴 때마다 경로와 결과가 안정적으로 재현되지 않는다」. 여기서 말하는 「CI는 죽었다」는 GitHub Actions를 못 쓴다는 뜻이 아니라, 고전 CI 전제—빌드와 검증이 결정적 흐름이다—가 Agent가 코드를 반복 수정하고 workflow를 반복 트리거하는 장면에서는 더 이상 서지 않는다는 뜻입니다. 더 정확히는: CI는 남아 있지만 의미가 바뀌었다. 「지속적 통합」에서 「지속적 시도」로 미끄러지고 있습니다.
GitHub가 이 흐름에 맞춰 제품을 바꿀까요?
바꿉니다. 다만 속도가 쓰임의 드리프트를 못 따라잡을 수 있습니다. 가까운 미래에도 workflow 최적화, runner 확장, 캐시 개선은 계속—모두 전통형 CI용입니다. Agent 관련(sandbox, 호출 감사, token 과금)은 점진적으로 붙을 가능성이 크고, 하룻밤에 narrative를 갈아엎지는 않을 겁니다. 팀 입장에선 공식 정의를 기다리지 않고 움직일 수 있습니다: 기존 Actions 위에서 PR / Archive 풀 분리, retry 제한, 서명 머신 잠금—Agent 시대 최저 비용 가드레일입니다.
Cloud Mac과 호스팅 macOS runner 차이는?
한 줄로: 호스팅 runner는 「1 job 실행 시간」을 빌리고, Cloud Mac은 「장기 안정 환경」을 산다. 가끔 릴리스하고 queue를 감수하며 job이 짧으면—호스팅 macos-latest로 충분한 경우가 많습니다. Agent loop나 고빈도 iOS CI는 다릅니다. Xcode / 인증서 / 캐시 상주, fast와 Archive 물리 분리, sleep이나 조용한 업그레이드로 환경이 끊기지 않음. Cloud Mac 가치는 후자—서명·Archive·공증에서는 retry 각 라운드가 같은 키·같은 툴체인에서 돌아야 하며 cold start 운에 맡기면 안 됩니다.
OpenClaw / 로컬 Agent와 관계는?
충돌하지 않습니다. 층이 다릅니다. OpenClaw, Cursor Agent, 로컬 Copilot 등은 「무엇을 바꿀지, 태스크를 어떻게 편성할지」—Gateway·스케줄링 쪽. 이 글의 Runner / Cloud Mac은 「어디서, 어떤 환경으로 돌릴지」—컴파일, 테스트, 서명, 업로드. Agent는 로컬에서 patch해도 CI에서 루프해도 macOS 빌드는 결국 재현 가능한 실행면에 착지해야 합니다. 편성층과 실행층을 나눠 설계하지 않으면 「Agent는 똑똑한데 매번 CI가 낯선 환경에서 제로부터」라는 어긋남이 납니다.
4층 다음 단계: Cloud Mac 1대로 실행면 고정
앞 세 층에 공감한다면—queue, Xcode 편차, retry 폭주, flaky—4층을 한꺼번에 다 할 필요 없습니다. 가장 흔한 경로: 먼저 Cloud Mac 1대로 warm 빠른 풀을 세워 Agent retry에서 가장 아픈 cold start와 툴체인 드리프트를 누르고, Archive와 서명은 필요 시 격리. Apple Silicon 저전력은 상시 온라인에 맞고, iOS / macOS 팀에 GitHub minutes 팩을 더하는 것보다 루프화 CI 요금 구조를 직접 겨냅니다.
이 글을 PoC 기준으로 삼는다면 VPSSpark Cloud Mac mini를 macOS execution substrate 시작점으로—요금제 확인 후 환경을 먼저 고정하고 Agent N번째 라운드를 돌리세요.