Skip to content

CI 비용 관리 가이드 ​

GitHub Actions 비용은 실행 시간 × 실행 횟수로 결정된다. 이 저장소들에서 두 값은 다음처럼 측정됐다(2026-09-14, 최근 30일).

측정 ​

한 실행의 실제 작업 시간은 짧다. 문제는 횟수다.

저장소실행(30일)내역대략 소모
PortalConsole444회push(main) 411 · PR 33약 660분
UiPlatform233회push(main) 220 · PR 13약 280분
portal-foundation88회태그 게시 59 · 수동 실행 29약 185분
ModelGateway14회push 7 · PR 7약 20분
합계779회약 1,150분/월

실행 1회의 실제 소모 시간(actions/runs 단계별 측정):

워크플로설치검증빌드작업 합계
Verify Directory Service9초47초10초약 1분 30초
Publish portal-foundation6초—109초(검사·테스트·빌드)약 2분

횟수를 만든 것은 워크플로 설정이 아니라 main 커밋 수다.

저장소최근 30일 main 커밋하루 최대
PortalConsole52370 (09-07)
portal-foundation40671 (09-07)
UiPlatform266103 (09-06)

커밋 1건이 곧 실행 1회이므로, 비용을 줄이는 일은 대부분 "푸시 횟수를 줄이는 일" 이다.

적용한 것 (워크플로) ​

  1. 중복 실행 취소 — concurrency + cancel-in-progress: true. 같은 브랜치에 연달아 푸시하면 이전 실행을 취소하고 최신 커밋만 검증한다. 순간적으로 몰아치는 푸시에서 효과가 크다.
  2. 문서 전용 변경 제외 — paths-ignore: ["**/*.md", "docs/**"]. 문서만 바뀐 변경은 전체 검증을 돌리지 않는다. 문서 게시(publish-docs)는 별도 워크플로가 담당하므로 영향이 없다.
  3. CI 생략 키워드 — 커밋 메시지에 [skip ci] · [ci skip] · [no ci] · [skip actions] · [actions skip] 중 하나가 들어 있으면 GitHub가 실행 자체를 만들지 않는다. 워크플로에 조건을 넣는 방식보다 낫다(실행이 생성되지 않으므로 대기 시간도 안 쓴다) — 그래서 직접 만든 잡 조건은 두지 않았다. 버전 범프·생성 파일처럼 검증이 의미 없는 커밋에 쓴다. 몰아치는 푸시에서는 중간 커밋에 붙이면 마지막 한 번만 검증된다.
    • 주의 1: 메시지 어디에든(본문 포함) 들어 있으면 적용된다. 이 규칙을 설명하려고 커밋 메시지에 키워드를 적으면 정작 그 커밋의 CI 가 건너뛰어진다 — 실제로 그렇게 실행이 만들어지지 않아 원인을 찾느라 시간을 썼다.
    • 주의 2: 그 푸시에서 트리거되는 모든 워크플로가 건너뛰어진다(문서 게시 포함). 게시가 필요한 커밋에는 쓰지 않는다. PR 제목·본문에 키워드가 있으면 스쿼시 머지 커밋 제목에 그대로 들어가 main 검증까지 건너뛴다 — 실제로 이 가드를 소개하는 PR 이 그렇게 됐다.
  4. 시간 상한 — timeout-minutes 로 실행 시간을 묶어 멈춘 작업이 과금으로 번지지 않게 한다(게시 워크플로는 게이트가 무거워 20분).

main push 검증 끄기 (2026-09-15 정리) ​

위 가드를 적용한 뒤에도 push 횟수가 비용을 지배했다. 그래서 main push로는 원격 검증을 돌리지 않고 로컬 게이트로 대체했다 — ProcessCenter에서 먼저 적용하고, 나머지 저장소에 같은 방식으로 옮겼다.

저장소정리 전 실측정리 내용
ProcessCenter최근 30일 1,397회 · push 1회에 ci.yml·verify.yml이 같은 단계를 중복 실행ci.yml 삭제, verify.yml은 PR(main)·수동 실행에서만
PortalConsole최근 6일 push 66회(1회 약 85초)verify.yml push 트리거 제거 + workflow_dispatch 추가
UiPlatform최근 8일 push 76회(1회 약 32초)같음. 문서 게시(Publish platform docs, docs/** 한정)는 유지
ModelGateway최근 2일 push 8회(1회 약 26초)같음
FileStore · ExploreGateway · RagService워크플로 없음(원격 검증 0회)PR(main)·수동 실행 전용 검증을 새로 추가
portal-foundation태그 게시 59 · 수동 실행 29(최근 30일) · push 검증 없음PR(main)·수동 실행 전용 검증을 새로 추가. 태그 게시는 그대로
  • 로컬 게이트: pnpm verify(check → build) · pnpm verify:full(+단위 테스트) — FileStore는 verify:admin(admin-web 타입 검사·빌드) · verify:all(둘 다)이 더 있고, portal-foundation은 verify(check) · verify:full(test + check)이며 각 스크립트가 내부에서 패키지 빌드를 돌린다. RagService는 python scripts/verify.py(--syntax-only 지원)다.
  • FileStore의 admin-web(vite, 자체 lockfile)도 같은 PR 잡의 마지막 단계에서 검사·빌드한다.
  • RagService는 Dockerfile 이미지와 같은 Python 3.11에서 돌리고, DB가 필요한 테스트는 각 테스트의 skipUnless 가드로 건너뛴다(tests/e2e_rag_isolation.py는 수집 대상이 아니다).
  • 규칙은 각 저장소 AGENTS.md의 "로컬 검증과 원격 검증 (CI 비용)" 절에 있다.
  • Coolify 배포는 push 웹훅이라 영향받지 않는다. 다만 CI 생략 키워드가 그 푸시의 모든 커밋에 있으면 Coolify도 배포를 건너뛴다 — 이 정리 커밋에는 그 키워드를 쓰지 않았다.

남은 선택지 (효과 큰 순) ​

  1. 푸시를 묶는다 — 근본 해법. 하루 70커밋을 5푸시로 묶으면 실행도 1/10이 된다. 자동화·에이전트가 파일 단위로 커밋하지 않고 작업 단위로 한 번에 푸시하게 한다.
  2. 자체 러너(self-hosted). 이미 운영 중인 서버에 러너를 붙이면(runs-on: self-hosted) 분 소모가 0이 된다. 저장소가 모두 비공개라 공개 저장소 포크 위험도 없다. 대신 러너 패치·격리 관리 주체가 우리가 된다.
  3. PR 경유. main 직접 푸시 대신 PR로 묶으면 실행이 PR 단위로 줄어든다(현재 PR 실행은 전체의 7%).
  4. 저장소 공개. 공개 저장소는 Actions 분이 무료다. portal-foundation 은 이미 공개 npm 패키지를 내보내므로 선택 여지가 있으나, 소스 전체를 공개한다는 판단이 필요하다.

하지 않은 것과 이유 ​

  • 게시 워크플로의 cancel-in-progress: false 유지 — 게시 도중 취소는 배포 상태를 어긋나게 만든다.
  • 게시 파이프라인에 검증 생략 스위치를 두지 않음 — 릴리스 게이트는 우회구를 만들지 않는다. 검증을 건너뛰고 싶은 커밋은 [skip ci] 로 아예 실행을 만들지 않는 편이 낫다.
  • 검증을 여러 잡으로 병렬화하지 않음 — 벽시계 시간은 줄지만 과금은 잡마다 붙어 오히려 늘어난다. 한 잡에서 순서대로 돌리는 지금 구조가 비용에는 유리하다.