GitHub Actions란?
GitHub Actions는 GitHub에 내장된 CI/CD(지속적 통합/배포) 플랫폼입니다. 코드를 push하면 자동으로 테스트, 빌드, 배포가 실행됩니다. 공장의 자동화 라인에 비유하면, 원재료(코드)가 들어오면 품질 검사(테스트) → 조립(빌드) → 출하(배포)가 자동으로 이루어지는 것입니다.
핵심 개념
| 개념 | 설명 | 비유 |
|---|
| Workflow | 자동화 프로세스 전체 | 공정 라인 |
| Event | 워크플로우를 시작하는 이벤트 | 시작 버튼 |
| Job | 같은 러너에서 실행되는 작업 단위 | 작업 스테이션 |
| Step | Job 안의 개별 명령 | 작업 단계 |
| Runner | 워크플로우를 실행하는 서버 | 작업자 |
| Action | 재사용 가능한 작업 단위 | 조립 부품 |
기본 워크플로우 작성
# .github/workflows/ci.yml
name: CI Pipeline
# 트리거 이벤트 정의
on:
push:
branches: [main, develop] # main, develop 브랜치 push 시
pull_request:
branches: [main] # main 대상 PR 생성/수정 시
# 환경변수 (워크플로우 전체에서 사용)
env:
NODE_VERSION: "22"
jobs:
# Job 1: 코드 품질 검사
lint:
name: Lint & Type Check
runs-on: ubuntu-latest # Ubuntu 최신 러너에서 실행
steps:
# 소스 코드 체크아웃
- uses: actions/checkout@v4
# Node.js 설정 + 캐시
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm" # node_modules 캐시 (빌드 속도 향상)
# 의존성 설치
- run: npm ci # ci는 lock 파일 기준 정확한 버전 설치
# 린트 실행
- run: npm run lint
name: ESLint 검사
# 타입 체크
- run: npm run typecheck
name: TypeScript 타입 검사
# Job 2: 테스트
test:
name: Unit Tests
runs-on: ubuntu-latest
needs: lint # lint job이 성공한 후에만 실행
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
- run: npm ci
- run: npm test -- --coverage
name: 테스트 실행 (커버리지 포함)
# 테스트 커버리지 결과 업로드
- uses: actions/upload-artifact@v4
if: always() # 테스트 실패해도 결과 업로드
with:
name: coverage-report
path: coverage/
# Job 3: 빌드
build:
name: Build
runs-on: ubuntu-latest
needs: test # 테스트 성공 후 실행
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: "npm"
- run: npm ci
- run: npm run build
name: 프로덕션 빌드
# 빌드 결과물 저장
- uses: actions/upload-artifact@v4
with:
name: build-output
path: dist/
retention-days: 7 # 7일간 보관
매트릭스 빌드: 여러 환경에서 동시 테스트
# 여러 Node.js 버전과 OS에서 동시 테스트
jobs:
test-matrix:
name: Test (${{ matrix.os }} / Node ${{ matrix.node-version }})
runs-on: ${{ matrix.os }}
strategy:
matrix:
os: [ubuntu-latest, windows-latest, macos-latest]
node-version: [18, 20, 22]
exclude:
# macOS + Node 18 조합 제외 (불필요)
- os: macos-latest
node-version: 18
include:
# 특정 조합에 추가 설정
- os: ubuntu-latest
node-version: 22
coverage: true # 이 조합에서만 커버리지 수집
fail-fast: false # 하나 실패해도 나머지 계속 실행
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: "npm"
- run: npm ci
- run: npm test
# 커버리지 설정이 있는 조합에서만 실행
- run: npm test -- --coverage
if: matrix.coverage == true
시크릿과 환경변수
# 시크릿은 GitHub Settings → Secrets and Variables → Actions에서 설정
jobs:
deploy:
runs-on: ubuntu-latest
environment: production # 환경별 시크릿 분리 가능
steps:
- uses: actions/checkout@v4
# 시크릿 사용 — 로그에 자동 마스킹됨
- name: 배포
env:
API_KEY: ${{ secrets.API_KEY }} # 시크릿
DEPLOY_TOKEN: ${{ secrets.DEPLOY_TOKEN }}
APP_ENV: production # 일반 변수
run: |
echo "배포 환경: $APP_ENV"
# $API_KEY, $DEPLOY_TOKEN은 로그에 *** 로 마스킹됨
./deploy.sh
자동 배포 워크플로우
# .github/workflows/deploy.yml
name: Deploy to Production
on:
push:
branches: [main] # main 브랜치 push 시만 배포
# 동시 배포 방지
concurrency:
group: production-deploy
cancel-in-progress: false # 진행 중인 배포는 취소하지 않음
jobs:
deploy:
name: Deploy
runs-on: ubuntu-latest
environment:
name: production
url: https://example.com # 배포 URL (GitHub에 표시)
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
- run: npm ci
- run: npm run build
# Docker 이미지 빌드 & 푸시
- name: Docker 빌드 및 푸시
uses: docker/build-push-action@v5
with:
context: .
push: true
tags: |
ghcr.io/${{ github.repository }}:latest
ghcr.io/${{ github.repository }}:${{ github.sha }}
# SSH로 서버 배포
- name: 서버 배포
uses: appleboy/ssh-action@v1
with:
host: ${{ secrets.SSH_HOST }}
username: ${{ secrets.SSH_USER }}
key: ${{ secrets.SSH_PRIVATE_KEY }}
script: |
cd /app
docker compose pull
docker compose up -d --remove-orphans
echo "배포 완료: $(date)"
# Slack 알림
- name: 배포 성공 알림
if: success()
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "배포 성공: ${{ github.repository }} (${{ github.sha }})"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
# 배포 실패 알림
- name: 배포 실패 알림
if: failure()
uses: slackapi/slack-github-action@v1
with:
payload: |
{
"text": "배포 실패: ${{ github.repository }} — 확인 필요!"
}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
PR 자동화
# .github/workflows/pr-check.yml
name: PR Checks
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
pr-check:
runs-on: ubuntu-latest
# PR에 권한 부여 (댓글 작성 등)
permissions:
contents: read
pull-requests: write
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
- run: npm ci
- run: npm run build
# 빌드 크기 비교 댓글
- name: 번들 크기 보고
uses: andresz1/size-limit-action@v1
with:
github_token: ${{ secrets.GITHUB_TOKEN }}
# PR에 번들 크기 변화를 댓글로 표시
# 자동 라벨 추가
- uses: actions/labeler@v5
with:
repo-token: ${{ secrets.GITHUB_TOKEN }}
캐싱으로 빌드 속도 향상
# 캐시 전략 — 의존성 설치 시간 단축
steps:
# npm 캐시 (setup-node가 자동 처리)
- uses: actions/setup-node@v4
with:
node-version: "22"
cache: "npm"
# 커스텀 캐시 — 빌드 캐시 등
- name: Turbo 캐시
uses: actions/cache@v4
with:
path: .turbo # 캐시 경로
key: turbo-${{ runner.os }}-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
turbo-${{ runner.os }}-
| 캐시 대상 | 효과 | 설정 방법 |
|---|
| npm/yarn/pnpm | 의존성 설치 80% 단축 | setup-node의 cache 옵션 |
| Docker 레이어 | 이미지 빌드 50% 단축 | docker/build-push-action의 cache-from |
| 빌드 결과물 | 증분 빌드 | actions/cache로 .next/, dist/ 캐시 |
실전 팁
npm ci를 npm install 대신 사용하세요: CI 환경에서는 npm ci가 lock 파일 기준으로 정확한 버전을 설치하고, 더 빠릅니다.
concurrency 설정으로 동시 실행을 제어하세요: 같은 브랜치에서 여러 번 push하면 이전 실행을 자동 취소하여 리소스를 절약합니다.
if: always(), if: failure()를 활용하세요: 테스트 실패 시에도 리포트를 업로드하거나 알림을 보내는 후속 작업이 가능합니다.
- Reusable Workflow로 중복을 줄이세요: 여러 리포지토리에서 공통 워크플로우를
uses: org/workflows/.github/workflows/ci.yml@main으로 재사용할 수 있습니다.
- GitHub Actions Marketplace를 활용하세요: 대부분의 작업에 이미 만들어진 Action이 있습니다. 직접 스크립트를 작성하기 전에 검색해보세요.
- 비용을 모니터링하세요: Public 리포지토리는 무료지만, Private 리포지토리는 월 2,000분 무료 후 과금됩니다. 불필요한 워크플로우를 정리하세요.