Contents
see ListCI가 느려지면 배포 속도보다 피드백 속도가 먼저 떨어집니다
프로젝트가 커질수록 GitHub Actions 실행 시간은 개발 흐름을 좌우합니다. 모든 푸시에서 패키지 설치, 전체 빌드, 전체 테스트를 반복하면 작은 문서 수정에도 수 분을 기다리게 됩니다. 단순히 러너 사양을 높이기보다, 실행할 작업을 정확히 줄이고 재사용 가능한 결과를 캐시하는 편이 비용과 안정성 면에서 효과적입니다. 이 글은 Node.js 기반 웹 프로젝트를 기준으로 설명하지만, 핵심 원칙은 Java, Python, Docker 기반 서비스에도 같습니다.
먼저 측정 기준을 정합니다
개선 전에 워크플로 실행 기록에서 평균 실행 시간과 가장 오래 걸리는 job을 확인합니다. install, build, test, image build 단계를 나누어 두면 병목이 패키지 다운로드인지 테스트인지 쉽게 구분할 수 있습니다. 캐시는 항상 빨라지는 것이 아니라, 압축·복원 시간이 실제 설치 시간보다 길면 오히려 손해가 될 수 있습니다. 의존성 수, lock 파일 변경 빈도, 실행 횟수를 함께 보고 판단해야 합니다.
- 워크플로 이름과 job 이름을 기능 단위로 구분합니다.
- 실패율과 평균 실행 시간을 주 단위로 비교합니다.
- 캐시 적중 여부와 lock 파일 변경 시점을 로그에서 확인합니다.
- 보안 검사나 배포 승인처럼 생략하면 안 되는 단계를 성능 최적화 대상과 분리합니다.
의존성 캐시는 lock 파일을 키로 사용합니다
npm install 대신 npm ci를 사용하면 package-lock.json과 다른 상태를 조용히 섞지 않고 재현 가능한 설치를 보장합니다. setup-node의 내장 캐시는 npm 다운로드 캐시를 관리하므로 설정이 간단하고, lock 파일이 바뀌면 자동으로 새 캐시를 만듭니다. 모노레포라면 각 패키지의 lock 파일 경로를 모두 지정해야 잘못된 캐시 재사용을 막을 수 있습니다.
name: test
on:
pull_request:
push:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 22
cache: npm
cache-dependency-path: package-lock.json
- run: npm ci
- run: npm run lint
- run: npm test
- run: npm run buildnode_modules 디렉터리 자체를 무조건 캐시하는 방식은 주의가 필요합니다. 네이티브 모듈, 운영체제, Node.js 버전 차이 때문에 복원 후 오류가 날 수 있고, 캐시 용량도 커집니다. 먼저 패키지 매니저 다운로드 캐시와 npm ci 조합을 사용한 뒤, 설치 시간이 충분히 큰 경우에만 node_modules 캐시를 별도로 실험합니다.
변경되지 않은 영역의 작업은 시작하지 않습니다
프론트엔드와 서버, 인프라 코드가 한 저장소에 함께 있다면 모든 변경에 전체 파이프라인을 돌릴 이유가 없습니다. paths 필터는 워크플로 자체를 제한할 때 유용하고, job 내부 조건은 공통 검증 후 특정 빌드만 골라 실행할 때 적합합니다. 다만 필수 상태 검사로 지정한 워크플로를 paths로 완전히 건너뛰면 PR 머지가 막힐 수 있습니다. 보호 브랜치 규칙과 required check 구성을 먼저 확인해야 합니다.
on:
pull_request:
paths:
- 'apps/web/**'
- 'packages/ui/**'
- 'package.json'
- 'package-lock.json'
- '.github/workflows/web-ci.yml'
concurrency:
group: web-ci-${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: trueconcurrency 설정은 같은 브랜치에 새 커밋이 올라왔을 때 이전 실행을 취소합니다. PR에 커밋을 여러 번 올리는 팀이라면 오래된 결과를 끝까지 기다리지 않아도 됩니다. 단, 데이터 마이그레이션이나 실제 배포처럼 중간 취소가 위험한 job에는 별도 그룹을 쓰거나 cancel-in-progress를 적용하지 않아야 합니다.
빌드 산출물과 테스트 결과를 구분해 다룹니다
한 워크플로 안에서 build job과 test job이 같은 결과물을 사용할 때는 artifact를 이용해 명확하게 전달할 수 있습니다. 이 방식은 캐시와 목적이 다릅니다. 캐시는 다음 실행에서도 재사용하는 속도 최적화 수단이고, artifact는 같은 실행 안에서 job 간 결과를 전달하거나 사람이 내려받아 확인하는 기록입니다. 테스트 리포트, 커버리지, 정적 분석 결과는 artifact로 보존 기간을 짧게 설정하는 것이 관리하기 쉽습니다.
Docker 이미지 빌드도 무작정 매번 처음부터 만들지 말고 레이어 구조를 점검합니다. 의존성 정의 파일을 먼저 복사하고 설치한 뒤 소스 코드를 복사하면 소스만 바뀐 경우 의존성 설치 레이어를 재사용할 수 있습니다. 반대로 비밀값이 들어간 .env 파일을 이미지 컨텍스트에 넣으면 캐시 효율뿐 아니라 보안에도 문제가 생기므로 .dockerignore로 제외합니다.
캐시와 실행 조건을 운영 체크리스트로 관리합니다
- lock 파일 변경 시 캐시 키가 새로 생성되는지 확인합니다.
- Node.js와 운영체제가 다른 job끼리 동일한 node_modules 캐시를 공유하지 않습니다.
- 필수 검사 워크플로에 paths 필터를 추가하기 전 PR 보호 규칙을 검토합니다.
- 취소해도 안전한 검증 job에만 concurrency 취소를 적용합니다.
- 캐시 적중률, 복원 시간, 전체 실행 시간을 함께 기록해 효과를 판단합니다.
- 토큰, 인증서, .env 파일은 캐시와 artifact에 포함하지 않습니다.
핵심은 CI에서 일을 더 빨리 시키는 것이 아니라 불필요한 일을 시작하지 않는 것입니다. 재현 가능한 설치를 기본으로 두고, lock 파일 기반 캐시, 변경 경로 분리, 안전한 실행 취소를 순서대로 적용하면 속도와 신뢰성을 함께 높일 수 있습니다.
tool
| No | 작성일 | Title |
|---|---|---|
| 2143 | 2026. 02. 11. | Docker Compose v2와 컨테이너 오케스트레이션 실전 |
| 2142 | 2026. 02. 11. | Claude Code 완전 가이드: AI 코딩 에이전트 활용법 |
| 2033 | 2025. 11. 30. | Grafana + Prometheus 모니터링 구축 |
| 2032 | 2025. 11. 30. | Terraform으로 인프라 코드화 (IaC) |
| 2031 | 2025. 11. 30. | Vim 에디터 기초와 생산성 향상 |
| 2030 | 2025. 11. 30. | Postman으로 API 테스트 자동화 |
| 2029 | 2025. 11. 30. | Jenkins CI/CD 파이프라인 구축 |
| 2028 | 2025. 11. 30. | Maven vs Gradle - 빌드 도구 비교 |
| 2027 | 2025. 11. 30. | IntelliJ IDEA 생산성 향상 단축키 |
| 2026 | 2025. 11. 30. | Kubernetes 기초 - Pod, Service, Deployment |