sy/dev
Study
9 min read

GitOps와 CI/CD — GitHub Actions에서 Kubernetes까지 자동화 배포 파이프라인

지금까지 Docker, Kubernetes, AWS, 배포 전략을 배웠다. 이제 마지막 퍼즐: 자동화. 코드를 push하는 순간 테스트·빌드·배포가 자동으로 일어난다면? GitHub Actions로 CI/CD 파이프라인을 구성하고, GitOps 원칙으로 선언형 배포를 관리하자.

💡

한 줄 요약CI/CD는 코드 push → 자동 테스트 → 자동 빌드 → 자동 배포의 파이프라인이고, GitOps는 Git을 진실의 원천(source of truth)으로 삼아 선언형 배포를 자동화하는 방식이다.

지금까지 배운 것들을 다시 정리하면:

1. Docker: 앱을 Container로 만들기
2. Kubernetes: Container를 자동으로 관리
3. AWS: 클라우드 인프라 제공
4. 배포 전략: Blue-Green, Canary, Rolling

하지만 현실에서 매일 이 모든 걸 수동으로 하려면:

$ docker build -t myapp:v1.1 .
$ docker push myapp:v1.1
$ kubectl set image deployment/myapp myapp=myapp:v1.1
$ kubectl rollout status deployment/myapp
# ... 손으로 여러 번 타이핑

이걸 매번 하려면? 자동화가 필수다.

CI/CD란?

CI (Continuous Integration) — 지속적 통합

git push (코드 변경)
  ↓
GitHub 웹훅 감지
  ↓
자동으로 테스트 실행
  ├─ 단위 테스트 ✅
  ├─ 통합 테스트 ✅
  └─ 린트 검사 ✅
  ↓
테스트 통과 → Merge 가능 (PR 승인)
테스트 실패 → Merge 불가 (고쳐야 함)

목표: 코드 품질 자동 검증. 문제를 빨리 발견.

CD (Continuous Deployment) — 지속적 배포

테스트 통과 → main 브랜치 merge
  ↓
자동으로 Docker 이미지 빌드
  ↓
이미지를 Registry (Docker Hub, ECR)에 푸시
  ↓
Kubernetes 클러스터에 자동 배포
  ↓
사용자가 새 버전 사용 (수동 개입 0)

목표: 검증된 코드를 자동으로 본환경에 배포. 배포 속도 극대화.

GitHub Actions로 CI/CD 구현

1단계: 테스트 자동화 (CI)

# .github/workflows/test.yml
name: CI - Test
 
on:
  pull_request:
    branches: [main]
 
jobs:
  test:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Set up Python
      uses: actions/setup-python@v4
      with:
        python-version: 3.11
    
    - name: Install dependencies
      run: |
        python -m pip install --upgrade pip
        pip install -r requirements.txt
    
    - name: Run tests
      run: |
        python -m pytest tests/
    
    - name: Run linter
      run: |
        flake8 app/

동작:

  1. PR 생성 → 자동으로 워크플로우 실행
  2. 테스트 통과 → "✅ All checks passed" (merge 가능)
  3. 테스트 실패 → "❌ Tests failed" (merge 불가)

2단계: 빌드 및 배포 (CD)

# .github/workflows/deploy.yml
name: CD - Deploy to Kubernetes
 
on:
  push:
    branches: [main]  # main 브랜치에만
 
jobs:
  deploy:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Build Docker image
      run: |
        docker build -t myapp:${{ github.sha }} .
        docker build -t myapp:latest .
    
    - name: Login to Docker Hub
      uses: docker/login-action@v2
      with:
        username: ${{ secrets.DOCKER_USERNAME }}
        password: ${{ secrets.DOCKER_PASSWORD }}
    
    - name: Push to Docker Hub
      run: |
        docker push myapp:${{ github.sha }}
        docker push myapp:latest
    
    - name: Deploy to Kubernetes
      run: |
        # kubectl 설정 (kubeconfig 복원)
        mkdir -p $HOME/.kube
        echo "${{ secrets.KUBECONFIG }}" | base64 -d > $HOME/.kube/config
        
        # 이미지 업데이트 (Rolling 배포 시작)
        kubectl set image deployment/myapp \
          myapp=myapp:${{ github.sha }} \
          --record
        
        # 배포 상태 확인
        kubectl rollout status deployment/myapp --timeout=5m
    
    - name: Notify Slack
      if: always()
      run: |
        STATUS="${{ job.status }}"
        curl -X POST ${{ secrets.SLACK_WEBHOOK }} \
          -d "{\"text\":\"Deploy $STATUS: myapp:${{ github.sha }}\"}"

동작 흐름:

git push main
  ↓
GitHub Actions 트리거
  ↓
1. Docker 이미지 빌드 (myapp:abc123)
  ↓
2. Docker Hub에 푸시
  ↓
3. kubectl set image 명령 실행
  ↓
4. Kubernetes가 자동으로 롤링 배포 시작
  ↓
5. 배포 완료 → Slack 알림

3단계: Secrets 관리

워크플로우에서 민감 정보 사용:

