🔧 DevOps

Workflow

워크플로우

자동화된 작업 흐름. GitHub Actions 워크플로우. YAML 정의.

상세 설명

워크플로우(Workflow)는 특정 목표를 달성하기 위해 정의된 자동화된 작업 흐름입니다. DevOps에서는 주로 CI/CD 파이프라인, 데이터 처리 파이프라인, 인프라 자동화 시나리오를 의미합니다. GitHub Actions, Argo Workflows, Apache Airflow가 대표적인 워크플로우 엔진입니다.

워크플로우는 트리거(Trigger), 잡(Job), 스텝(Step)으로 구성됩니다. 트리거는 워크플로우를 시작하는 이벤트(push, schedule, webhook), 잡은 독립적으로 실행되는 작업 단위, 스텝은 잡 내의 개별 명령입니다. 잡 간 의존성과 조건부 실행을 정의할 수 있습니다.

선언적 정의가 핵심입니다. YAML, JSON 또는 DSL로 워크플로우를 정의하면 엔진이 실행을 관리합니다. 상태 관리, 재시도, 병렬 실행, 로깅이 자동으로 처리되어 복잡한 조정 로직을 직접 구현할 필요가 없습니다.

실무에서는 코드 푸시 시 빌드-테스트-배포를 자동화하거나, 정기적인 데이터 처리(ETL), 인프라 프로비저닝에 활용합니다. 워크플로우를 코드로 관리(Workflow as Code)하면 버전 관리, 리뷰, 재사용이 가능해집니다.

코드 예제

# GitHub Actions CI/CD 워크플로우 예제
# .github/workflows/ci-cd.yml

name: CI/CD Pipeline

on:
  push:
    branches: [main, develop]
  pull_request:
    branches: [main]
  # 수동 실행 가능
  workflow_dispatch:
    inputs:
      environment:
        description: '배포 환경'
        required: true
        default: 'staging'
        type: choice
        options:
          - staging
          - production

env:
  REGISTRY: ghcr.io
  IMAGE_NAME: ${{ github.repository }}

jobs:
  # 1단계: 린트 및 타입 체크
  lint:
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run ESLint
        run: npm run lint

      - name: Run TypeScript check
        run: npm run type-check

  # 2단계: 테스트 (린트와 병렬 실행)
  test:
    runs-on: ubuntu-latest
    services:
      postgres:
        image: postgres:15
        env:
          POSTGRES_PASSWORD: test
        ports:
          - 5432:5432
        options: >-
          --health-cmd pg_isready
          --health-interval 10s
          --health-timeout 5s
          --health-retries 5

    steps:
      - uses: actions/checkout@v4

      - name: Setup Node.js
        uses: actions/setup-node@v4
        with:
          node-version: '20'
          cache: 'npm'

      - name: Install dependencies
        run: npm ci

      - name: Run tests
        run: npm test -- --coverage
        env:
          DATABASE_URL: postgresql://postgres:test@localhost:5432/test

      - name: Upload coverage
        uses: codecov/codecov-action@v3
        with:
          token: ${{ secrets.CODECOV_TOKEN }}

  # 3단계: 빌드 (린트, 테스트 완료 후)
  build:
    needs: [lint, test]
    runs-on: ubuntu-latest
    permissions:
      contents: read
      packages: write

    outputs:
      image-tag: ${{ steps.meta.outputs.tags }}

    steps:
      - uses: actions/checkout@v4

      - name: Log in to Container Registry
        uses: docker/login-action@v3
        with:
          registry: ${{ env.REGISTRY }}
          username: ${{ github.actor }}
          password: ${{ secrets.GITHUB_TOKEN }}

      - name: Extract metadata
        id: meta
        uses: docker/metadata-action@v5
        with:
          images: ${{ env.REGISTRY }}/${{ env.IMAGE_NAME }}
          tags: |
            type=sha,prefix=
            type=ref,event=branch

      - name: Build and push
        uses: docker/build-push-action@v5
        with:
          context: .
          push: true
          tags: ${{ steps.meta.outputs.tags }}
          cache-from: type=gha
          cache-to: type=gha,mode=max

  # 4단계: 배포 (main 브랜치만)
  deploy:
    needs: build
    if: github.ref == 'refs/heads/main'
    runs-on: ubuntu-latest
    environment:
      name: production
      url: https://myapp.example.com

    steps:
      - name: Deploy to Kubernetes
        uses: azure/k8s-deploy@v4
        with:
          action: deploy
          manifests: k8s/
          images: ${{ needs.build.outputs.image-tag }}

      - name: Notify Slack
        uses: slackapi/slack-github-action@v1
        with:
          payload: |
            {
              "text": "Deployed ${{ github.sha }} to production"
            }
        env:
          SLACK_WEBHOOK_URL: ${{ secrets.SLACK_WEBHOOK }}

실무에서 이렇게 말해요

시니어: "PR마다 수동으로 테스트 돌리고 있는데, GitHub Actions 워크플로우 만들면 push할 때 자동으로 돌아가요."

주니어: "테스트 통과 안 하면 머지 못하게 막을 수 있나요?"

시니어: "네, Branch Protection Rule에서 required status checks 설정하면 워크플로우 성공해야만 머지 버튼 활성화돼요."

면접관: "CI/CD 파이프라인 설계 경험을 설명해주세요."

지원자: "GitHub Actions로 빌드-테스트-배포 워크플로우를 구성했습니다. lint와 test job을 병렬로 실행해 시간을 단축하고, build job은 둘 다 성공해야 실행되도록 needs로 의존성을 설정했습니다. main 브랜치 push 시에만 deploy job이 실행되고, environment approval로 프로덕션 배포 전 승인을 받도록 했습니다."

리뷰어: "워크플로우에서 npm ci 대신 npm install 쓰셨는데, ci가 lock 파일 기반이라 더 안정적이에요."

개발자: "npm ci로 바꾸고, actions/setup-node의 cache 옵션도 추가해서 의존성 설치 시간 줄이겠습니다."

주의사항

더 배우기