2 min read
CI 캐시 최적화 플레이북
의존성 캐시, 빌드 아티팩트 캐시를 분리해 파이프라인 시간을 단축하는 방법

도입
CI 시간이 길어지면 개발 생산성뿐 아니라 배포 안정성도 떨어진다. 캐시를 무작정 켜면 빨라질 것 같지만 키 설계가 잘못되면 오히려 불안정한 빌드가 발생한다. 이 글은 신뢰성을 유지하면서 CI 캐시 효율을 높이는 실전 플레이북을 정리한다.

문제 정의
캐시 최적화는 속도와 재현성의 균형 문제다.
- 캐시 키 범위가 넓어 사소한 변경에도 전체 캐시가 무효화된다.
- 의존성 캐시와 빌드 산출물 캐시를 혼합해 오염 가능성이 높다.
- 캐시 적중률을 관측하지 않아 최적화 효과를 측정하지 못한다.
핵심은 캐시를 계층으로 나누는 것이다. 의존성, 빌드 중간 결과, 테스트 결과를 별도로 관리해야 한다.
핵심 개념
| 관점 | 설계 기준 | 검증 포인트 |
|---|---|---|
| 키 설계 | 락파일 + 런타임 버전 포함 | cache miss 원인 분류 |
| 계층화 | deps/build/test 캐시 분리 | 오염 재현률 |
| 관측 | hit ratio 대시보드 | 평균 파이프라인 시간 |
| 정리 | TTL 기반 캐시 청소 | 스토리지 비용 |
속도 개선은 측정 가능한 지표가 있어야 유지된다. 캐시 적중률과 실패율을 함께 추적하면 과최적화를 방지할 수 있다.
코드 예시 1: GitHub Actions 캐시 키
- name: Cache pnpm store
uses: actions/cache@v4
with:
path: ~/.pnpm-store
key: pnpm-\${{ runner.os }}-\${{ hashFiles('pnpm-lock.yaml') }}
restore-keys: |
pnpm-\${{ runner.os }}-
- name: Cache Next build
uses: actions/cache@v4
with:
path: .next/cache
key: next-\${{ runner.os }}-\${{ hashFiles('**/*.ts', '**/*.tsx', 'next.config.ts') }}
코드 예시 2: 캐시 지표 수집
export function logCacheMetrics(input: { step: string; hit: boolean; durationMs: number }) {
console.log(
JSON.stringify({
metric: "ci_cache",
step: input.step,
hit: input.hit,
duration_ms: input.durationMs,
timestamp: new Date().toISOString(),
}),
);
}
아키텍처 흐름
Mermaid diagram rendering...
트레이드오프
- 캐시 범위를 좁히면 안정성은 높지만 최대 속도 개선폭은 줄어든다.
- restore-keys를 넓게 두면 적중률은 오르지만 오래된 캐시를 불러올 위험이 있다.
- 캐시 계층이 늘면 설정 복잡도는 증가하지만 디버깅 난이도는 오히려 낮아진다.
정리
CI 캐시 최적화는 빠른 빌드보다 재현 가능한 빌드를 목표로 해야 한다. 계층화된 캐시 전략과 지표 기반 튜닝을 결합하면 안정성과 속도를 동시에 확보할 수 있다.
이미지 출처
- Cover: source link
- License: CC BY-SA 3.0 / Author: Bernard Gagnon
- Note: Wikimedia Commons 무료 라이선스 이미지를 다운로드 후 1600px 기준 JPG로 최적화했습니다.