# .github/workflows/deploy.yml에서 사용
username: ${{ secrets.DOCKER_USERNAME }}
password: ${{ secrets.DOCKER_PASSWORD }}
kubeconfig: ${{ secrets.KUBECONFIG }}
slack_webhook: ${{ secrets.SLACK_WEBHOOK }}

설정 방법:

GitHub Repository
→ Settings
  → Secrets and variables
    → Actions
      → New repository secret
        - DOCKER_USERNAME: seongyeon
        - DOCKER_PASSWORD: (access token)
        - KUBECONFIG: (base64 인코딩된 kubeconfig)
        - SLACK_WEBHOOK: https://hooks.slack.com/...

GitOps 패턴

정의

Git을 진실의 원천(source of truth)으로 삼아, Git의 상태가 곧 본환경의 상태가 되도록 관리하는 방식.

전통 (Imperative)

# 개발자가 직접 명령
$ kubectl apply -f deployment.yaml
$ kubectl set image deployment/myapp myapp=myapp:v1.1
$ kubectl scale deployment/myapp --replicas=10
# Git과 실제 상태가 불일치할 수 있음 ❌

GitOps (Declarative)

Git Repository
└─ kubernetes/
   ├─ deployment.yaml
   ├─ service.yaml
   └─ configmap.yaml

Kubernetes Cluster
└─ GitOps 에이전트 (ArgoCD, Flux)
   └─ 계속 Git을 감시
   └─ Git과 클러스터 상태 동기화

변경 과정:
1. deployment.yaml 에서 replicas: 5 → 10 변경
2. git push
3. GitOps 에이전트가 감지
4. 자동으로 kubectl apply 실행
5. Pod 10개로 확장

장점

  • 진실의 원천: Git = 현재 상태 (항상 일치)
  • 감시 기능: 누군가 수동으로 kubectl 변경해도 자동으로 Git 상태로 복구
  • 버전 관리: 배포 히스토리가 Git에 기록됨 (audit trail)
  • Rollback: git revert 한 줄로 이전 버전 복구

실전: 이 블로그의 CI/CD

이 블로그의 배포 파이프라인을 예로 들어보자:

# .github/workflows/deploy.yml
name: Deploy Blog
 
on:
  push:
    branches: [main]
 
jobs:
  build-and-deploy:
    runs-on: ubuntu-latest
    
    steps:
    - uses: actions/checkout@v3
    
    - name: Setup Node.js
      uses: actions/setup-node@v3
      with:
        node-version: 18
    
    - name: Install dependencies
      run: npm install
    
    - name: Build static site
      run: npm run build
      # Next.js가 HTML/CSS/JS 생성
    
    - name: Deploy to GitHub Pages
      uses: peaceiris/actions-gh-pages@v3
      with:
        github_token: ${{ secrets.GITHUB_TOKEN }}
        publish_dir: ./out
        # out 디렉토리를 gh-pages 브랜치에 푸시

결과:

Markdown 파일 작성
  ↓ git push
GitHub Actions 트리거
  ↓
Next.js 빌드 (Markdown → HTML)
  ↓
정적 파일을 gh-pages 브랜치에 푸시
  ↓
GitHub Pages가 자동 배포
  ↓
블로그 업데이트 완료 (수동 개입 0)

이것이 CI/CD의 진정한 가치: 코드 → 배포까지 자동화.

ArgoCD로 GitOps 구현

더 정교한 Kubernetes 배포를 위해 ArgoCD 사용:

# kubernetes/argocd-app.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
  name: myapp
  namespace: argocd
spec:
  project: default
  source:
    repoURL: https://github.com/me/myapp-config
    targetRevision: main
    path: kubernetes/
  destination:
    server: https://kubernetes.default.svc
    namespace: production
  syncPolicy:
    automated:
      prune: true      # Git에서 삭제된 리소스도 제거
      selfHeal: true   # 수동 변경도 자동으로 복구
    syncOptions:
    - CreateNamespace=true

동작:

  1. Git 저장소의 kubernetes/ 폴더를 감시
  2. deployment.yaml 수정 → git push
  3. ArgoCD가 자동으로 감지 (또는 수동 sync)
  4. kubectl apply 자동 실행
  5. 클러스터 상태 = Git 상태

CI/CD 체크리스트

프로덕션 환경의 CI/CD 파이프라인:

- [ ] 테스트 자동화 (단위, 통합, E2E)
- [ ] 코드 품질 검사 (linter, SAST)
- [ ] 보안 스캔 (의존성 취약점, 이미지 스캔)
- [ ] Docker 이미지 빌드 및 서명
- [ ] 이미지 Registry에 푸시
- [ ] Kubernetes 배포 자동화
- [ ] 배포 후 스모크 테스트 (health check)
- [ ] Slack/이메일 알림
- [ ] 자동 롤백 (실패 시)
- [ ] 배포 승인 프로세스 (선택적)

핵심 정리

단계도구역할
CIGitHub Actions테스트, 린트, 빌드
RegistryDocker Hub / ECR이미지 저장
CDGitHub Actions / ArgoCD배포 자동화
GitOpsArgoCD / FluxGit 상태 동기화

다음 글 예고

  • 모니터링·로깅: Prometheus, Grafana, ELK... 운영 환경 관찰하기

참고자료

Comments