DevOps CI/CD 파이프라인 구축 가이드
GitHub Actions를 활용한 CI/CD 파이프라인 구축 방법을 알아봅니다. 자동 테스트, 빌드, 배포까지 DevOps 워크플로우 설계 핵심을 다룹니다.
DevOps CI/CD 파이프라인 구축 가이드
소프트웨어 개발에서 CI/CD(지속적 통합/지속적 배포)는 코드 변경사항을 자동으로 테스트하고 배포하는 프로세스입니다. 수동 배포의 위험성과 비효율성을 제거하고, 개발팀이 코드 품질에 집중할 수 있도록 도와줍니다.
CI/CD의 기본 개념
CI (Continuous Integration) - 지속적 통합
CI는 개발자들이 코드 변경사항을 자주 메인 브랜치에 병합하는 관행입니다. 각 병합 시 자동으로 빌드와 테스트가 실행되어 문제를 조기에 발견할 수 있습니다.
CI의 핵심 원칙은 다음과 같습니다.
- 코드를 자주 커밋하고 병합합니다 (하루에 최소 1회 이상)
- 모든 변경사항에 대해 자동 테스트를 실행합니다
- 빌드가 깨지면 즉시 수정합니다
- 테스트 커버리지를 지속적으로 관리합니다
CD (Continuous Delivery/Deployment) - 지속적 전달/배포
CD는 CI를 통과한 코드를 자동으로 스테이징 또는 프로덕션 환경에 배포하는 과정입니다.
- Continuous Delivery: 프로덕션 배포 전 수동 승인 필요
- Continuous Deployment: 모든 변경사항이 자동으로 프로덕션 배포
개발자 커밋 → 자동 빌드 → 자동 테스트 → 코드 리뷰 → 스테이징 배포 → 프로덕션 배포
[CI 영역] [CD 영역]
GitHub Actions로 CI/CD 구축하기
GitHub Actions는 GitHub에 내장된 CI/CD 플랫폼으로, YAML 파일로 워크플로우를 정의합니다. 무료 티어에서도 월 2,000분의 실행 시간을 제공하므로 개인 프로젝트에 적합합니다.
기본 워크플로우 구조
# .github/workflows/ci.yml
name: CI Pipeline
on:
push:
branches: [main, develop]
pull_request:
branches: [main]
jobs:
test:
runs-on: ubuntu-latest
strategy:
matrix:
node-version: [18, 20]
steps:
- uses: actions/checkout@v4
- name: Setup Node.js
uses: actions/setup-node@v4
with:
node-version: ${{ matrix.node-version }}
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npm test
- run: npm run build
주요 구성 요소 설명
트리거(on): 워크플로우가 실행되는 조건을 정의합니다. push, pull_request, schedule 등 다양한 이벤트를 지원합니다.
잡(jobs): 독립적으로 실행되는 작업 단위입니다. 각 잡은 별도의 가상 머신에서 실행되며 병렬 처리가 가능합니다.
스텝(steps): 잡 내에서 순차적으로 실행되는 단계입니다. 커맨드 실행이나 액션(Action) 사용이 가능합니다.
실전 파이프라인 설계
Node.js 프로젝트 전체 파이프라인
name: Full Pipeline
on:
push:
branches: [main]
pull_request:
branches: [main]
env:
NODE_VERSION: '20'
jobs:
# 1단계: 코드 품질 검사
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- uses: actions/setup-node@v4
with:
node-version: ${{ env.NODE_VERSION }}
cache: 'npm'
- run: npm ci
- run: npm run lint
- run: npx tsc --noEmit
# 2단계: 단위 테스트
unit-test:
runs-on: ubuntu-latest
needs: lint
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: Upload coverage
uses: actions/upload-artifact@v4
with:
name: coverage
path: coverage/
# 3단계: 빌드
build:
runs-on: ubuntu-latest
needs: unit-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: Upload build
uses: actions/upload-artifact@v4
with:
name: build
path: .next/
# 4단계: 배포 (main 브랜치만)
deploy:
runs-on: ubuntu-latest
needs: build
if: github.ref == 'refs/heads/main'
steps:
- uses: actions/checkout@v4
- name: Deploy to Vercel
uses: amondnet/vercel-action@v25
with:
vercel-token: ${{ secrets.VERCEL_TOKEN }}
vercel-org-id: ${{ secrets.VERCEL_ORG_ID }}
vercel-project-id: ${{ secrets.VERCEL_PROJECT_ID }}
vercel-args: '--prod'의존성 캐싱 전략
빌드 시간을 단축하려면 의존성 캐싱이 중요합니다. actions/cache나 setup-node의 cache 옵션을 활용하면 npm 패키지를 재다운로드하지 않아도 됩니다.
- uses: actions/setup-node@v4
with:
node-version: '20'
cache: 'npm' # package-lock.json 기반 자동 캐싱
환경 분리와 시크릿 관리
환경별 설정
프로덕션, 스테이징, 개발 환경을 분리하는 것은 안전한 배포의 기본입니다.
deploy-staging:
environment: staging
runs-on: ubuntu-latest
steps:
- name: Deploy
env:
DATABASE_URL: ${{ secrets.STAGING_DATABASE_URL }}
API_KEY: ${{ secrets.STAGING_API_KEY }}
run: npm run deploy:staging
deploy-production:
environment: production
runs-on: ubuntu-latest
needs: deploy-staging
steps:
- name: Deploy
env:
DATABASE_URL: ${{ secrets.PROD_DATABASE_URL }}
API_KEY: ${{ secrets.PROD_API_KEY }}
run: npm run deploy:prod
시크릿 관리 모범 사례
민감한 정보는 GitHub Secrets에 저장하고, 워크플로우에서 참조합니다. 시크릿은 로그에 마스킹되어 출력되므로 안전합니다.
- API 키, 데이터베이스 URL 등은 반드시 시크릿으로 관리합니다
- 환경별로 시크릿을 분리합니다 (PROD_, STAGING_ 접두사 활용)
- 정기적으로 시크릿을 로테이션합니다
- 최소 권한 원칙을 적용합니다
테스트 자동화 전략
테스트 피라미드
효과적인 테스트 전략은 테스트 피라미드를 따릅니다.
/\
/ \ E2E 테스트 (적음, 느림, 비쌈)
/ \ Cypress, Playwright
/------\
/ \ 통합 테스트 (중간)
/ \ Supertest, Testing Library
/------------\
/ \ 단위 테스트 (많음, 빠름, 저렴)
/________________\ Jest, Vitest
PR 자동 검사
Pull Request가 생성되면 자동으로 코드 품질을 검사하는 워크플로우를 설정할 수 있습니다.
name: PR Check
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
check:
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
- run: npm test
- run: npm run build
- name: Comment PR
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: '모든 검사를 통과했습니다!'
})
Docker를 활용한 배포
컨테이너 기반 배포는 환경 일관성을 보장합니다. Dockerfile을 작성하고 GitHub Actions에서 이미지를 빌드하여 레지스트리에 푸시할 수 있습니다.
멀티 스테이지 Dockerfile
# 빌드 스테이지
FROM node:20-alpine AS builder
WORKDIR /app
COPY package*.json ./
RUN npm ci
COPY . .
RUN npm run build
# 프로덕션 스테이지
FROM node:20-alpine AS runner
WORKDIR /app
ENV NODE_ENV=production
COPY --from=builder /app/.next ./.next
COPY --from=builder /app/public ./public
COPY --from=builder /app/package*.json ./
RUN npm ci --omit=dev
EXPOSE 3000
CMD ["npm", "start"]
모니터링과 알림
배포 후 모니터링은 서비스 안정성의 핵심입니다.
Slack 알림 설정
- name: Slack Notification
uses: 8398a7/action-slack@v3
with:
status: ${{ job.status }}
text: |
배포 결과: ${{ job.status }}
커밋: ${{ github.sha }}
브랜치: ${{ github.ref_name }}
env:
SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}
if: always()
마무리
CI/CD 파이프라인은 현대 소프트웨어 개발의 필수 인프라입니다. GitHub Actions를 활용하면 별도의 CI 서버 없이도 강력한 자동화 파이프라인을 구축할 수 있습니다. 처음에는 간단한 파이프라인으로 시작하고, 프로젝트가 성장하면서 테스트, 보안 스캔, 성능 테스트 등을 점진적으로 추가하는 것을 권장합니다. 자동화에 투자하는 시간은 반드시 개발 생산성으로 돌아옵니다.
관련 게시글
개발자를 위한 리눅스 필수 명령어 총정리
리눅스 터미널에서 반드시 알아야 할 파일 관리, 프로세스 관리, 네트워크, 권한 관리, 쉘 스크립트 기초까지 개발자 필수 명령어를 총정리합니다.
Git 워크플로우 베스트 프랙티스: 효율적인 협업을 위한 완벽 가이드
Git Flow, GitHub Flow, 브랜치 전략, 커밋 메시지 컨벤션, 코드 리뷰 문화까지 팀 협업을 위한 Git 워크플로우 베스트 프랙티스를 정리합니다.
Docker 컨테이너 입문 가이드: 개념부터 실전까지
Docker의 핵심 개념, Dockerfile 작성법, 이미지 빌드, 컨테이너 관리, Docker Compose 사용법까지 실전 예제와 함께 배우는 Docker 입문 가이드입니다.