Skip to content

필사 모드: 고급 CI/CD 파이프라인 구축 가이드 — GitHub Actions, ArgoCD, Tekton, 보안 파이프라인

한국어
0%
정확도 0%
💡 왼쪽 원문을 읽으면서 오른쪽에 따라 써보세요. Tab 키로 힌트를 받을 수 있습니다.
원문 렌더가 준비되기 전까지 텍스트 가이드로 표시합니다.

들어가며

CI/CD를 "코드 푸시하면 자동으로 배포되는 것" 정도로 이해하는 단계를 넘어, 프로덕션 수준의 파이프라인이 무엇인지 고민해 본 적이 있는가? 실제 프로덕션 환경에서는 보안 스캔, 정적 분석, 컨테이너 이미지 서명, 멀티 클러스터 배포, 자동 롤백까지 수십 개의 단계가 유기적으로 연결되어야 한다.

이 글에서는 CI/CD 성숙도 모델부터 GitHub Actions 고급 패턴, ArgoCD GitOps, Tekton 클라우드 네이티브 파이프라인, DevSecOps 보안 파이프라인, 배포 전략 심화까지 종합적으로 다룬다.

1. CI/CD 성숙도 모델

조직의 CI/CD 수준을 객관적으로 평가하기 위한 5단계 성숙도 모델이다. 각 레벨은 이전 레벨의 역량 위에 구축된다.

Level 1 - 수동 (Manual)

빌드와 배포를 개발자가 수동으로 수행하는 단계다. 로컬에서 빌드하고 FTP나 SCP로 서버에 직접 배포한다. "내 컴퓨터에서는 되는데"가 일상적으로 발생하며, 배포 주기가 월 단위인 경우가 많다.

**특징:** 문서화된 절차가 있을 수 있지만 자동화는 거의 없다. 배포 시 휴먼 에러가 빈번하고, 롤백은 이전 버전을 수동으로 다시 배포하는 방식이다.

Level 2 - 기본 자동화 (Basic Automation)

CI 서버가 도입되어 코드 푸시 시 자동 빌드와 테스트가 실행된다. Jenkins, GitHub Actions, GitLab CI 같은 도구를 사용하지만, 파이프라인이 단순한 빌드-테스트-배포 직선 구조다.

Level 2: 기본 파이프라인 예시

name: Basic CI/CD

on:

push:

branches: [main]

jobs:

build-and-deploy:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- run: npm install

- run: npm test

- run: npm run build

- run: ./deploy.sh

Level 3 - 표준화 (Standardized)

파이프라인이 조직 전체에 표준화되고, 재사용 가능한 파이프라인 템플릿이 존재한다. 테스트 커버리지 게이트, 코드 품질 체크, 보안 스캔이 기본으로 포함된다. 환경별(dev, staging, prod) 배포 파이프라인이 분리되어 있다.

Level 4 - 고급 자동화 (Advanced Automation)

GitOps 기반 선언적 배포, 카나리/블루-그린 배포 전략, 자동화된 보안 파이프라인(SAST, DAST, 컨테이너 스캔), SBOM 생성과 아티팩트 서명이 파이프라인에 통합된다. 배포 주기가 일 단위 이하로 줄어든다.

Level 5 - 자가 치유 (Self-Healing)

메트릭 기반 자동 롤백, SLO 위반 시 자동 복구, ML 기반 이상 탐지, 프로덕션 피드백이 파이프라인에 자동 반영된다. 배포가 완전히 자동화되어 개발자가 배포를 의식하지 않는다.

| 레벨 | 배포 주기 | 롤백 방식 | 보안 | 테스트 |

|------|-----------|-----------|------|--------|

| L1 수동 | 월 단위 | 수동 재배포 | 없음 | 수동 |

| L2 기본 | 주 단위 | 수동 트리거 | 없음 | 자동 유닛 |

| L3 표준 | 일 단위 | 원클릭 롤백 | 기본 스캔 | 유닛+통합 |

| L4 고급 | 시간 단위 | 자동 카나리 | 전체 파이프라인 | 유닛+통합+E2E |

| L5 치유 | 지속 배포 | SLO 기반 자동 | 지속적 검증 | 카오스 포함 |

2. GitHub Actions 고급 패턴

GitHub Actions의 기본을 넘어서는 고급 패턴들이다.

