카테고리 없음

CI/CD 완벽 가이드

Burnnnnnnnnnny 2024. 11. 5. 01:00

CI/CD 완벽 가이드: 현대적인 소프트웨어 개발 파이프라인 구축하기

들어가며

지속적 통합(Continuous Integration, CI)과 지속적 배포(Continuous Delivery/Deployment, CD)는 현대 소프트웨어 개발의 핵심 프랙티스입니다. 이 가이드에서는 CI/CD의 개념부터 실제 구현까지 상세히 다루겠습니다.

1. CI/CD 기본 개념

1.1 지속적 통합(CI)

  • 코드 변경사항의 정기적 통합
  • 자동화된 빌드 및 테스트
  • 품질 관리 자동화

1.2 지속적 배포(CD)

  • Continuous Delivery: 수동 승인 후 배포
  • Continuous Deployment: 완전 자동화된 배포
  • 안정적이고 빠른 제품 출시

2. CI/CD 파이프라인 구성요소

2.1 버전 관리

# Git 기본 워크플로우
git checkout -b feature/new-feature
git add .
git commit -m "feat: add new feature"
git push origin feature/new-feature

2.2 자동화된 빌드

# GitHub Actions 빌드 설정 예시
name: Build Application

on:
  push:
    branches: [ main, develop ]
  pull_request:
    branches: [ main, develop ]

jobs:
  build:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2

    - name: Set up JDK
      uses: actions/setup-java@v2
      with:
        java-version: '11'

    - name: Build with Maven
      run: mvn clean install

2.3 자동화된 테스트

// Jest 테스트 예시
describe('User Authentication', () => {
  test('should login with valid credentials', async () => {
    const response = await auth.login({
      username: 'testuser',
      password: 'testpass'
    });
    expect(response.status).toBe(200);
    expect(response.data.token).toBeDefined();
  });
});

2.4 코드 품질 검사

# SonarQube 설정 예시
sonar.projectKey=my-project
sonar.sources=src
sonar.tests=test
sonar.javascript.lcov.reportPaths=coverage/lcov.info
sonar.coverage.exclusions=**/*.test.js

3. 주요 CI/CD 도구

3.1 Jenkins 파이프라인

// Jenkinsfile 예시
pipeline {
    agent any

    stages {
        stage('Build') {
            steps {
                sh 'npm install'
                sh 'npm run build'
            }
        }

        stage('Test') {
            steps {
                sh 'npm run test'
            }
        }

        stage('Deploy') {
            when {
                branch 'main'
            }
            steps {
                sh './deploy.sh'
            }
        }
    }

    post {
        always {
            junit '**/test-results.xml'
            cleanWs()
        }
    }
}

3.2 GitHub Actions

# GitHub Actions 워크플로우 예시
name: CI/CD Pipeline

on:
  push:
    branches: [ main ]
  pull_request:
    branches: [ main ]

jobs:
  build-and-deploy:
    runs-on: ubuntu-latest

    steps:
    - uses: actions/checkout@v2

    - name: Use Node.js
      uses: actions/setup-node@v2
      with:
        node-version: '14'

    - name: Install dependencies
      run: npm ci

    - name: Run tests
      run: npm test

    - name: Deploy to production
      if: github.ref == 'refs/heads/main'
      run: |
        echo "${{ secrets.DEPLOY_KEY }}" > deploy_key
        chmod 600 deploy_key
        ssh -i deploy_key user@server './deploy.sh'

3.3 GitLab CI/CD

# .gitlab-ci.yml 예시
image: node:14

stages:
  - build
  - test
  - deploy

build:
  stage: build
  script:
    - npm install
    - npm run build
  artifacts:
    paths:
      - dist/

test:
  stage: test
  script:
    - npm run test
  coverage: '/Coverage: \d+.\d+%/'

deploy:
  stage: deploy
  script:
    - apt-get update -qy
    - apt-get install -y ruby-dev
    - gem install dpl
    - dpl --provider=heroku --app=my-app --api-key=$HEROKU_API_KEY
  only:
    - main

4. 배포 전략

4.1 블루-그린 배포

# Kubernetes Blue-Green 배포 예시
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-blue
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      version: blue
  template:
    metadata:
      labels:
        app: myapp
        version: blue
    spec:
      containers:
      - name: myapp
        image: myapp:1.0
---
apiVersion: apps/v1
kind: Deployment
metadata:
  name: myapp-green
spec:
  replicas: 3
  selector:
    matchLabels:
      app: myapp
      version: green
  template:
    metadata:
      labels:
        app: myapp
        version: green
    spec:
      containers:
      - name: myapp
        image: myapp:2.0

4.2 카나리 배포

# Istio 카나리 배포 예시
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: myapp
spec:
  hosts:
  - myapp.com
  http:
  - route:
    - destination:
        host: myapp-v1
      weight: 90
    - destination:
        host: myapp-v2
      weight: 10

5. 모니터링과 로깅

5.1 로그 수집

# ELK Stack 설정 예시
input {
  beats {
    port => 5044
  }
}

filter {
  grok {
    match => { "message" => "%{COMBINEDAPACHELOG}" }
  }
}

output {
  elasticsearch {
    hosts => ["localhost:9200"]
    index => "app-logs-%{+YYYY.MM.dd}"
  }
}

5.2 메트릭 모니터링

# Prometheus 설정 예시
global:
  scrape_interval: 15s

scrape_configs:
  - job_name: 'spring-actuator'
    metrics_path: '/actuator/prometheus'
    static_configs:
      - targets: ['localhost:8080']

6. CI/CD 보안

6.1 보안 스캔

# Docker 이미지 보안 스캔 예시
name: Security Scan

on:
  push:
    branches: [ main ]

jobs:
  security:
    runs-on: ubuntu-latest
    steps:
    - uses: actions/checkout@v2

    - name: Run Trivy vulnerability scanner
      uses: aquasecurity/trivy-action@master
      with:
        image-ref: 'my-docker-image:latest'
        format: 'table'
        exit-code: '1'
        ignore-unfixed: true
        severity: 'CRITICAL,HIGH'

6.2 시크릿 관리

# Vault 설정 예시
path "secret/data/myapp/*" {
  capabilities = ["read", "list"]
}

path "auth/token/create" {
  capabilities = ["create", "update"]
}

7. CI/CD 모범 사례

7.1 파이프라인 최적화

  • 병렬 실행 활용
  • 캐싱 전략 수립
  • 테스트 최적화

7.2 구성 관리

  • Infrastructure as Code
  • 환경 설정 분리
  • 버전 관리

결론

CI/CD는 현대 소프트웨어 개발의 핵심 요소입니다. 효과적인 CI/CD 파이프라인을 구축하고 유지하기 위해서는 도구의 선택부터 보안, 모니터링까지 다양한 측면을 고려해야 합니다. 각 조직의 상황과 요구사항에 맞는 CI/CD 전략을 수립하고, 지속적으로 개선해 나가는 것이 중요합니다.