소프트웨어 개발 과정에서 품질을 보장하고 릴리즈 속도를 높이기 위한 필수 방법론으로 CI/CD(지속적 통합 및 지속적 배포)가 널리 쓰이고 있습니다. 이는 코드의 잦은 병합에 따르는 문제를 해결하고, 코드를 운용 환경으로 자동으로 배포하는 생명주기를 의미합니다. 이번 포스트에서는 CI/CD의 개념부터 실제 GitHub Actions 파이프라인 구성까지 상세히 알아보겠습니다.
1. CI (Continuous Integration): 지속적 통합
과거에는 다수의 개발자들의 코드를 하나로 병합하는 날인 "통합의 날(Integration Hell)"이 있었습니다. 주간 또는 월간으로 작업한 코드를 한꺼번에 병합하다 보니 수많은 충돌이 발생하고, 이를 해결하는 데 며칠씩 걸리기도 했습니다.
CI는 코드 변경사항들이 자동으로 레포지토리에 병합, 빌드, 그리고 테스트되도록 하는 관행입니다. 개발자가 변경 사항을 작은 단위로 자주(하루에도 여러 번) push하고, 이때마다 자동화된 파이프라인이 실행됩니다. 버그를 조기에 발견할 수 있으며 코드의 품질을 일정 범위 내에서 지속적으로 검증하게 됩니다.
전형적인 CI 파이프라인의 단계는 다음과 같습니다.
- 코드 체크아웃: 저장소에서 최신 코드를 가져옵니다.
- 의존성 설치:
npm install,pip install등으로 필요한 패키지를 설치합니다. - 정적 분석(Lint): ESLint, Pylint 등으로 코드 스타일과 잠재적 오류를 검사합니다.
- 단위/통합 테스트: 자동화된 테스트를 실행하고 커버리지를 측정합니다.
- 빌드: 프로덕션용 아티팩트(Docker 이미지, 번들 파일 등)를 생성합니다.
- 보안 스캔: 알려진 취약점이 있는 의존성을 검사합니다.
2. CD (Continuous Deployment/Delivery): 지속적 배포
CD는 통합 이후 테스트를 통과한 코드가 실제 프로덕션, 혹은 스테이징 환경까지 배포되는 과정을 자동화하는 것입니다.
- 지속적 제공 (Continuous Delivery): 배포 준비상태까지만 만들어두고, 실제 배포는 개발자/운영자의 수동 승인을 거칩니다. 프로덕션 배포에 신중을 기해야 하는 금융, 의료 도메인에서 자주 채택됩니다.
- 지속적 배포 (Continuous Deployment): 인간의 개입을 완전히 배제하여 테스트가 완벽히 통과하면 바로 실제 서비스 라이브 환경에 반영됩니다. 빠른 이터레이션이 중요한 SaaS 제품에서 많이 사용됩니다.
3. GitHub Actions로 CI/CD 파이프라인 구성하기
GitHub Actions는 현재 가장 널리 사용되는 CI/CD 플랫폼 중 하나입니다. 레포지토리의 .github/workflows/ 디렉토리에 YAML 파일을 작성하여 파이프라인을 정의합니다.
# .github/workflows/ci-cd.yml
name: CI/CD Pipeline
on:
push:
branches: [ main, develop ]
pull_request:
branches: [ main ]
jobs:
# CI 단계: 테스트 및 빌드
test-and-build:
runs-on: ubuntu-latest
steps:
- name: 코드 체크아웃
uses: actions/checkout@v4
- name: Node.js 설정
uses: actions/setup-node@v4
with:
node-version: '18'
cache: 'npm'
- name: 의존성 설치
run: npm ci
- name: 린트 검사
run: npm run lint
- name: 단위 테스트 실행
run: npm test -- --coverage
- name: 프로덕션 빌드
run: npm run build
- name: Docker 이미지 빌드 및 푸시
if: github.ref == 'refs/heads/main'
run: |
docker build -t myapp:${{ github.sha }} .
docker push myapp:${{ github.sha }}
# CD 단계: 프로덕션 배포 (main 브랜치에서만 실행)
deploy:
needs: test-and-build
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main'
environment: production # 수동 승인 게이트
steps:
- name: 서버 배포
run: |
echo "Deploying version ${{ github.sha }} to production..."
# kubectl, ansible, 또는 배포 스크립트 실행
4. 테스트 전략: 테스트 피라미드
효과적인 CI를 위해서는 체계적인 테스트 전략이 필요합니다. 테스트 피라미드(Test Pyramid)는 각 레이어의 테스트 비율을 설명합니다.
- 단위 테스트(Unit Test) — 피라미드 하단 (70%): 개별 함수나 컴포넌트를 격리하여 테스트합니다. 실행이 빠르고 유지보수가 쉽습니다. Jest, Pytest, JUnit이 대표적입니다.
- 통합 테스트(Integration Test) — 피라미드 중단 (20%): 여러 컴포넌트가 결합된 상태를 테스트합니다. API 엔드포인트와 데이터베이스의 실제 연동을 검증하는 것이 예입니다.
- E2E 테스트(End-to-End Test) — 피라미드 상단 (10%): 실제 사용자 시나리오를 브라우저 자동화로 테스트합니다. Playwright, Cypress가 대표적입니다. 가장 현실적이지만 느리고 불안정(Flaky)하기 쉽습니다.
5. 배포 전략: 제로 다운타임 달성하기
24/7 운영되는 서비스에서 배포 중 서비스 중단(Downtime)은 치명적입니다. 제로 다운타임 배포를 위한 여러 전략을 소개합니다.
블루-그린 배포(Blue-Green Deployment)는 두 개의 동일한 프로덕션 환경(블루, 그린)을 유지합니다. 현재 라이브인 블루 환경에서 서비스하는 동안, 그린 환경에 새 버전을 배포합니다. 준비가 되면 로드 밸런서를 그린으로 전환합니다. 문제 발생 시 즉시 블루로 롤백(Rollback)이 가능합니다.
카나리 배포(Canary Deployment)는 새 버전을 전체 사용자에게 한 번에 배포하는 대신, 소수의 사용자(예: 5%)에게 먼저 배포하여 실제 트래픽으로 검증합니다. 문제가 없으면 점진적으로 비율을 늘려 100%로 확대합니다. 위험을 최소화하면서 실제 사용자 피드백을 받을 수 있습니다.
롤링 배포(Rolling Deployment)는 여러 서버(포드)를 순차적으로 업데이트하는 방식입니다. 구 버전과 신 버전이 동시에 운영되는 순간이 있으므로, API 하위 호환성 유지가 중요합니다. Kubernetes의 기본 배포 전략입니다.
6. 대표적인 CI/CD 도구
현재 업계에서는 다양한 플랫폼들이 CI/CD 워크플로우를 제공하고 있습니다.
GitHub Actions: 리포지토리와 긴밀하게 연결되는 방식으로, YAML 스크립트를 통해 방대한 에코시스템의 워크플로우를 구성할 수 있습니다. GitHub 생태계를 사용한다면 가장 자연스러운 선택입니다.
Jenkins: 오래 전부터 가장 대중적인 도구였으며 플러그인 생태계가 막강합니다. 온프레미스 환경이나 복잡한 커스텀 파이프라인에 강점이 있지만 관리 부담이 있습니다.
GitLab CI/CD: 코드를 호스팅하는 랩에서 일체형으로 파이프라인을 구축 가능합니다. Auto DevOps 기능으로 설정 없이 자동 파이프라인도 지원합니다.
CircleCI / Buildkite: 빠른 빌드 속도와 유연한 워크플로우로 인기 있는 클라우드 CI/CD 서비스입니다.
결론
CI/CD 파이프라인이 잘 구축되어 있다면, 개발자는 코딩과 비즈니스 로직 작성 본연의 업무에만 집중할 수 있고 비효율적인 수동 배포 작업의 낭비를 막을 수 있습니다. 좋은 CI/CD는 단순한 자동화 도구가 아니라 팀 전체의 코드 품질 문화를 높이는 기반이 됩니다. 처음에는 GitHub Actions로 간단한 테스트 파이프라인부터 시작하고, 점진적으로 자동 배포와 다양한 환경(staging, production)을 추가해 나가는 것을 추천합니다.