2-1. 재사용 가능한 워크플로 (Reusable Workflows)

여러 저장소에서 동일한 파이프라인 로직을 공유하려면 재사용 워크플로를 활용한다. 호출하는 쪽에서는 `uses` 키워드로 외부 워크플로를 참조한다.

.github/workflows/reusable-build.yml (공유 저장소)

name: Reusable Build

on:

workflow_call:

inputs:

node-version:

required: false

type: string

default: '20'

registry-url:

required: true

type: string

secrets:

npm-token:

required: true

jobs:

build:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- uses: actions/setup-node@v4

with:

node-version: ${{ inputs.node-version }}

registry-url: ${{ inputs.registry-url }}

- run: npm ci

env:

NODE_AUTH_TOKEN: ${{ secrets.npm-token }}

- run: npm run build

- uses: actions/upload-artifact@v4

with:

name: build-output

path: dist/

호출하는 워크플로

name: App CI

on: [push]

jobs:

call-build:

uses: my-org/shared-workflows/.github/workflows/reusable-build.yml@v2

with:

node-version: '20'

registry-url: 'https://npm.pkg.github.com'

secrets:

npm-token: ${{ secrets.NPM_TOKEN }}

2-2. Composite Actions

하나의 액션 안에 여러 단계를 묶어 재사용하는 패턴이다. 재사용 워크플로와 달리 단일 job의 step으로 삽입된다.

.github/actions/setup-and-test/action.yml

name: 'Setup and Test'

description: 'Node.js 환경 설정 후 테스트 실행'

inputs:

node-version:

description: 'Node.js version'

required: false

default: '20'

runs:

using: 'composite'

steps:

- uses: actions/setup-node@v4

with:

node-version: ${{ inputs.node-version }}

cache: 'npm'

- run: npm ci

shell: bash

- run: npm test -- --coverage

shell: bash

- uses: actions/upload-artifact@v4

with:

name: coverage

path: coverage/

2-3. 매트릭스 빌드 전략

여러 환경 조합을 병렬로 테스트하되, 불필요한 조합을 제외하는 고급 매트릭스 설정이다.

jobs:

test:

strategy:

fail-fast: false

matrix:

os: [ubuntu-latest, macos-latest, windows-latest]

node: [18, 20, 22]

exclude:

- os: macos-latest

node: 18

include:

- os: ubuntu-latest

node: 22

experimental: true

runs-on: ${{ matrix.os }}

continue-on-error: ${{ matrix.experimental || false }}

steps:

- uses: actions/checkout@v4

- uses: actions/setup-node@v4

with:

node-version: ${{ matrix.node }}

- run: npm ci

- run: npm test

2-4. OIDC를 이용한 클라우드 인증

장기 시크릿(Access Key) 대신 OIDC(OpenID Connect) 토큰을 사용하여 클라우드에 안전하게 인증하는 방식이다. AWS, GCP, Azure 모두 지원한다.

jobs:

deploy:

runs-on: ubuntu-latest

permissions:

id-token: write

contents: read

steps:

- uses: actions/checkout@v4

- uses: aws-actions/configure-aws-credentials@v4

with:

role-to-assume: arn:aws:iam::123456789012:role/github-actions-role

aws-region: ap-northeast-2

- run: aws s3 sync ./dist s3://my-bucket

- run: aws cloudfront create-invalidation --distribution-id E1234 --paths "/*"

OIDC의 핵심 장점은 시크릿 관리가 필요 없다는 것이다. GitHub에서 발급한 단기 토큰을 AWS STS가 검증하고 임시 자격 증명을 발급한다. 토큰은 워크플로 실행 중에만 유효하므로 유출되어도 악용이 어렵다.

3. GitOps와 ArgoCD

3-1. GitOps 원칙

GitOps는 Git을 단일 진실 원천(Single Source of Truth)으로 사용하여 인프라와 애플리케이션의 선언적 상태를 관리하는 운영 모델이다. 네 가지 핵심 원칙이 있다.

**선언적 설정:** 시스템의 원하는 상태를 선언적으로 기술한다. "무엇을" 원하는지 정의하지, "어떻게" 달성할지 명령하지 않는다.

**Git을 진실의 원천으로:** 모든 변경은 Git을 통해 이루어지고, Git 히스토리가 곧 감사 로그다.

