GitHub Actions 튜토리얼: 2026년 CI/CD 자동화 실전 가이드
GitHub Actions 튜토리얼: 2026년 CI/CD 자동화 실전 가이드
GitHub Actions 단계별 튜토리얼. Node.js, Python 실전 예제로 테스트, 빌드, 배포 자동화를 배워보세요.
CI/CD란 무엇이고 왜 중요한가?
CI/CD는 지속적 통합(Continuous Integration)과 지속적 배포(Continuous Deployment)의 약자입니다. 핵심은 코드가 변경될 때마다 발생하는 반복적인 단계를 자동화하는 것입니다:
- 지속적 통합(CI): 코드가 push되거나 풀 리퀘스트가 열릴 때 자동으로 테스트와 검사를 실행합니다. 이렇게 하면 깨진 코드가 병합되기 전에 발견됩니다.
- 지속적 배포(CD): 코드가 모든 검사를 통과하면 스테이징 또는 프로덕션 환경에 자동으로 배포됩니다.
CI/CD 없이는 팀이 테스트 실행, 애플리케이션 빌드, 서버 배포를 수동으로 기억해야 합니다. 이는 오류가 발생하기 쉽고 느립니다. CI/CD를 통해 이 단계들이 자동으로 일관되게 실행됩니다.
GitHub Actions는 GitHub의 내장 CI/CD 플랫폼입니다. 저장소에 깊이 통합되어 있으며, 공개 저장소는 무료, 비공개 저장소도 넉넉한 무료 티어를 제공합니다. 간단한 린팅부터 복잡한 다중 환경 배포까지 처리할 만큼 강력합니다.
핵심 개념
워크플로 (Workflow)
워크플로는 .github/workflows/에 저장된 YAML 파일에 정의된 자동화 프로세스입니다. 저장소는 각각 다른 이벤트로 트리거되는 여러 워크플로를 가질 수 있습니다.
이벤트 (트리거)
이벤트는 워크플로가 실행될 시점을 정의합니다. 일반적인 트리거:
push— 브랜치에 코드가 push될 때pull_request— PR이 열리거나 업데이트될 때schedule— cron 일정에 따라workflow_dispatch— GitHub UI에서 수동으로 트리거
잡 (Job)
워크플로는 하나 이상의 잡으로 구성됩니다. 잡은 기본적으로 병렬로 실행됩니다. 각 잡은 새로운 가상 머신(러너)에서 실행됩니다.
스텝 (Step)
각 잡은 순차적으로 실행되는 스텝들로 구성됩니다. 스텝은 셸 명령을 실행하거나 미리 빌드된 액션을 사용할 수 있습니다.
액션 (Action)
액션은 GitHub Marketplace에서 게시된 재사용 가능한 작업 단위입니다. 예를 들어, actions/checkout은 저장소를 체크아웃하고, actions/setup-node는 Node.js를 설치합니다.
첫 번째 워크플로: Node.js 테스트
저장소에 .github/workflows/test.yml을 생성하세요:
name: Test
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
steps:
- name: 코드 체크아웃
uses: actions/checkout@v4
- name: Node.js 설정
uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: 의존성 설치
run: npm ci
- name: 린터 실행
run: npm run lint
- name: 테스트 실행
run: npm test
- name: TypeScript 타입 검사
run: npm run typecheck
이 워크플로는 main 또는 develop에 push할 때마다, 그리고 main에 대한 모든 풀 리퀘스트에서 실행됩니다. 코드를 체크아웃하고, Node.js 20을 설정하고(npm 캐싱으로 속도 향상), 의존성을 설치한 다음, lint, 테스트, 타입 검사를 순차적으로 실행합니다. 어느 단계에서든 실패하면 워크플로가 실패하고 GitHub가 PR 병합을 차단합니다.
Python 워크플로: 린트 및 테스트
name: Python CI
on:
push:
branches: [main]
pull_request:
branches: [main]
jobs:
lint-and-test:
runs-on: ubuntu-latest
steps:
- name: 코드 체크아웃
uses: actions/checkout@v4
- name: Python 설정
uses: actions/setup-python@v5
with:
python-version: '3.12'
cache: 'pip'
- name: 의존성 설치
run: |
pip install --upgrade pip
pip install -r requirements.txt
pip install ruff pytest pytest-cov
- name: Ruff로 린트
run: ruff check .
- name: 커버리지와 함께 테스트 실행
run: pytest --cov=src --cov-report=xml
- name: 커버리지 리포트 업로드
uses: codecov/codecov-action@v4
with:
file: ./coverage.xml
매트릭스 빌드: 여러 버전에서 테스트
매트릭스 전략을 사용해 여러 버전의 Node.js나 Python에 대해 테스트를 동시에 실행하세요:
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: ['18', '20', '22']
os: [ubuntu-latest, windows-latest]
steps:
- uses: actions/checkout@v4
- name: Node.js ${{ matrix.node-version }} 사용
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm test
이것은 각 조합에 대해 별도의 잡을 생성합니다: Node.js 버전 3개 × OS 2개 = 6개의 병렬 잡. 라이브러리가 Node 18, 20, 22를 지원해야 한다면, 이렇게 하면 호환성 문제가 자동으로 잡힙니다.
시크릿 관리
워크플로에 API 키나 비밀번호를 절대 하드코딩하지 마세요. GitHub Secrets를 사용하세요.
시크릿 설정:
- 저장소 → Settings → Secrets and variables → Actions로 이동
- "New repository secret" 클릭
- 이름(예:
API_KEY)과 값 추가
워크플로에서 시크릿 사용:
steps:
- name: 프로덕션 배포
env:
API_KEY: ${{ secrets.API_KEY }}
DATABASE_URL: ${{ secrets.DATABASE_URL }}
run: |
echo "API 키로 배포 중..."
npm run deploy
시크릿은 로그에서 마스킹됩니다 — 코드가 실수로 $API_KEY를 출력해도 GitHub가 ***로 대체합니다.
Cloudflare Pages에 배포하기
Next.js 앱을 빌드하고 Cloudflare Pages에 배포하는 완전한 워크플로:
name: Cloudflare Pages 배포
on:
push:
branches: [main]
jobs:
test:
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 test
deploy:
runs-on: ubuntu-latest
needs: test # 테스트 통과 시에만 배포
environment: production
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm'
- name: 설치 및 빌드
run: |
npm ci
npm run build
- name: Cloudflare Pages 배포
uses: cloudflare/pages-action@v1
with:
apiToken: ${{ secrets.CLOUDFLARE_API_TOKEN }}
accountId: ${{ secrets.CLOUDFLARE_ACCOUNT_ID }}
projectName: my-project
directory: .next
gitHubToken: ${{ secrets.GITHUB_TOKEN }}
needs: test 지시문은 테스트 잡이 성공한 경우에만 배포 잡이 실행되도록 합니다. environment: production은 프로덕션 배포에 필수 검토자 승인 단계를 추가합니다.
빠른 워크플로를 위한 캐싱
느린 워크플로는 개발자들이 실행하지 않도록 만듭니다. 캐싱을 적극 활용하세요:
- name: node_modules 캐시
uses: actions/cache@v4
with:
path: ~/.npm
key: ${{ runner.os }}-node-${{ hashFiles('**/package-lock.json') }}
restore-keys: |
${{ runner.os }}-node-
- name: pip 패키지 캐시
uses: actions/cache@v4
with:
path: ~/.cache/pip
key: ${{ runner.os }}-pip-${{ hashFiles('**/requirements.txt') }}
restore-keys: |
${{ runner.os }}-pip-
캐시 키는 락 파일의 해시를 포함합니다. package-lock.json이나 requirements.txt가 변경될 때 캐시가 무효화되고 의존성이 재설치됩니다. 그렇지 않으면 캐시가 몇 초 안에 복원되어 워크플로 속도를 크게 높입니다.
조건부 스텝과 수동 승인
조건으로 스텝 실행 시점을 제어하세요:
- name: 스테이징 배포
if: github.ref == 'refs/heads/develop'
run: npm run deploy:staging
- name: 프로덕션 배포
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
run: npm run deploy:production
- name: PR에 댓글 달기
if: github.event_name == 'pull_request'
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: '모든 검사를 통과했습니다! 검토 준비가 되었습니다.'
})
프로덕션 수준 워크플로를 위한 팁
- 액션 버전 고정 —
actions/checkout@main이 아닌actions/checkout@v4를 사용해 예기치 않은 호환성 문제를 방지하세요 - 워크플로를 빠르게 유지 — CI는 5분 이내를 목표로 하세요. 느린 파이프라인은 좌절한 개발자들에 의해 비활성화됩니다
- 경로 필터 사용 — 관련 파일이 변경될 때만 워크플로를 트리거하세요
- 타임아웃 제한 설정 — 잡에
timeout-minutes: 10을 추가해 오작동하는 빌드가 모든 분을 소모하지 않도록 하세요 - 워크플로 권한 검토 — 보안을 위해
permissions: read-all또는 최소한 필요한 권한을 사용하세요
GitHub Actions는 현대 개발자에게 가장 강력한 도구 중 하나입니다. 잘 설계된 워크플로는 버그가 프로덕션에 도달하기 전에 잡아내고, 모든 환경에서 일관된 빌드를 보장하며, 배포의 수동 작업을 제거합니다. 오늘 간단한 테스트 워크플로부터 시작해 프로젝트가 성숙해지면 배포 자동화를 점진적으로 추가해 나가세요.