본문 바로가기

개발 자동화 & 생산성 도구

GitHub Actions 캐시·동시성 최적화 — 빌드 시간과 중복 실행 줄이기

반응형

GitHub Actions가 느려지면 Runner 성능부터 의심하기 쉽지만 실제로는 매 실행마다 의존성을 다시 받고, 같은 브랜치의 오래된 빌드를 끝까지 수행하고, 캐시와 Artifact를 혼동해서 시간이 늘어나는 경우가 많습니다.

최적화는 단계별 실행시간을 측정한 뒤 의존성 캐시 → 중복 실행 취소 → Job 구조 → 테스트 병렬화 순서로 적용하는 편이 좋습니다.

핵심 요약

  • Cache는 재생성 가능한 의존성·중간 파일, Artifact는 보존·전달할 결과물에 사용합니다.
  • Cache Key에는 OS, 도구 버전, Lockfile Hash를 포함합니다.
  • restore-keys는 부분 일치를 허용하므로 오래된 의존성의 안전성을 검토합니다.
  • concurrency로 같은 브랜치의 이전 실행을 취소하면 Runner 낭비를 줄일 수 있습니다.
  • Cache에는 Token, Credential, 서명되지 않은 민감 파일을 넣지 않습니다.

1. 먼저 실행시간을 분해한다

단계확인대표 개선

Checkout·Setup 도구 설치 시간 Setup Action의 내장 캐시
Dependency 네트워크 다운로드 Lockfile 기반 Cache
Compile 증분 빌드 가능성 빌드 캐시·Job 재구성
Test 느린 Suite·Flaky Test Shard·Matrix·격리
Upload 과도한 파일 크기 필요한 Artifact만 압축

2. Lockfile 기반 캐시

- uses: actions/setup-node@v4
  with:
    node-version: 22
    cache: npm
    cache-dependency-path: package-lock.json

- run: npm ci

공식 setup-* Action은 npm, Gradle, Maven, pip 등 대표 패키지 관리자의 캐시를 간단히 구성합니다. 직접 actions/cache를 사용할 때는 다음처럼 키를 설계합니다.

- uses: actions/cache@v4
  with:
    path: ~/.gradle/caches
    key: ${{ runner.os }}-gradle-${{ hashFiles('**/*.gradle*', '**/gradle-wrapper.properties') }}
    restore-keys: |
      ${{ runner.os }}-gradle-

기존 Cache 내용은 수정되지 않으며 새 Key에서 새 Cache가 만들어집니다. 너무 넓은 경로를 저장하면 업로드·복원 시간이 절약 시간보다 길어질 수 있습니다.

3. 중복 실행 취소

concurrency:
  group: ${{ github.workflow }}-${{ github.ref }}
  cancel-in-progress: true

PR에 연속 Push가 들어오면 이전 Commit의 CI 결과는 대개 필요하지 않습니다. Workflow와 Ref를 함께 Group으로 사용하면 다른 Workflow까지 실수로 취소하는 일을 줄일 수 있습니다. Release Branch나 배포 Workflow는 진행 중 실행을 취소하면 안 될 수 있으므로 정책을 분리합니다.

4. Cache와 Artifact 구분

구분CacheArtifact

목적 다음 실행 속도 향상 결과 보존·Job 간 전달
없어도 빌드 가능 후속 Job에 필요할 수 있음
예시 npm·Gradle 다운로드 JAR, Coverage, Test Report
보안 신뢰하지 않은 입력으로 취급 보존 기간과 접근권한 확인

5. Matrix와 병렬화

Matrix는 OS·런타임 버전 호환성 검사에 유용하지만 조합이 곱셈으로 늘어납니다. 모든 PR에 전체 Matrix를 실행하기보다 빠른 필수 검사와 Nightly 전체 검사를 분리합니다.

  • 단위 테스트는 Shard별 시간이 비슷하도록 과거 실행시간으로 배분합니다.
  • 빌드 결과를 Artifact로 한 번 만들고 후속 검사가 재사용하게 합니다.
  • needs를 검토해 독립 Job이 불필요하게 직렬화되지 않게 합니다.
  • 변경 경로에 따라 문서·프런트·백엔드 Workflow를 분리합니다.

6. 캐시 보안 주의

GitHub 문서는 Cache에 Secret이나 Credential을 저장하지 말라고 안내합니다. PR이나 Fork에서 복원 가능한 Cache는 신뢰할 수 없는 입력으로 봐야 하며, Cache Poisoning 가능성도 고려합니다.

  • 실행 파일·스크립트 Cache는 생성 주체와 Trigger를 제한합니다.
  • 낮은 신뢰도의 PR에서는 Restore-only 정책을 검토합니다.
  • Dependency 설치 후 Lockfile 검증과 무결성 검사를 유지합니다.
  • Secret이 들어갈 수 있는 홈 디렉터리 전체를 Cache하지 않습니다.

7. 개선 체크리스트

  1. 최근 20회 실행의 단계별 중앙값과 P95를 기록합니다.
  2. Cache Hit·Miss와 복원 시간을 측정합니다.
  3. PR용 Concurrency로 오래된 실행을 취소합니다.
  4. 필수 검사와 Nightly Matrix를 분리합니다.
  5. Artifact 경로·크기·보존 기간을 줄입니다.
  6. 변경 후 전체 시간과 실패·Flaky 비율을 함께 비교합니다.

공식 자료

정리: 빠른 CI는 큰 Runner보다 반복 작업을 제거하는 설계에서 시작합니다. Lockfile 기반 Cache와 Branch별 Concurrency를 먼저 적용하고, 측정값을 기준으로 Job 병렬화와 Matrix 범위를 조정하세요.

반응형