**자동 적용:** Git의 선언적 상태가 변경되면 자동으로 시스템에 적용된다.

**지속적 조정:** 에이전트가 실제 상태와 원하는 상태를 지속적으로 비교하여 차이(drift)를 교정한다.

3-2. ArgoCD 아키텍처

ArgoCD는 쿠버네티스를 위한 선언적 GitOps 연속 배포 도구다.

ArgoCD Application 리소스

apiVersion: argoproj.io/v1alpha1

kind: Application

metadata:

name: my-app

namespace: argocd

spec:

project: default

source:

repoURL: https://github.com/my-org/k8s-manifests.git

targetRevision: main

path: apps/my-app/overlays/production

destination:

server: https://kubernetes.default.svc

namespace: my-app

syncPolicy:

automated:

prune: true

selfHeal: true

syncOptions:

- CreateNamespace=true

retry:

limit: 5

backoff:

duration: 5s

factor: 2

maxDuration: 3m

`syncPolicy.automated`를 설정하면 Git 변경 시 자동으로 클러스터에 반영된다. `selfHeal: true`는 누군가 수동으로 클러스터 상태를 변경해도 Git 상태로 자동 복원하는 기능이다.

3-3. App of Apps 패턴

대규모 환경에서는 수십~수백 개의 Application을 관리해야 한다. App of Apps 패턴은 하나의 루트 Application이 나머지 Application들을 관리하는 구조다.

root-app.yaml - 다른 Application들을 관리하는 루트

apiVersion: argoproj.io/v1alpha1

kind: Application

metadata:

name: root-app

namespace: argocd

spec:

project: default

source:

repoURL: https://github.com/my-org/argocd-apps.git

targetRevision: main

path: apps

destination:

server: https://kubernetes.default.svc

namespace: argocd

apps/frontend.yaml - 루트가 관리하는 자식 Application

apiVersion: argoproj.io/v1alpha1

kind: Application

metadata:

name: frontend

namespace: argocd

spec:

project: default

source:

repoURL: https://github.com/my-org/k8s-manifests.git

path: apps/frontend/overlays/production

targetRevision: main

destination:

server: https://kubernetes.default.svc

namespace: frontend

3-4. ApplicationSet으로 멀티 클러스터 배포

ApplicationSet은 하나의 템플릿으로 여러 Application을 자동 생성하는 ArgoCD의 기능이다. 클러스터 목록, Git 디렉토리, PR 이벤트 등을 기반으로 동적 생성한다.

apiVersion: argoproj.io/v1alpha1

kind: ApplicationSet

metadata:

name: my-app-set

namespace: argocd

spec:

generators:

- clusters:

selector:

matchLabels:

env: production

template:

metadata:

name: 'my-app-{{name}}'

spec:

project: default

source:

repoURL: https://github.com/my-org/k8s-manifests.git

targetRevision: main

path: 'apps/my-app/overlays/{{metadata.labels.region}}'

destination:

server: '{{server}}'

namespace: my-app

4. Tekton Pipelines

4-1. Tekton이란

Tekton은 쿠버네티스 네이티브 CI/CD 프레임워크다. GitHub Actions나 Jenkins와 달리 파이프라인의 모든 구성 요소가 쿠버네티스 커스텀 리소스(CRD)로 정의된다. 각 태스크가 별도의 Pod으로 실행되므로 완전한 격리와 확장성을 제공한다.

**핵심 구성 요소:**

- **Task:** 하나 이상의 Step으로 구성된 실행 단위. Pod 하나에 매핑된다.

- **Pipeline:** 여러 Task를 연결한 DAG(방향성 비순환 그래프) 구조의 워크플로다.

- **TaskRun / PipelineRun:** Task나 Pipeline의 실행 인스턴스. 쿠버네티스 리소스로 추적 가능하다.

- **Workspace:** Task 간 데이터 공유를 위한 볼륨이다.

4-2. Task 정의

apiVersion: tekton.dev/v1

kind: Task

metadata:

name: build-and-push

spec:

params:

- name: image-url

type: string

- name: image-tag

type: string

default: latest

workspaces:

- name: source

steps:

- name: build

image: gcr.io/kaniko-project/executor:latest

args:

- --dockerfile=Dockerfile

- --context=$(workspaces.source.path)

- --destination=$(params.image-url):$(params.image-tag)

