GitHub Actions CI/CD란 무엇인가
GitHub Actions는 GitHub 저장소에 내장된 CI/CD 플랫폼입니다. 코드 푸시, PR 생성, 태그 발행 등의 이벤트를 트리거로 빌드, 테스트, 배포 파이프라인을 자동 실행합니다. 별도 CI 서버 없이 YAML 파일 하나로 전체 파이프라인을 정의할 수 있다는 점이 Jenkins, GitLab CI 대비 가장 큰 장점입니다.
이 글에서는 워크플로우 구조부터 실전 파이프라인 설계, 캐시·시크릿·매트릭스 전략, 그리고 비용을 줄이는 최적화 기법까지 실무에서 바로 적용할 수 있는 내용을 다룹니다.
워크플로우 기본 구조
GitHub Actions 워크플로우는 .github/workflows/ 디렉토리에 YAML 파일로 정의합니다. 핵심 구성 요소는 다음과 같습니다.
| 구성 요소 | 역할 | 예시 |
|---|---|---|
| Workflow | 자동화 프로세스 전체 | ci.yml |
| Event (on) | 워크플로우 실행 트리거 | push, pull_request, schedule |
| Job | 독립 실행 단위 (Runner 위에서) | build, test, deploy |
| Step | Job 내 순차 실행 단위 | checkout, install, test |
| Action | 재사용 가능한 단위 작업 | actions/checkout@v4 |
최소 워크플로우 예시
name: CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
- run: npm ci
- run: npm test
실전 파이프라인 설계: Node.js 프로젝트
프로덕션 수준의 파이프라인은 lint, test, build, deploy를 분리하고 Job 간 의존성을 설정합니다.
name: Production Pipeline
on:
push:
branches: [main]
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm run lint
test:
runs-on: ubuntu-latest
needs: lint
services:
postgres:
image: postgres:16
env:
POSTGRES_PASSWORD: test
ports:
- 5432:5432
options: --health-cmd pg_isready --health-interval 10s
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm test
env:
DATABASE_URL: postgresql://postgres:test@localhost:5432/test
build:
runs-on: ubuntu-latest
needs: test
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: 20
cache: npm
- run: npm ci
- run: npm run build
- uses: actions/upload-artifact@v4
with:
name: dist
path: dist/
deploy:
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main'
environment: production
steps:
- uses: actions/download-artifact@v4
with:
name: dist
- run: echo "Deploy to production"
Docker 이미지 빌드 + 레지스트리 푸시
컨테이너 기반 배포를 사용한다면 Docker 이미지 빌드와 레지스트리 푸시를 파이프라인에 포함해야 합니다. Docker Multi-Stage Build 최적화와 함께 적용하면 이미지 크기와 빌드 시간을 동시에 줄일 수 있습니다.
docker:
runs-on: ubuntu-latest
needs: test
permissions:
contents: read
packages: write
steps:
- uses: actions/checkout@v4
- uses: docker/setup-buildx-action@v3
- uses: docker/login-action@v3
with:
registry: ghcr.io
username: ${{ github.actor }}
password: ${{ secrets.GITHUB_TOKEN }}
- uses: docker/build-push-action@v5
with:
context: .
push: true
tags: ghcr.io/${{ github.repository }}:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
매트릭스 전략: 다중 환경 테스트
여러 Node.js 버전, OS, 데이터베이스 조합을 한 번에 테스트하려면 매트릭스 전략을 사용합니다.
test:
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, macos-latest]
node-version: [18, 20, 22]
fail-fast: false
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
- run: npm ci
- run: npm test
fail-fast: false로 설정하면 하나의 조합이 실패해도 나머지 조합의 테스트가 계속 실행됩니다. 어떤 환경에서 문제가 발생하는지 한 번에 파악할 수 있습니다.
캐시 전략: 빌드 시간 단축
의존성 설치는 파이프라인에서 가장 시간이 오래 걸리는 단계입니다. 캐시를 적극 활용해야 합니다.
| 방법 | 설정 | 효과 |
|---|---|---|
| setup-node cache | cache: npm |
npm ci 시간 50% 단축 |
| actions/cache | 커스텀 키 + 경로 지정 | 유연한 캐시 제어 |
| Docker layer cache | cache-from: type=gha |
Docker 빌드 70% 단축 |
| Turborepo remote cache | 모노레포 빌드 캐시 | 변경된 패키지만 빌드 |
커스텀 캐시 예시
- uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-npm-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-npm-
시크릿 관리 모범 사례
API 키, 데이터베이스 비밀번호 등 민감 정보는 반드시 GitHub Secrets에 저장하고, 워크플로우에서 ${{ secrets.SECRET_NAME }}으로 참조합니다.
- name: Deploy
run: |
aws s3 sync dist/ s3://${{ secrets.S3_BUCKET }}
env:
AWS_ACCESS_KEY_ID: ${{ secrets.AWS_ACCESS_KEY_ID }}
AWS_SECRET_ACCESS_KEY: ${{ secrets.AWS_SECRET_ACCESS_KEY }}
시크릿 관리 체크리스트
- Repository Secrets: 저장소 단위 시크릿
- Environment Secrets: production/staging 환경별 분리
- Organization Secrets: 여러 저장소에서 공유
GITHUB_TOKEN: 자동 생성, 최소 권한 원칙 적용 (permissions블록)
Environment와 수동 승인
프로덕션 배포 전 수동 승인을 강제하려면 Environment 보호 규칙을 사용합니다.
deploy:
runs-on: ubuntu-latest
needs: build
environment:
name: production
url: https://myapp.com
steps:
- run: echo "Deploying to production"
GitHub 저장소 Settings → Environments → production에서 Required reviewers를 설정하면, 이 Job은 지정된 팀원이 승인해야 실행됩니다.
Reusable Workflow: 중복 제거
여러 저장소에서 동일한 파이프라인을 사용한다면 Reusable Workflow로 공통 로직을 추출합니다.
# .github/workflows/reusable-test.yml
on:
workflow_call:
inputs:
node-version:
required: true
type: string
jobs:
test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ inputs.node-version }}
- run: npm ci
- run: npm test
# 호출하는 워크플로우
jobs:
call-test:
uses: my-org/.github/.github/workflows/reusable-test.yml@main
with:
node-version: '20'
비용 최적화 전략
GitHub Actions는 public 저장소는 무료이지만, private 저장소는 분 단위로 과금됩니다. 비용을 줄이는 핵심 전략은 다음과 같습니다.
| 전략 | 설명 | 절감 효과 |
|---|---|---|
| 경로 필터링 | paths:로 변경된 파일이 있을 때만 실행 |
불필요한 실행 제거 |
| 동시성 제한 | concurrency:로 중복 실행 취소 |
연속 푸시 시 이전 빌드 취소 |
| timeout-minutes | Job 타임아웃 설정 | 무한 실행 방지 |
| Self-hosted Runner | 자체 서버에서 실행 | 과금 시간 0분 |
on:
push:
branches: [main]
paths:
- 'src/**'
- 'package.json'
concurrency:
group: ${{ github.workflow }}-${{ github.ref }}
cancel-in-progress: true
흔한 실수와 해결법
실수 1: 캐시 키가 너무 넓거나 좁음
캐시 키에 lock 파일 해시를 포함하지 않으면 오래된 의존성이 사용됩니다. 반대로 너무 구체적이면 캐시 히트율이 낮아집니다. hashFiles('**/package-lock.json')과 restore-keys를 함께 사용하세요.
실수 2: GITHUB_TOKEN 권한 과다
기본적으로 GITHUB_TOKEN은 넓은 권한을 가집니다. permissions 블록으로 필요한 권한만 명시하세요.
permissions:
contents: read
packages: write
실수 3: 시크릿을 로그에 노출
echo ${{ secrets.API_KEY }}는 자동 마스킹되지만, Base64 인코딩 등 변환 후 출력하면 노출됩니다. 시크릿 값을 절대 가공해서 출력하지 마세요.
실수 4: needs 체인 없이 배포 Job 실행
테스트 Job이 실패해도 배포 Job이 실행될 수 있습니다. 반드시 needs:로 의존성을 명시하세요.
운영 체크리스트
- 모든 워크플로우에
timeout-minutes설정 (권장: 15~30분) concurrency그룹으로 중복 실행 방지- 프로덕션 배포에 Environment 보호 규칙 적용
permissions블록으로 최소 권한 원칙 적용- 의존성 캐시 활용 여부 확인 (npm, pip, gradle)
- Self-hosted Runner 도입 시 보안 격리 검토
- 워크플로우 실행 이력을 주 1회 점검하여 불필요한 실행 제거
마무리
GitHub Actions는 설정 진입 장벽이 낮지만, 프로덕션 수준의 파이프라인을 만들려면 캐시, 시크릿, 환경 분리, 비용 최적화까지 고려해야 합니다. 이 글의 패턴을 기반으로 프로젝트에 맞게 커스터마이즈하면, 안정적이고 빠른 CI/CD 파이프라인을 구축할 수 있습니다.
Spring Boot 프로젝트의 환경별 설정 분리가 필요하다면 Spring Boot Profiles 심화 가이드를 함께 읽어보세요.
지금 프로젝트의 CI/CD 파이프라인에 캐시와 concurrency 설정을 추가해 보세요. 빌드 시간 변화를 댓글로 공유해 주시면, 추가 최적화 팁을 드리겠습니다.