CollabOps

프로덕션 전체 파이프라인

실제 프로덕션 환경의 전체 CI/CD 파이프라인 — 체크아웃부터 배포, 알림까지

실제 프로덕션 환경에서 사용할 수 있는 전체 파이프라인 예제입니다. 체크아웃, 린트, 테스트, 빌드, 배포, 알림까지 모든 단계를 포함합니다.

전체 코드

name: production-pipeline

# ─────────────────────────────────────────
# 트리거 설정
# ─────────────────────────────────────────
triggers:
  # main/develop push 시 실행 (src/ 변경 시에만)
  push:
    branches: [main, develop]
    paths: [src/**, package.json, Dockerfile]

  # main 대상 Change Request 시 실행
  change_request:
    branches: [main]

  # 매일 자정 스케줄 실행
  schedule:
    branch: main
    cron: ["0 0 * * *"]

  # 수동 실행 가능
  workflow_dispatch:

# ─────────────────────────────────────────
# 전역 환경 변수
# ─────────────────────────────────────────
env:
  APP_NAME: my-app
  REGISTRY: "asia-northeast3-docker.pkg.dev"
  PROJECT_ID: "${{ vars.GCP_PROJECT_ID }}"

jobs:
  # ═══════════════════════════════════════
  # Phase 1: Source
  # ═══════════════════════════════════════

  checkout:
    phase: source
    steps:
      - name: checkout
        uses: "collabops/checkout@v2"
        with:
          repo-url: "https://<collabops-host>/<workspace>/<repository>.git"
          fetch-depth: "0"         # 전체 히스토리 (버전 추출용)

  # 버전 정보 + 메타데이터 수집 (build Job 내부에서 사용)
  # → Step Output은 같은 Job 내에서만 참조 가능하므로,
  #   메타데이터 수집 step을 build Job 안에 배치합니다.

  # ═══════════════════════════════════════
  # Phase 2: Dependencies
  # ═══════════════════════════════════════

  install:
    phase: deps
    needs: [checkout]
    steps:
      - name: npm-ci
        image: node:18
        run: |
          cd /workspace/source
          npm ci                   # 의존성 clean install

  # ═══════════════════════════════════════
  # Phase 3: Test (병렬 실행)
  # ═══════════════════════════════════════

  lint:
    phase: test
    needs: [install]
    steps:
      - name: eslint
        image: node:18
        run: |
          cd /workspace/source
          npm run lint

      - name: typecheck
        image: node:18
        run: |
          cd /workspace/source
          npx tsc --noEmit

  test:
    phase: test
    needs: [install]               # lint와 병렬 실행
    steps:
      - name: unit-test
        id: test-result
        image: node:18
        run: |
          cd /workspace/source
          npm test -- --coverage 2>&1 | tee /tmp/test.txt

          # 커버리지 수치 추출
          COVERAGE=$(grep 'Statements' /tmp/test.txt | grep -oP '\d+\.\d+' | head -1 || echo "N/A")
          echo "coverage=${COVERAGE}%" >> $COLLABOPS_OUTPUT
        env:
          CI: "true"

  # ═══════════════════════════════════════
  # Phase 4: Build
  # ═══════════════════════════════════════

  # GCP 인증 (빌드/배포에 필요)
  auth:
    phase: build
    needs: [checkout]
    steps:
      - name: gcloud-auth
        uses: "collabops/gcloud-auth@v1"
        with:
          project-id: ${{ vars.GCP_PROJECT_ID }}
          credentials: ${{ secrets.GCP_SA_KEY }}

      - name: docker-auth
        uses: "collabops/gcloud-docker-auth@v1"
        with:
          registry: ${{ env.REGISTRY }}

  build:
    phase: build
    needs: [lint, test, auth]             # 테스트 통과 + 인증 완료 후
    services:
      - docker                     # Docker 서비스 활성화
    steps:
      # 메타데이터 수집 (같은 Job 내에서 step output 참조)
      - name: collect-meta
        id: meta
        image: node:18
        run: |
          cd /workspace/source

          # package.json 버전
          VERSION=$(node -p "require('./package.json').version")
          echo "version=${VERSION}" >> $COLLABOPS_OUTPUT

          # 짧은 SHA (이미지 태그용)
          SHORT_SHA=$(echo "${{ collabops.sha }}" | cut -c1-7)
          echo "short_sha=${SHORT_SHA}" >> $COLLABOPS_OUTPUT

          # 빌드 타임스탬프
          echo "build_time=$(date -u +%Y%m%dT%H%M%S)" >> $COLLABOPS_OUTPUT

          echo "=== Build Metadata ==="
          echo "Version: ${VERSION}"
          echo "SHA: ${SHORT_SHA}"
          echo "Branch: ${{ collabops.ref_name }}"
          echo "Event: ${{ collabops.event_name }}"

      - name: build-push
        uses: "collabops/docker-build-push@v1"
        with:
          tags: |
            ${{ env.REGISTRY }}/${{ env.PROJECT_ID }}/docker/${{ env.APP_NAME }}:latest
            ${{ env.REGISTRY }}/${{ env.PROJECT_ID }}/docker/${{ env.APP_NAME }}:${{ steps.meta.outputs.version }}
            ${{ env.REGISTRY }}/${{ env.PROJECT_ID }}/docker/${{ env.APP_NAME }}:${{ steps.meta.outputs.short_sha }}
          build-args: |
            NODE_ENV=production
            APP_VERSION=${{ steps.meta.outputs.version }}
            BUILD_TIME=${{ steps.meta.outputs.build_time }}

  # ═══════════════════════════════════════
  # Phase 5: Deploy (main push만)
  # ═══════════════════════════════════════

  deploy:
    phase: deploy
    needs: [build]
    # main 브랜치 push일 때만 프로덕션 배포
    # CR이나 다른 브랜치에서는 빌드까지만 실행
    if: "collabops.ref == 'refs/heads/main' && collabops.event_name == 'push'"
    steps:
      # GKE 클러스터 인증
      - name: gke-setup
        uses: "collabops/gcloud-setup@v1"
        with:
          project-id: ${{ vars.GCP_PROJECT_ID }}
          cluster-name: ${{ vars.GKE_CLUSTER }}
          cluster-location: ${{ vars.GKE_REGION }}

      # 프로덕션 배포
      - name: rollout
        image: google/cloud-sdk:527.0.0-slim
        run: |
          SHORT_SHA=$(echo "${{ collabops.sha }}" | cut -c1-7)
          IMAGE="${{ env.REGISTRY }}/${{ env.PROJECT_ID }}/docker/${{ env.APP_NAME }}:${SHORT_SHA}"

          echo "Deploying ${IMAGE} to production..."

          # Deployment 이미지 업데이트
          kubectl set image deployment/${{ env.APP_NAME }} \
            app=${IMAGE} \
            -n production

          # 롤아웃 완료 대기 (최대 5분)
          kubectl rollout status deployment/${{ env.APP_NAME }} \
            -n production \
            --timeout=300s

          echo "Deploy complete!"

  # ═══════════════════════════════════════
  # Phase 6: Notification (항상 실행)
  # ═══════════════════════════════════════

  notify:
    needs: [deploy]
    if: "always()"                 # 성공/실패 관계없이 항상 알림
    steps:
      - name: slack
        uses: "collabops/slack-notify@v1"
        with:
          webhook-url: ${{ secrets.SLACK_WEBHOOK }}
          title: "Production Deploy"
          message: |
            App: ${{ env.APP_NAME }}
            Branch: ${{ collabops.ref_name }}
            Commit: ${{ collabops.sha }}
            Actor: ${{ collabops.actor }}
          color: good

실행 흐름

checkout
  ├── install (의존성 설치)
  │     ├── lint (ESLint + TypeScript)    ← 병렬
  │     └── test (단위 테스트 + 커버리지)  ← 병렬
  └── auth (GCP + Docker 인증)

              └── build (메타데이터 수집 → Docker 빌드 & 푸시)
                    │     ※ lint, test, auth 모두 완료 후 실행
                    └── deploy (GKE 배포, main push만)
                          └── notify (Slack 알림, 항상)

트리거별 동작

트리거실행 범위
push (main)전체 실행 (테스트 → 빌드 → 배포 → 알림)
push (develop)테스트 → 빌드까지 (배포 건너뜀)
change_request테스트 → 빌드까지 (배포 건너뜀)
schedule테스트 → 빌드까지 (배포 건너뜀)
workflow_dispatch테스트 → 빌드까지 (배포 건너뜀)

deploy Job의 if 조건이 collabops.event_name == 'push'이므로, schedule이나 workflow_dispatch를 포함하여 push 외의 모든 트리거에서는 빌드까지만 실행되고 배포는 건너뜁니다.

목차