- --cache=true

- --cache-ttl=24h

4-3. Pipeline 정의

apiVersion: tekton.dev/v1

kind: Pipeline

metadata:

name: ci-pipeline

spec:

params:

- name: repo-url

type: string

- name: image-url

type: string

workspaces:

- name: shared-workspace

tasks:

- name: fetch-source

taskRef:

name: git-clone

workspaces:

- name: output

workspace: shared-workspace

params:

- name: url

value: $(params.repo-url)

- name: run-tests

taskRef:

name: npm-test

runAfter:

- fetch-source

workspaces:

- name: source

workspace: shared-workspace

- name: build-image

taskRef:

name: build-and-push

runAfter:

- run-tests

workspaces:

- name: source

workspace: shared-workspace

params:

- name: image-url

value: $(params.image-url)

- name: security-scan

taskRef:

name: trivy-scan

runAfter:

- build-image

params:

- name: image-url

value: $(params.image-url)

4-4. PipelineRun으로 실행

apiVersion: tekton.dev/v1

kind: PipelineRun

metadata:

generateName: ci-pipeline-run-

spec:

pipelineRef:

name: ci-pipeline

params:

- name: repo-url

value: https://github.com/my-org/my-app.git

- name: image-url

value: ghcr.io/my-org/my-app

workspaces:

- name: shared-workspace

volumeClaimTemplate:

spec:

accessModes:

- ReadWriteOnce

resources:

requests:

storage: 1Gi

5. 보안 파이프라인 (DevSecOps)

5-1. 보안 파이프라인의 구성 요소

프로덕션 수준의 보안 파이프라인은 다음 단계를 자동으로 수행한다.

| 단계 | 도구 | 목적 |

|------|------|------|

| SAST (정적 분석) | SonarQube, Semgrep, CodeQL | 소스 코드의 보안 취약점 탐지 |

| SCA (의존성 분석) | Snyk, Dependabot, OWASP DC | 오픈소스 의존성 취약점 탐지 |

| 시크릿 스캔 | GitLeaks, TruffleHog | 코드에 포함된 비밀 정보 탐지 |

| 컨테이너 스캔 | Trivy, Grype | 컨테이너 이미지 취약점 탐지 |

| DAST (동적 분석) | OWASP ZAP, Nuclei | 실행 중인 애플리케이션 취약점 탐지 |

| SBOM 생성 | Syft, CycloneDX | 소프트웨어 구성 요소 목록 생성 |

| 아티팩트 서명 | Cosign, Notation | 빌드 아티팩트 무결성 보장 |

5-2. SAST - SonarQube 통합

GitHub Actions에서 SonarQube 분석

name: Security Pipeline

on: [push, pull_request]

jobs:

sast:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

with:

fetch-depth: 0

- uses: SonarSource/sonarqube-scan-action@v3

env:

SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

SONAR_HOST_URL: ${{ secrets.SONAR_HOST_URL }}

with:

args: >

-Dsonar.projectKey=my-project

-Dsonar.sources=src/

-Dsonar.tests=tests/

