← 개발 일기로 돌아가기

2026년 원격 Mac 셀프호스티드 GitHub Actions Runner로 OpenClaw CI 연동: 읽기 전용 Webhook, macOS 라벨 풀, M4 병렬 처리 (Lobster 워크플로 + 트러블슈팅 FAQ)

코드와 터미널이 있는 노트북—OpenClaw CI용 원격 Mac 셀프호스티드 Runner를 상징
본문 주선: 원격 Mac → 셀프호스티드 Runner → OpenClaw macos-node / macos-swift. Gateway 설치·6개 리전 횡평은 범위 밖입니다.

OpenClaw 포크·플러그인을 유지보수하는 팀이라면, 2026년에는 보통 두 갈래를 동시에 봅니다. 업스트림 OpenClaw CImacos-node, macos-swift, checks-node-compat-node22에 실제 macOS가 필요하고, GitHub 호스트형 macOS 분·대기열은 계속 부담이 됩니다. 이 글은 전용 원격 Mac 위 GitHub Actions 셀프호스티드 macOS Runner로 위 lane만 돌리고, macOS 라벨 풀읽기 전용 Webhook + Lobster 다단계 워크플로로 실패를 triage하는 방법에만 집중합니다. Gateway 18789·온보딩·6개 리전 TCO는 다루지 않습니다(리전·일·월 비용은 macOS Runner 노드·TCO 글 참고). 요금: Mac mini 요금 · 미 동부/서부 결제: 미 동부, 미 서부 · Runner 운영: 도움말 센터.

1) 호스트형 macOS Runner vs 원격 Mac 셀프호스티드: OpenClaw CI 결정표

OpenClaw CI 문서에 따르면 macos-node는 macOS 관련 소스 변경 시 TypeScript 테스트를, macos-swift는 Swift lint/build/test를 담당합니다. 수동 workflow_dispatch는 스마트 범위를 건너뛰고 Node 22 호환을 포함한 전체 그래프를 돌립니다. 업스트림은 Blacksmith macos-latest급 Runner를 쓰기 좋지만, 포크 메인테이너는 그 큐·캐시에 의존하기 어렵고 자체 macOS 태그가 필요합니다.

호스트형 macOS는 PR 빈도가 낮을 때 유리합니다. 원격 M4에 셀프호스티드를 두면 고정 임대 대신 node_modules·DerivedData를 유지해 매일 main·플러그인 계약 shard·로컬에 가까운 pnpm check에 맞추기 쉽습니다. 장기 Gateway/에이전트 배포는 원격 Mac OpenClaw 실전 가이드가 담당하고, 본문은 CI Runner만 다룹니다(한 줄: Gateway는 채팅·도구, Runner는 컴파일·테스트).

경로 OpenClaw CI 적합도 주요 비용
GitHub 호스트형 macos-latest 업스트림 workflow는 제로옵스; 포크는 큐·캐시 공유 어려움. 분 과금; 콜드 macos-swift; 피크 대기열.
원격 Mac 셀프호스티드 Runner label로 macos-node / macos-swift 매핑; Node 22·pnpm store 고정. Runner 업그레이드·디스크·병렬 mutex.
Linux 호스트만, macOS lane 생략 문서·순수 Node PR에는 OK; Swift/macOS 테스트 대체 불가. 머지 전 수동·스케줄 full macOS dispatch 필요.
결정 힌트: 주 1회 이상 workflow_dispatch full CI를 돌리거나, 포크에서 macos-node 대기가 15분을 넘기면 openclaw-macos-node 태그 1대를 먼저 계획하세요. 플러그인 팀은 dispatch가 일상이면 M4 1석이 약 90일 안에 회수되는 경우가 많습니다(워크플로 크기에 따르며 SLA 약속 아님).

셀프호스티드가 맞는 또 다른 신호: preflight가 플러그인 터치마다 macOS lane을 예약하는데, 호스트 Runner는 job 간 캐시를 버려 TypeScript·Swift가 다운로드에 시간을 씁니다. 원격 Mac에서 따뜻한 pnpm store·DerivedData는 CPU가 비슷해도 wall-clock을 줄이는 경우가 많습니다—리포에서 측정 후 좌석을 잡으세요.

2) 환경 체크리스트: Xcode CLT, Node 22, CI 사용자 격리