-Dsonar.coverage.exclusions=**/*.test.ts

- uses: SonarSource/sonarqube-quality-gate-check@v1

timeout-minutes: 5

env:

SONAR_TOKEN: ${{ secrets.SONAR_TOKEN }}

5-3. 컨테이너 이미지 스캔 - Trivy

container-scan:

runs-on: ubuntu-latest

needs: [build]

steps:

- uses: aquasecurity/trivy-action@master

with:

image-ref: 'ghcr.io/my-org/my-app:latest'

format: 'sarif'

output: 'trivy-results.sarif'

severity: 'CRITICAL,HIGH'

exit-code: '1'

- uses: github/codeql-action/upload-sarif@v3

if: always()

with:

sarif_file: 'trivy-results.sarif'

Trivy는 OS 패키지와 언어별 의존성 모두를 스캔한다. `exit-code: '1'`을 설정하면 CRITICAL 또는 HIGH 취약점 발견 시 파이프라인이 실패한다.

5-4. SBOM 생성과 Cosign 서명

SBOM(Software Bill of Materials)은 소프트웨어에 포함된 모든 구성 요소의 목록이다. 미국 행정명령 14028 이후 공급망 보안의 필수 요소가 되었다.

sbom-and-sign:

runs-on: ubuntu-latest

needs: [container-scan]

permissions:

id-token: write

packages: write

steps:

- name: Generate SBOM

uses: anchore/sbom-action@v0

with:

image: ghcr.io/my-org/my-app:latest

format: spdx-json

output-file: sbom.spdx.json

- name: Install Cosign

uses: sigstore/cosign-installer@v3

- name: Sign Container Image

run: |

cosign sign --yes \

ghcr.io/my-org/my-app:latest

- name: Attach SBOM to Image

run: |

cosign attach sbom \

--sbom sbom.spdx.json \

ghcr.io/my-org/my-app:latest

Cosign은 Sigstore 프로젝트의 일부로, 키리스(keyless) 서명을 지원한다. OIDC 토큰을 사용하여 별도의 서명 키 관리 없이 이미지에 서명할 수 있다.

5-5. 시크릿 스캔 - GitLeaks

secret-scan:

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

with:

fetch-depth: 0

- uses: gitleaks/gitleaks-action@v2

env:

GITHUB_TOKEN: ${{ secrets.GITHUB_TOKEN }}

6. 테스트 자동화 전략

6-1. 테스트 피라미드

프로덕션 CI/CD에서는 테스트의 종류와 비율이 중요하다.

**유닛 테스트 (70%):** 가장 빠르고 가장 많아야 한다. 개별 함수, 메서드, 컴포넌트를 격리 테스트한다.

**통합 테스트 (20%):** 여러 모듈이 함께 동작하는 것을 검증한다. DB, API, 메시지 큐 등 외부 의존성과의 상호작용을 테스트한다.

**E2E 테스트 (10%):** 사용자 시나리오를 처음부터 끝까지 검증한다. 가장 느리고 불안정하므로 핵심 플로우만 테스트한다.

6-2. 병렬 테스트와 테스트 분할

대규모 테스트 스위트의 실행 시간을 단축하기 위한 전략이다.

jobs:

test:

strategy:

matrix:

shard: [1, 2, 3, 4]

runs-on: ubuntu-latest

steps:

- uses: actions/checkout@v4

- run: npm ci

- name: Run Tests (Shard ${{ matrix.shard }}/4)

run: |

npx jest --shard=${{ matrix.shard }}/4 \

--ci --coverage --forceExit

- uses: actions/upload-artifact@v4

with:

name: coverage-${{ matrix.shard }}

path: coverage/

merge-coverage:

needs: [test]

runs-on: ubuntu-latest

steps:

- uses: actions/download-artifact@v4

with:

pattern: coverage-*

merge-multiple: true

- name: Merge Coverage Reports

run: npx istanbul-merge --out merged-coverage.json coverage-*/coverage-final.json

6-3. Playwright E2E 테스트

e2e:

runs-on: ubuntu-latest

needs: [deploy-staging]

steps:

- uses: actions/checkout@v4

- run: npm ci

- name: Install Playwright Browsers

run: npx playwright install --with-deps

- name: Run E2E Tests

run: npx playwright test --reporter=html

env:

BASE_URL: https://staging.my-app.com

- uses: actions/upload-artifact@v4

if: failure()

with:

name: playwright-report

path: playwright-report/

7. 배포 전략 심화

7-1. Argo Rollouts 카나리 배포

Argo Rollouts는 쿠버네티스에서 고급 배포 전략을 구현하는 컨트롤러다. 표준 Deployment를 대체하는 Rollout 리소스를 제공한다.

apiVersion: argoproj.io/v1alpha1

kind: Rollout

metadata:

name: my-app

spec:

replicas: 10

strategy:

canary:

canaryService: my-app-canary

stableService: my-app-stable

trafficRouting:

istio:

virtualServices:

- name: my-app-vsvc

routes:

- primary

steps:

- setWeight: 5

- pause:

duration: 5m

- setWeight: 20

- pause:

duration: 5m

- setWeight: 50

- pause:

duration: 10m

- setWeight: 80

- pause:

duration: 5m

analysis:

templates:

- templateName: success-rate

startingStep: 2

args:

- name: service-name

value: my-app-canary

selector:

matchLabels:

app: my-app

template:

metadata:

labels:

app: my-app

spec:

containers:

- name: my-app

image: ghcr.io/my-org/my-app:v2.0.0

ports:

- containerPort: 8080