OpenClaw는 대부분 Node shard를 Linux에서 돌리지만 macos-node·checks-node-compat-node22는 호스트에 Node 22가 필요합니다(CI 문서·로컬 pnpm check와 동일). Runner 호스트에서:

  • Xcode Command Line Tools + 팀이 고정한 Xcode minor; Swift lane은 CLT만으로는 부족하고 전체 Xcode 필요.
  • CI 사용자 셸에서 fnm 또는 miseNode 22.x; workflow에는 actions/setup-node 병행.
  • 업스트림 packageManager와 맞는 pnpm; 캐시는 일상 개발 계정이 아닌 CI 홈 아래.
  • actions-runner 전용 Unix 사용자(예: runner)—브라우저·채팅 시크릿과 분리.
  • 리소스 상한: memory_pressure 관찰; 24GB에서도 두 번째 job 병렬은 측정 후.
사전 점검 체크리스트(인쇄용):
  1. xcode-select -p, xcodebuild -version이 문서와 일치.
  2. node -v가 v22.x; pnpm -v가 lockfile 정책과 일치.
  3. SSH 로그아웃 후에도 launchd로 Runner 유지.
  4. 여유 디스크 > 25%(DerivedData + pnpm store 급증).
  5. PAT 분리: Webhook/추론 시크릿 vs 서명 인증서용 GitHub Secrets.

플랫폼 API: Apple Developer Documentation · Node 정책: nodejs.org.

3) Runner 등록 및 macOS 라벨 풀(HowTo)

GitHub 셀프호스티드 Runner 가이드를 따릅니다. OpenClaw 포크에서는 모호한 self-hosted 하나가 아니라 lane별 label을 명시하세요.

등록 및 label(리포 Runner)
# ~/actions-runner
./config.sh --url https://github.com/YOUR_ORG/YOUR_FORK \
  --token YOUR_REGISTRATION_TOKEN \
  --labels self-hosted,macOS,ARM64,openclaw-macos-node,openclaw-m4-16 \
  --name nuv-openclaw-macos-node-01

sudo ./svc.sh install
sudo ./svc.sh start

라벨 풀(lane 분리):

  • openclaw-macos-node — 업스트림 macos-node(TypeScript/Vitest macOS 경로).
  • openclaw-macos-swiftmacos-swift; CPU/RAM 부담 큼—16GB에서 node와 기본 병렬 금지.
  • openclaw-node22 — dispatch 호환·로컬 pnpm check 스모크용(선택).
  • openclaw-m4-16 / openclaw-m4-24 — matrix·용량 계획용 하드웨어 tier.
포크 workflow: macos-node를 풀에 연결
jobs:
  macos-node:
    runs-on: [self-hosted, macOS, openclaw-macos-node]
    steps:
      - uses: actions/checkout@v4
      - uses: actions/setup-node@v4
        with:
          node-version: '22'
          cache: 'pnpm'
      - run: pnpm install --frozen-lockfile
      - run: pnpm test --filter macos-relevant

코드사인·공증이 있으면 concurrency: { group: codesign-macos, cancel-in-progress: false }로 키체인 동시 잠금을 막으세요. SSH·Runner 추가 메모: 도움말 센터.

리포 vs 조직 Runner: 단일 포크는 위 label의 리포 Runner 1대로 충분합니다. 여러 플러그인이 한 결제 그룹을 쓰면 조직 Runner + 접근 제한을 검토하고, 실험 리포가 Swift lane을 빼앗지 않게 runner group을 쓰세요(Enterprise에서 제공 시).

업그레이드: runbook에 Runner 앱 버전을 고정하세요. GitHub Runner 릴리스마다 job을 drain(./svc.sh stop) → 바이너리 업그레이드 → 재시작 → Idle 확인 후 자동 할당을 다시 켭니다. 오래된 Runner는 「로컬 OK, CI만 실패」의 흔한 원인입니다.

4) OpenClaw CI / dispatch 연동 및 읽기 전용 Webhook

업스트림 preflight는 push/PR 그대로 두고 macOS runs-on만 풀로 바꿉니다. 전체 검증은 CI 문서의 수동 dispatch를 사용합니다:

전체 CI 그래프 트리거(macOS 포함)
gh workflow run ci.yml --ref main
gh workflow run ci.yml --ref main -f target_ref=your-branch -f include_android=true