7-2. AnalysisTemplate - 메트릭 기반 자동 판단

카나리 배포 중 프로메테우스 메트릭을 조회하여 자동으로 승격(promote) 또는 롤백(abort)을 결정한다.

apiVersion: argoproj.io/v1alpha1

kind: AnalysisTemplate

metadata:

name: success-rate

spec:

args:

- name: service-name

metrics:

- name: success-rate

interval: 60s

successCondition: result[0] >= 0.95

failureLimit: 3

provider:

prometheus:

address: http://prometheus.monitoring:9090

query: |

sum(rate(http_requests_total{

service="{{args.service-name}}",

status=~"2.."

}[5m])) /

sum(rate(http_requests_total{

service="{{args.service-name}}"

}[5m]))

성공률이 95% 미만인 분석이 3번 연속 발생하면 자동으로 롤백한다. 이것이 Level 5 자가 치유 파이프라인의 핵심이다.

7-3. 블루-그린 배포

apiVersion: argoproj.io/v1alpha1

kind: Rollout

metadata:

name: my-app-bluegreen

spec:

replicas: 5

strategy:

blueGreen:

activeService: my-app-active

previewService: my-app-preview

autoPromotionEnabled: false

prePromotionAnalysis:

templates:

- templateName: smoke-test

postPromotionAnalysis:

templates:

- templateName: success-rate

scaleDownDelaySeconds: 300

selector:

matchLabels:

app: my-app

template:

metadata:

labels:

app: my-app

spec:

containers:

- name: my-app

image: ghcr.io/my-org/my-app:v2.0.0

블루-그린 배포에서는 새 버전(그린)이 완전히 준비된 후 트래픽을 한 번에 전환한다. `prePromotionAnalysis`로 전환 전 스모크 테스트를 실행하고, `scaleDownDelaySeconds`로 구버전을 일정 시간 유지하여 빠른 롤백을 가능하게 한다.

7-4. 트래픽 미러링 (Shadow Traffic)

실제 프로덕션 트래픽을 새 버전에 복제하여 실제 부하로 테스트하되, 새 버전의 응답은 사용자에게 전달하지 않는 방식이다.

apiVersion: networking.istio.io/v1beta1

kind: VirtualService

metadata:

name: my-app

spec:

hosts:

- my-app.example.com

http:

- route:

- destination:

host: my-app-stable

port:

number: 80

mirror:

host: my-app-canary

port:

number: 80

mirrorPercentage:

value: 100.0

8. 멀티 환경 관리

8-1. 환경 구조 설계

프로덕션 파이프라인은 최소 3개 환경을 운영한다.

- **dev:** 개발자의 feature 브랜치 배포. 불안정해도 괜찮다.

- **staging:** main 브랜치 배포. 프로덕션과 동일한 설정이어야 한다.

- **production:** 실제 사용자 트래픽을 처리하는 환경이다.

8-2. Kustomize Overlays

Kustomize는 쿠버네티스 매니페스트를 환경별로 커스터마이징하는 도구다. 기본(base) 설정 위에 환경별 오버레이를 적용한다.

k8s/

base/

deployment.yaml

service.yaml

kustomization.yaml

overlays/

dev/

kustomization.yaml

replica-patch.yaml

staging/

kustomization.yaml

replica-patch.yaml

production/

kustomization.yaml

replica-patch.yaml

hpa.yaml

k8s/base/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1

kind: Kustomization

resources:

- deployment.yaml

- service.yaml

k8s/overlays/production/kustomization.yaml

apiVersion: kustomize.config.k8s.io/v1beta1

kind: Kustomization

resources:

- ../../base

- hpa.yaml

patches:

- path: replica-patch.yaml

namePrefix: prod-

commonLabels:

env: production

k8s/overlays/production/replica-patch.yaml

apiVersion: apps/v1

kind: Deployment

metadata:

name: my-app

spec:

replicas: 5

template:

spec:

containers:

- name: my-app

resources:

requests:

cpu: 500m

memory: 512Mi

limits:

cpu: 1000m

memory: 1Gi

8-3. Helm Values 환경별 관리

values-dev.yaml

replicaCount: 1

image:

tag: latest

resources:

requests:

cpu: 100m

memory: 128Mi

ingress:

host: dev.my-app.internal

autoscaling:

enabled: false

values-production.yaml

replicaCount: 5

image:

tag: v2.0.0

resources:

requests:

cpu: 500m

memory: 512Mi

limits:

cpu: 1000m

memory: 1Gi

ingress:

host: my-app.example.com

tls: true

autoscaling:

enabled: true

minReplicas: 5

maxReplicas: 20

targetCPU: 70

환경별 배포

helm upgrade --install my-app ./chart \

-f values-production.yaml \

--namespace production \

--wait --timeout 5m

9. 모니터링과 롤백

9-1. 배포 후 모니터링 체크리스트

배포 직후 확인해야 하는 핵심 메트릭이다.

**즉시 확인 (0~5분):**

- Pod 상태: 모든 Pod가 Running/Ready 상태인가

- 에러 로그: 새 버전에서 예외가 급증하지 않았는가

- 헬스체크: readiness/liveness 프로브가 정상인가

**단기 확인 (5~30분):**

- 응답 시간: p50, p95, p99 레이턴시가 이전 버전과 유사한가

- 에러율: 5xx 비율이 임계치 이내인가

- 처리량: 요청 처리량이 예상 범위인가

**중기 확인 (30분~수 시간):**

- 메모리 사용량: 메모리 누수 징후가 없는가

- CPU 사용량: CPU 사용이 안정적인가

- 비즈니스 메트릭: 주문 수, 전환율 등이 정상인가

9-2. 프로메테우스 기반 자동 롤백

PrometheusRule - 자동 롤백 트리거

apiVersion: monitoring.coreos.com/v1

kind: PrometheusRule

metadata:

name: deployment-rollback-rules

spec:

groups:

- name: deployment-health

rules:

- alert: HighErrorRate

expr: |

sum(rate(http_requests_total{status=~"5.."}[5m]))

/

sum(rate(http_requests_total[5m]))

> 0.05

for: 2m

labels:

severity: critical

action: rollback

annotations:

summary: "Error rate above 5 percent for 2 minutes"

- alert: HighLatency

expr: |

histogram_quantile(0.99,

sum(rate(http_request_duration_seconds_bucket[5m])) by (le)

) > 2

for: 3m

labels:

severity: critical

action: rollback

annotations:

summary: "p99 latency above 2 seconds for 3 minutes"

9-3. SLO 기반 배포 게이트

서비스 수준 목표(SLO)를 배포 결정의 기준으로 활용한다. 에러 버짓이 소진되면 배포를 중단하는 전략이다.

SLO 정의 예시

apiVersion: sloth.slok.dev/v1

kind: PrometheusServiceLevel

metadata:

name: my-app-slo

spec:

service: my-app

labels:

team: platform

slos:

- name: requests-availability

objective: 99.9

sli:

events:

errorQuery: sum(rate(http_requests_total{status=~"5.."}[5m]))

totalQuery: sum(rate(http_requests_total[5m]))

alerting:

name: MyAppAvailability

pageAlert:

labels:

severity: critical

ticketAlert:

labels:

severity: warning

에러 버짓 계산 방식은 다음과 같다. SLO가 99.9%라면 한 달에 약 43분의 다운타임이 허용된다. 이미 30분을 소진했다면 남은 13분의 에러 버짓으로는 위험한 배포를 진행하지 않는다.

10. 실전: 프로덕션 파이프라인 아키텍처

10-1. 전체 아키텍처

프로덕션 수준의 완전한 CI/CD 파이프라인은 다음과 같은 구조를 가진다.

개발자 코드 Push

|

v

[CI 단계 - GitHub Actions]

|-- 코드 체크아웃

|-- 의존성 설치 (캐시 활용)

|-- 린트 + 포맷 체크

|-- 유닛 테스트 (병렬 4 샤드)

|-- 통합 테스트

|-- SAST (SonarQube)

|-- 시크릿 스캔 (GitLeaks)

|-- 의존성 취약점 스캔 (Snyk)

|-- 컨테이너 빌드 (Kaniko)

|-- 컨테이너 스캔 (Trivy)

|-- SBOM 생성 (Syft)

|-- 이미지 서명 (Cosign)

|-- 이미지 레지스트리 Push

|

v

[CD 단계 - ArgoCD / GitOps]

|-- 매니페스트 저장소 자동 업데이트

|-- ArgoCD 동기화

|-- dev 환경 자동 배포

|-- staging 환경 자동 배포