읽기 전용 Webhook 추론(단계적): 실패 triage용으로 먼저 읽기 전용 이벤트—workflow_run.completed, check_run.completed, workflow_job.completed—만 구독하고 메타데이터(리포, 브랜치, conclusion, URL)만 저장합니다. Phase 0에서 Contents 쓰기·자동 머지는 요청하지 마세요. 서명 검증 후 에이전트가 로그 URL·Actions API 읽기 scope로 가져가고, 코멘트·label 확장은 승인 정책과 함께 Phase 2로.

단계 Webhook / 권한 목적
Phase 0 읽기 전용 + workflow_run / check_run 실패 알림, 큐 관찰, Lobster triage 입력.
Phase 1 Actions 로그 읽기 PAT 실패 job 로그 조각; macos-node shard 연결.
Phase 2 제한적 쓰기(이슈 코멘트, label) 자동 ci-failure, 페이저 멘션—리뷰 게이트 필수.
vs Gateway: Gateway는 에이전트 도구·로컬 hook; CI Webhook은 GitHub 이벤트만 소비합니다. PR 제목·코멘트 본문을 프로덕션에서 셸 명령으로 취급하지 마세요—메타데이터만 triage(ClawSweeper식 최소 전달).

수신기에는 안정 필드만 로그: workflow_run.id, head_branch, conclusion, run HTML URL. HMAC 실패와 인증 실패를 분리해 on-call이 secret 오설정과 재전송을 구분하게 하세요. Lobster를 붙일 때는 이 필드를 JSON stdin으로 넘기고, 악의적 PR 제목이 도구 선택에 영향을 주는 전체 webhook body는 채팅 프롬프트에 붙이지 마세요.

5) M4 16GB / 24GB 병렬 치트시트(단일 머신 라벨 풀)

OpenClaw macOS lane 기준 실무 가이드(SLA 아님, 리포 의존). 추가 좌석·리전 비용은 Runner 노드·TCO 글—여기서는 6개 리전 표를 넣지 않습니다.

구성 권장 병렬 label 리스크
M4 16GB macos-node 1개 또는 가벼운 Swift 1개—동시에 둘 다 아님. openclaw-macos-node, openclaw-m4-16 Vitest OOM; DerivedData vs pnpm store 디스크 경쟁.
M4 24GB 비피크에 macos-node 1 + Swift check 1; 또는 시차 2× node shard. openclaw-m4-24; Swift는 별도 runner 이름 유지. 병렬 Swift 컴파일도 memory 경고—concurrency group 사용.
머신 2대 node 1대, swift 1대—label로 라우팅, 한 Runner에 섞지 않음. 전용 openclaw-macos-swift 캐시 비공유—호스트마다 deps 예열.

Nuvcloud는 다중 노드 M4 베어 메탈·RAM/SSD 업그레이드로 고정 CI 좌석에 맞춥니다. 가용·가격: 요금·결제 페이지; 본문은 큐 SLA를 약속하지 않습니다.

SSD는 DerivedData, pnpm store, _work/ 세 곡선을 봅니다. 256GB 단일 lane 포크는 주간 DerivedData 정리로 가능; Swift 무거운 포크는 512GB·요금 마법사 1TB 옵션을 검토하세요. 16GB에서 Vitest 중 node 자식이 죽으면 jetsam을 의심하고, shard를 쪼개기 전에 24GB 호스트로 Swift를 옮기세요.

6) Lobster 워크플로: 재현 가능한 CI 실패 로그 triage

Lobster는 다단계 도구 체인을 승인 지점·resumeToken이 있는 결정적 한 번의 호출로 묶습니다. 「CI 빨강 → 로그 수집 → 분류 → 사람 OK → 요약 게시」에 LLM이 도구를 마음대로 호출하는 것보다 적합합니다. 에이전트 설정에 alsoAllow: ["lobster"] 후 파이프라인을 실행하세요.

Lobster: 실패 job 요약(예시 pipeline JSON)
{
  "action": "run",
  "pipeline": "exec --json --shell 'gh run list --workflow ci.yml --limit 5 --json databaseId,conclusion,headBranch' | exec --stdin json --shell 'gh run view $ID --log-failed' | exec --stdin json --shell 'node scripts/ci-triage-summarize.mjs' | approve --preview-from-stdin --limit 3 --prompt '온콜 채널에 요약 게시?'",
  "timeoutMs": 120000,
  "maxStdoutBytes": 512000
}