|-- E2E 테스트 (Playwright)

|-- DAST (OWASP ZAP)

|

v

[프로덕션 배포 - Argo Rollouts]

|-- 카나리 5% 배포

|-- 메트릭 분석 (AnalysisTemplate)

|-- 카나리 20% 증가

|-- 메트릭 재분석

|-- 카나리 50% 증가

|-- 최종 분석

|-- 100% 프로모션 또는 자동 롤백

|

v

[모니터링 - Prometheus / Grafana]

|-- SLO 대시보드

|-- 에러 버짓 추적

|-- 자동 롤백 알림

10-2. 파이프라인 최적화 팁

**캐시 전략:** 의존성 설치, Docker 레이어, 테스트 결과를 캐시하여 파이프라인 시간을 50% 이상 단축할 수 있다.

- uses: actions/cache@v4

with:

path: |

~/.npm

node_modules

key: deps-${{ hashFiles('**/package-lock.json') }}

restore-keys: |

deps-

**조건부 실행:** 변경된 파일에 따라 관련 작업만 실행하여 불필요한 빌드를 방지한다.

- uses: dorny/paths-filter@v3

id: changes

with:

filters: |

backend:

- 'src/api/**'

- 'src/models/**'

frontend:

- 'src/components/**'

- 'src/pages/**'

infra:

- 'terraform/**'

- 'k8s/**'

**병렬화:** 독립적인 작업은 병렬로 실행한다. 린트, 테스트, 보안 스캔은 서로 의존하지 않으므로 동시에 실행 가능하다.

10-3. 파이프라인 메트릭

파이프라인 자체의 성능도 측정해야 한다.

| 메트릭 | 설명 | 목표 |

|--------|------|------|

| Lead Time | 커밋부터 프로덕션 배포까지 시간 | 1시간 이하 |

| 배포 빈도 | 하루 프로덕션 배포 횟수 | 일 10회 이상 |

| 변경 실패율 | 배포 후 롤백 비율 | 5% 이하 |

| MTTR | 장애 발생 후 복구 시간 | 30분 이하 |

| 파이프라인 실행 시간 | CI 전체 소요 시간 | 15분 이하 |

| 테스트 커버리지 | 코드 커버리지 비율 | 80% 이상 |

이것이 DORA 메트릭(Lead Time, 배포 빈도, 변경 실패율, MTTR)의 핵심이다. Elite 수준의 팀은 이 네 가지 메트릭 모두에서 최고 등급을 달성한다.

마무리

CI/CD 파이프라인은 단순한 자동화 도구가 아니라, 소프트웨어 품질과 개발 속도를 결정하는 핵심 인프라다. 이 글에서 다룬 내용을 요약하면 다음과 같다.

1. **성숙도 모델을 기준으로 현재 수준을 파악하라.** 한 번에 Level 5를 목표로 하지 말고, 단계적으로 역량을 구축하라.

2. **재사용 가능한 파이프라인을 설계하라.** GitHub Actions의 재사용 워크플로와 Composite Actions를 활용하여 조직 전체의 파이프라인을 표준화하라.

3. **GitOps를 도입하라.** ArgoCD와 같은 도구로 선언적 배포를 구현하면 감사 추적, 자동 복구, 일관성을 모두 확보할 수 있다.

4. **보안을 파이프라인에 내장하라.** DevSecOps는 별도의 단계가 아니라 파이프라인의 모든 단계에 보안이 녹아드는 것이다.

5. **메트릭 기반으로 의사결정하라.** SLO와 에러 버짓을 활용하여 배포 리스크를 정량적으로 관리하라.

6. **DORA 메트릭을 추적하라.** 파이프라인의 성능 자체를 지속적으로 개선하라.

프로덕션 수준의 CI/CD는 하루아침에 완성되지 않는다. 하지만 각 구성 요소를 이해하고 단계적으로 도입한다면, 팀의 배포 역량은 확실히 달라질 것이다.

현재 단락 (1/816)

CI/CD를 "코드 푸시하면 자동으로 배포되는 것" 정도로 이해하는 단계를 넘어, 프로덕션 수준의 파이프라인이 무엇인지 고민해 본 적이 있는가? 실제 프로덕션 환경에서는 보안 스캔...

작성 글자: 0원문 글자: 18,047작성 단락: 0/816