.lobster 워크플로 파일로 collectclassifyapprovalnotify를 나누세요(Lobster 「workflow files」 참고). needs_approval이면:

승인 후 resume
{
  "action": "resume",
  "token": "<resumeToken>",
  "approve": true
}

재현 triage 습관: 실패마다 run_id, 트리거 label(예: openclaw-macos-node), stderr 첫 블록 해시를 위키에 남기세요. 이슈에 올리기 전 Lobster JSON에서 시크릿을 제거하세요. timeout이면 timeoutMs를 올리거나 「로그 가져오기」와 「LLM 요약」을 분리하세요. 실패 run 7일 읽기 전용 아카이브로 flaky와 회귀를 구분합니다.

팀은 종종 빠른 Lobster(실패 유형만: Node vs Swift vs 인프라)와 느린 Lobster(사람 승인 후 전체 로그) 두 개를 둡니다. OpenClaw CI의 「저렴한 preflight, 필요할 때만 무거운 lane」과 같고, 녹색 run에 토큰을 쓰지 않습니다.

CI에서 이미 gh를 쓰면 같은 PAT scope를 Runner 호스트 Lobster에 쓸 수 있습니다. Phase 0은 actions:read·metadata:read만; 퇴사 시 PAT 교체, Runner 등록 토큰을 API 자격증명으로 재사용하지 마세요.

7) FAQ

Q1: Runner가 Offline?
launchd, 토큰 만료, 디스크 full을 확인하세요. GitHub → Settings → Actions → Runners에서 제거 후 config.sh 재실행. 셀프호스티드 Runner 문서 참고.

Q2: macos-node가 Node를 불평?
호스트·setup-node·checks-node-compat-node22를 Node 22로 맞추고, 오래된 global npm 캐시를 비우세요.

Q3: Swift / SDK를 못 찾음?
전체 Xcode 설치, sudo xcodebuild -license accept; CLT만 있는 호스트에서 macos-swift 금지.

Q4: 읽기 전용 Webhook이 403?
secret, TLS, 리버스 프록시 경로, App 이벤트 권한 확인; 게이트웨이가 PR 본문을 명령으로 실행하지 않게 하세요.

Q5: openclaw doctor vs CI 빨강?
doctor는 설치/게이트웨이 건강; CI는 Actions 로그. Lobster + gh run view로 triage, onboard로 workflow 디버깅 대체 금지.

Q6: macOS 없이 Linux만?
순수 Node/문서 PR에는 가능하지만 macOS/Swift 변경 머지 전 최소 1회 workflow_dispatch full graph 또는 upstream preflight 의도와 어긋납니다.

Q7: 업스트림과 포크가 Runner 공유?
비권장—runner group·Secrets를 나눠 신뢰 못 하는 포크 스크립트가 서명 재료에 닿지 않게 하세요.

Q8: Lobster invalid JSON?
각 단계 stdout은 JSON; maxStdoutBytes 상향; --json 없이 사람 로그를 다음 단계에 넣지 마세요.

Q9: 호스트와 셀프호스티드 혼합?
가능—예: PR은 호스트, mainmacos-swift는 셀프호스티드(if: 또는 workflow 분리).

더 읽기: 기술 블로그 인덱스. 리전·병렬 좌석·일·월 비용은 macOS Runner 노드·TCO 글을 이어서 보세요.

클라우드 Mac mini에서 OpenClaw CI 풀이 더 안정적

macos-node / macos-swift를 전용 원격 M4에 두면 예측 가능한 연산라벨 풀 탄력을 얻습니다. Nuvcloud 베어 메탈 Mac mini는 네이티브 Unix, 24/7 Runner에 낮은 유휴 전력, 24GB RAM·SSD 업그레이드, Swift 전용 2번째 머신 병렬에 맞습니다. 읽기 전용 Webhook + Lobster triage와 맞추면 호스트 큐를 덜 지켜도 됩니다.

OpenClaw 포크 CI 풀을 계획 중이라면 openclaw-macos-node 태그 M4 1대부터—요금·리전 보기, 위 체크리스트대로 Runner·Webhook을 등록하세요.

한정 요금 보기