Split View: CI/CD 파이프라인 심화 가이드 2025: 배포 전략, GitOps, 모노레포, 보안 파이프라인
CI/CD 파이프라인 심화 가이드 2025: 배포 전략, GitOps, 모노레포, 보안 파이프라인
- 도입
- 1. 배포 전략 (Deployment Strategies)
- 2. GitOps
- 3. 모노레포 CI (Monorepo CI)
- 4. Feature Flags (피처 플래그)
- 5. 환경 관리 (Environment Management)
- 6. 파이프라인 보안 (Pipeline Security)
- 7. 롤백 전략 (Rollback Strategies)
- 8. 파이프라인 성능 최적화
- 9. 릴리스 관리 (Release Management)
- 10. 멀티 클라우드 배포
- 11. 실전 퀴즈
- 12. CI/CD 성숙도 체크리스트
- 13. 참고 자료
도입
2024년, DORA(DevOps Research and Assessment) 보고서에 따르면, 엘리트 팀은 하루에 여러 번 배포하고 변경 실패율은 5% 미만입니다. 반면 저성과 팀은 한 달에 한 번 배포하며, 복구에 수 주가 걸립니다. 이 격차의 핵심은 바로 CI/CD 파이프라인의 성숙도에 있습니다.
단순한 빌드-테스트-배포를 넘어서, 현대적 CI/CD는 배포 전략(Blue-Green, Canary), GitOps, 모노레포 최적화, 피처 플래그, 보안 파이프라인까지 아우릅니다. 이 가이드는 2025년 현재 프로덕션 환경에서 검증된 심화 CI/CD 전략을 체계적으로 다룹니다.
1. 배포 전략 (Deployment Strategies)
1.1 Rolling Update
가장 기본적인 배포 방식으로, 인스턴스를 순차적으로 교체합니다.
시간 →
인스턴스 1: [v1] [v1] [v2] [v2] [v2]
인스턴스 2: [v1] [v1] [v1] [v2] [v2]
인스턴스 3: [v1] [v1] [v1] [v1] [v2]
트래픽: 100% v1 → 혼합 → 100% v2
# Kubernetes Rolling Update
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # 최대 1개 추가 Pod
maxUnavailable: 0 # 다운타임 0
template:
spec:
containers:
- name: api
image: myapp:v2
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
장점: 간단, 추가 리소스 최소, 점진적 교체 단점: 배포 중 v1/v2 혼합 트래픽, 즉시 롤백 어려움
1.2 Blue-Green Deployment
두 개의 동일한 환경(Blue/Green)을 유지하고, 트래픽을 한 번에 전환합니다.
┌─────────────────────────────────────────────┐
│ │
│ Load Balancer │
│ │ │
│ ▼ (전환 전: Blue로 트래픽) │
│ ┌───────────┐ ┌───────────┐ │
│ │ Blue │ │ Green │ │
│ │ (v1) │ │ (v2) │ │
│ │ Active │ │ Standby │ │
│ └───────────┘ └───────────┘ │
│ │
│ 전환 후: Green으로 100% 트래픽 전환 │
│ │
│ ┌───────────┐ ┌───────────┐ │
│ │ Blue │ │ Green │ │
│ │ (v1) │ │ (v2) │ │
│ │ Standby │ │ Active │ │
│ └───────────┘ └───────────┘ │
└─────────────────────────────────────────────┘
# AWS ALB를 이용한 Blue-Green (GitHub Actions)
name: Blue-Green Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build and Push Docker Image
run: |
docker build -t myapp:${{ github.sha }} .
docker push myregistry/myapp:${{ github.sha }}
- name: Deploy to Green Environment
run: |
aws ecs update-service \
--cluster production \
--service green-service \
--task-definition myapp:${{ github.sha }}
- name: Run Smoke Tests on Green
run: |
./scripts/smoke-test.sh https://green.myapp.com
- name: Switch Traffic to Green
run: |
aws elbv2 modify-listener \
--listener-arn ${{ secrets.ALB_LISTENER_ARN }} \
--default-actions \
Type=forward,TargetGroupArn=${{ secrets.GREEN_TG_ARN }}
장점: 즉시 롤백 가능 (Blue로 트래픽 전환), 다운타임 없음 단점: 2배의 인프라 비용, 데이터베이스 마이그레이션 복잡
1.3 Canary Deployment
소수의 트래픽에만 새 버전을 먼저 배포하여 검증합니다.
Phase 1: 5% 트래픽을 Canary(v2)로
┌──────────────────────────────┐
│ v1 v1 v1 v1 v1 v1 v1 v1 v1 │ 95%
│ v2 │ 5%
└──────────────────────────────┘
Phase 2: 검증 후 25%로 확대
┌──────────────────────────────┐
│ v1 v1 v1 v1 v1 v1 v1 │ 75%
│ v2 v2 v2 │ 25%
└──────────────────────────────┘
Phase 3: 안정 확인 후 100%
┌──────────────────────────────┐
│ v2 v2 v2 v2 v2 v2 v2 v2 v2 │ 100%
└──────────────────────────────┘
# Istio를 이용한 Canary Deployment
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: myapp
spec:
hosts:
- myapp.example.com
http:
- route:
- destination:
host: myapp
subset: stable
weight: 95
- destination:
host: myapp
subset: canary
weight: 5
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: myapp
spec:
host: myapp
subsets:
- name: stable
labels:
version: v1
- name: canary
labels:
version: v2
장점: 리스크 최소화, 실제 트래픽으로 검증, 점진적 롤아웃 단점: 구현 복잡성, 메트릭 기반 자동화 필요
1.4 배포 전략 비교
| 전략 | 다운타임 | 롤백 속도 | 비용 | 복잡도 | 적합 시나리오 |
|---|---|---|---|---|---|
| Rolling | 없음 | 느림 | 낮음 | 낮음 | 일반 서비스 |
| Blue-Green | 없음 | 즉시 | 높음 (2배) | 중간 | 중요 서비스 |
| Canary | 없음 | 빠름 | 중간 | 높음 | 대규모 트래픽 |
| A/B Testing | 없음 | 빠름 | 중간 | 매우 높음 | 기능 실험 |
2. GitOps
2.1 GitOps 원칙
┌──────────────────────────────────────────────────────┐
│ GitOps 원칙 │
│ │
│ 1. 선언적 (Declarative) │
│ - 시스템 상태를 코드로 선언 │
│ │
│ 2. 버전 관리 (Versioned) │
│ - Git이 단일 진실의 원천(SSOT) │
│ │
│ 3. 자동 적용 (Automated) │
│ - 승인된 변경은 자동으로 시스템에 반영 │
│ │
│ 4. 자가 치유 (Self-healing) │
│ - 실제 상태와 원하는 상태의 차이를 자동 수정 │
└──────────────────────────────────────────────────────┘
2.2 ArgoCD 설정
# argocd-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp-production
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/k8s-manifests.git
targetRevision: main
path: apps/myapp/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true # 불필요한 리소스 정리
selfHeal: true # 수동 변경 자동 복구
allowEmpty: false
syncOptions:
- CreateNamespace=true
- PrunePropagationPolicy=foreground
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
2.3 ArgoCD App-of-Apps 패턴
# root-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: root-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/k8s-manifests.git
targetRevision: main
path: apps
destination:
server: https://kubernetes.default.svc
# apps/ 디렉토리 구조
# apps/
# myapp/
# application.yaml
# api-gateway/
# application.yaml
# monitoring/
# application.yaml
# cert-manager/
# application.yaml
2.4 ArgoCD vs Flux 비교
| 기능 | ArgoCD | Flux v2 |
|---|---|---|
| UI 대시보드 | 내장 웹 UI | Weave GitOps (별도) |
| 멀티 클러스터 | 지원 | 지원 |
| Helm 지원 | 네이티브 | HelmRelease CRD |
| Kustomize 지원 | 네이티브 | 네이티브 |
| 이미지 자동 업데이트 | ArgoCD Image Updater | 내장 |
| 알림 | ArgoCD Notifications | Notification Controller |
| RBAC | 내장 | Kubernetes RBAC 사용 |
| 접근 방식 | Pull 기반 | Pull 기반 |
| 학습 곡선 | 중간 | 중간-높음 |
2.5 ArgoCD 알림 설정
# argocd-notifications-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
namespace: argocd
data:
service.slack: |
token: $slack-token
trigger.on-sync-succeeded: |
- when: app.status.sync.status == 'Synced'
send: [app-sync-succeeded]
trigger.on-sync-failed: |
- when: app.status.sync.status == 'Unknown'
send: [app-sync-failed]
template.app-sync-succeeded: |
slack:
attachments: |
[{
"color": "#18be52",
"title": "{{.app.metadata.name}} 동기화 성공",
"text": "배포 완료: {{.app.spec.source.targetRevision}}"
}]
template.app-sync-failed: |
slack:
attachments: |
[{
"color": "#E96D76",
"title": "{{.app.metadata.name}} 동기화 실패",
"text": "오류: {{.app.status.conditions}}"
}]
3. 모노레포 CI (Monorepo CI)
3.1 모노레포 구조
monorepo/
apps/
web/ # Next.js 프론트엔드
api/ # Express 백엔드
mobile/ # React Native 앱
packages/
ui/ # 공유 UI 컴포넌트
utils/ # 공유 유틸리티
config/ # 공유 설정
turbo.json # Turborepo 설정
nx.json # 또는 Nx 설정
package.json
3.2 Turborepo 설정
{
"globalDependencies": ["**/.env.*local"],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**"],
"cache": true
},
"test": {
"dependsOn": ["build"],
"outputs": [],
"cache": true
},
"lint": {
"outputs": [],
"cache": true
},
"deploy": {
"dependsOn": ["build", "test", "lint"],
"cache": false
}
}
}
3.3 Nx 변경 감지 기반 빌드
# .github/workflows/monorepo-ci.yml
name: Monorepo CI
on:
pull_request:
branches: [main]
jobs:
affected:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # 전체 히스토리 필요
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
# 변경된 프로젝트만 빌드/테스트
- name: Lint affected
run: npx nx affected --target=lint --base=origin/main
- name: Test affected
run: npx nx affected --target=test --base=origin/main
- name: Build affected
run: npx nx affected --target=build --base=origin/main
# Remote Caching (Nx Cloud 또는 Turborepo Remote Cache)
remote-cache:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- name: Build with remote cache
run: npx turbo build --team=myteam --token=${{ secrets.TURBO_TOKEN }}
env:
TURBO_TEAM: myteam
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
3.4 Turborepo vs Nx vs Bazel 비교
| 기능 | Turborepo | Nx | Bazel |
|---|---|---|---|
| 학습 곡선 | 낮음 | 중간 | 높음 |
| 언어 지원 | JS/TS | JS/TS, Go, Rust 등 | 다중 언어 |
| 변경 감지 | 파일 해시 | 프로젝트 그래프 | 의존성 그래프 |
| 원격 캐싱 | Vercel RC | Nx Cloud | Remote Execution |
| 설정 복잡도 | 매우 간단 | 중간 | 복잡 |
| 대규모 적합성 | 중규모 | 대규모 | 초대규모 |
| 코드 생성 | 없음 | 내장 Generator | Rules |
4. Feature Flags (피처 플래그)
4.1 피처 플래그의 유형
┌──────────────────────────────────────────────────┐
│ Feature Flag 유형 │
├──────────────────────────────────────────────────┤
│ │
│ 1. Release Flag (릴리스 플래그) │
│ - 미완성 기능을 숨기고 배포 │
│ - 수명: 짧음 (며칠 ~ 몇 주) │
│ │
│ 2. Experiment Flag (실험 플래그) │
│ - A/B 테스트, 기능 비교 │
│ - 수명: 중간 (몇 주 ~ 몇 달) │
│ │
│ 3. Ops Flag (운영 플래그) │
│ - 시스템 동작 제어 (킬 스위치) │
│ - 수명: 영구적 │
│ │
│ 4. Permission Flag (권한 플래그) │
│ - 사용자/조직별 기능 접근 제어 │
│ - 수명: 영구적 │
└──────────────────────────────────────────────────┘
4.2 구현 예제
// featureFlags.ts
import { UnleashClient } from 'unleash-proxy-client';
const unleash = new UnleashClient({
url: 'https://unleash.myapp.com/api/frontend',
clientKey: process.env.UNLEASH_CLIENT_KEY!,
appName: 'myapp-frontend',
refreshInterval: 15,
});
unleash.start();
// React Hook
export function useFeatureFlag(flagName: string): boolean {
const [enabled, setEnabled] = useState(false);
useEffect(() => {
setEnabled(unleash.isEnabled(flagName));
const handler = () => {
setEnabled(unleash.isEnabled(flagName));
};
unleash.on('update', handler);
return () => unleash.off('update', handler);
}, [flagName]);
return enabled;
}
// 컴포넌트에서 사용
function CheckoutPage() {
const newCheckoutEnabled = useFeatureFlag('new-checkout-flow');
if (newCheckoutEnabled) {
return <NewCheckoutFlow />;
}
return <LegacyCheckoutFlow />;
}
4.3 Progressive Rollout (점진적 롤아웃)
// 서버 사이드 피처 플래그 (LaunchDarkly 스타일)
import LaunchDarkly from 'launchdarkly-node-server-sdk';
const client = LaunchDarkly.init(process.env.LD_SDK_KEY!);
async function getFeatureValue(
flagKey: string,
user: LDUser,
defaultValue: boolean
): Promise<boolean> {
await client.waitForInitialization();
return client.variation(flagKey, user, defaultValue);
}
// 점진적 롤아웃 설정 (LaunchDarkly 대시보드 설정과 동일)
// Phase 1: 내부 직원만 (beta-testers 그룹)
// Phase 2: 5% 사용자
// Phase 3: 25% 사용자
// Phase 4: 50% 사용자
// Phase 5: 100% 사용자
// 킬 스위치 패턴
async function processPayment(order: Order) {
const newPaymentEnabled = await getFeatureValue(
'new-payment-gateway',
{ key: order.userId },
false // 기본값: 비활성화
);
if (newPaymentEnabled) {
return newPaymentGateway.process(order);
}
return legacyPaymentGateway.process(order);
}
4.4 LaunchDarkly vs Unleash vs Flagsmith
| 기능 | LaunchDarkly | Unleash | Flagsmith |
|---|---|---|---|
| 가격 | 유료 (비쌈) | 오픈소스 + 엔터프라이즈 | 오픈소스 + 클라우드 |
| 타겟팅 | 매우 정교 | 기본 | 정교 |
| A/B 테스트 | 내장 | 별도 | 내장 |
| SDK 지원 | 25+ 언어 | 15+ 언어 | 15+ 언어 |
| 셀프호스팅 | 불가 | 가능 | 가능 |
| 감사 로그 | 지원 | 지원 | 지원 |
5. 환경 관리 (Environment Management)
5.1 환경 계층 구조
┌─────────────────────────────────────────┐
│ Production (프로덕션) │
│ - 실제 사용자 트래픽 │
│ - 최고 수준의 모니터링 │
│ - 변경 시 승인 프로세스 │
├─────────────────────────────────────────┤
│ Staging (스테이징) │
│ - 프로덕션과 동일한 구성 │
│ - QA 팀 테스트 │
│ - 통합 테스트 실행 │
├─────────────────────────────────────────┤
│ Development (개발) │
│ - 최신 기능 통합 │
│ - 자동 배포 (main 브랜치) │
├─────────────────────────────────────────┤
│ PR Preview (PR별 미리보기) │
│ - PR마다 독립 환경 생성 │
│ - PR 닫히면 자동 삭제 │
└─────────────────────────────────────────┘
5.2 Ephemeral Environments (임시 환경)
# .github/workflows/preview.yml
name: PR Preview Environment
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
deploy-preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy Preview
run: |
PREVIEW_URL="pr-${{ github.event.number }}.preview.myapp.com"
helm upgrade --install \
pr-${{ github.event.number }} \
./charts/myapp \
--namespace previews \
--set image.tag=${{ github.sha }} \
--set ingress.host=$PREVIEW_URL \
--set resources.requests.memory=256Mi \
--set resources.requests.cpu=100m
- name: Comment PR with URL
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `Preview deployed: https://pr-${context.issue.number}.preview.myapp.com`
})
cleanup-preview:
if: github.event.action == 'closed'
runs-on: ubuntu-latest
steps:
- name: Delete Preview
run: |
helm uninstall pr-${{ github.event.number }} \
--namespace previews
6. 파이프라인 보안 (Pipeline Security)
6.1 Secrets 관리
# GitHub Actions - OIDC를 이용한 AWS 인증 (비밀키 없이)
name: Secure Deploy
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# OIDC 기반 AWS 인증 (장기 비밀키 불필요)
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions-role
aws-region: ap-northeast-2
# 시크릿 스캔
- name: Scan for secrets
uses: trufflesecurity/trufflehog@v3
with:
path: ./
extra_args: --only-verified
# 컨테이너 이미지 스캔
- name: Scan container image
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:${{ github.sha }}
severity: 'CRITICAL,HIGH'
exit-code: '1'
6.2 SLSA (Supply-chain Levels for Software Artifacts)
# SLSA Level 3 - 서명된 빌드 + 출처 증명
name: SLSA Build
jobs:
build:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
attestations: write
steps:
- uses: actions/checkout@v4
- name: Build
run: npm run build
# Sigstore를 이용한 아티팩트 서명
- name: Sign artifact
uses: sigstore/cosign-installer@v3
- name: Sign container image
run: |
cosign sign \
--yes \
myregistry/myapp:${{ github.sha }}
# SLSA 출처 증명 생성
- name: Generate SLSA provenance
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.0.0
with:
image: myregistry/myapp
digest: ${{ steps.build.outputs.digest }}
6.3 보안 스캔 파이프라인
# .github/workflows/security.yml
name: Security Pipeline
on:
pull_request:
branches: [main]
schedule:
- cron: '0 6 * * 1' # 매주 월요일 06:00
jobs:
sast:
name: Static Analysis
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Semgrep
uses: semgrep/semgrep-action@v1
with:
config: p/owasp-top-ten
dependency-check:
name: Dependency Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm audit --audit-level=high
- name: Snyk Test
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
container-scan:
name: Container Security
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t myapp:scan .
- name: Trivy scan
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:scan
severity: 'CRITICAL,HIGH'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
iac-scan:
name: Infrastructure as Code Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Checkov scan
uses: bridgecrewio/checkov-action@master
with:
directory: ./terraform
framework: terraform
7. 롤백 전략 (Rollback Strategies)
7.1 즉시 롤백
# Kubernetes 롤백
# 마지막 성공 버전으로 즉시 롤백
# kubectl rollout undo deployment/myapp
# GitHub Actions 자동 롤백
name: Deploy with Auto-Rollback
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy new version
id: deploy
run: |
kubectl set image deployment/myapp \
myapp=myregistry/myapp:${{ github.sha }}
kubectl rollout status deployment/myapp --timeout=300s
- name: Run post-deploy checks
id: healthcheck
run: |
for i in $(seq 1 10); do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://myapp.com/health)
if [ "$STATUS" != "200" ]; then
echo "Health check failed: $STATUS"
exit 1
fi
sleep 5
done
- name: Rollback on failure
if: failure()
run: |
echo "Rolling back to previous version..."
kubectl rollout undo deployment/myapp
kubectl rollout status deployment/myapp --timeout=300s
7.2 데이터베이스 인식 롤백
배포 과정에서 DB 스키마 변경이 있는 경우:
1. Forward-Compatible 마이그레이션 (안전)
┌─────────────────────────────────────┐
│ Step 1: DB에 새 컬럼 추가 (nullable)│
│ Step 2: 앱 v2 배포 (두 컬럼 모두 사용)│
│ Step 3: 데이터 마이그레이션 │
│ Step 4: 이전 컬럼 제거 │
└─────────────────────────────────────┘
2. Expand-Contract 패턴
Phase 1 (Expand): 새 스키마 추가, 기존 유지
Phase 2 (Migrate): 데이터 이전
Phase 3 (Contract): 이전 스키마 제거
7.3 Forward-Fix vs Rollback 결정 기준
| 상황 | 권장 전략 | 이유 |
|---|---|---|
| 단순 버그 수정 | Forward-Fix | 롤백보다 수정이 빠름 |
| 심각한 장애 | 즉시 롤백 | 서비스 복구가 최우선 |
| DB 마이그레이션 포함 | Forward-Fix | 롤백 시 데이터 손실 위험 |
| 성능 저하 | 카나리 롤백 | 영향 범위 파악 후 결정 |
8. 파이프라인 성능 최적화
8.1 캐싱 전략
# .github/workflows/optimized-ci.yml
name: Optimized CI
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Node.js 의존성 캐싱
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
# Docker 레이어 캐싱
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v6
with:
context: .
push: true
tags: myapp:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Turborepo 원격 캐싱
- name: Build with cache
run: npx turbo build --cache-dir=.turbo
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: myteam
8.2 병렬화 전략
# 병렬 잡 실행
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run lint
unit-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run test:unit
type-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run type-check
# 모든 검증 통과 후 빌드
build:
needs: [lint, unit-test, type-check]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run build
8.3 Self-Hosted Runners
# 자체 호스팅 러너 (ARM64 Mac 등)
jobs:
build-ios:
runs-on: [self-hosted, macOS, ARM64]
steps:
- uses: actions/checkout@v4
- name: Build iOS
run: xcodebuild -workspace MyApp.xcworkspace ...
build-android:
runs-on: [self-hosted, Linux, X64]
steps:
- uses: actions/checkout@v4
- name: Build Android
run: ./gradlew assembleRelease
9. 릴리스 관리 (Release Management)
9.1 Semantic Versioning
MAJOR.MINOR.PATCH (예: 2.1.3)
MAJOR: 호환되지 않는 API 변경
MINOR: 하위 호환 기능 추가
PATCH: 하위 호환 버그 수정
예시:
1.0.0 → 1.0.1 (버그 수정)
1.0.1 → 1.1.0 (새 기능 추가)
1.1.0 → 2.0.0 (Breaking Change)
9.2 자동 릴리스 노트
# .github/workflows/release.yml
name: Release
on:
push:
tags: ['v*']
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate Changelog
id: changelog
uses: orhun/git-cliff-action@v3
with:
config: cliff.toml
- name: Create Release
uses: softprops/action-gh-release@v2
with:
body: ${{ steps.changelog.outputs.content }}
draft: false
prerelease: false
9.3 Conventional Commits
# 커밋 메시지 형식
# type(scope): description
feat(auth): add OAuth2.0 login support
fix(cart): resolve quantity update race condition
docs(api): update REST API documentation
chore(deps): upgrade express to v5.0
perf(db): optimize query for order listing
refactor(payment): extract payment strategy pattern
test(checkout): add E2E tests for checkout flow
# Breaking Change 표기
feat(api)!: change response format for /orders endpoint
BREAKING CHANGE: The orders endpoint now returns
paginated responses instead of a flat array.
9.4 Release Train 모델
┌─────────────────────────────────────────────┐
│ Release Train (격주 릴리스) │
│ │
│ Week 1: 기능 개발 + 코드 동결(Code Freeze) │
│ Week 2: QA + 버그 수정 + 릴리스 │
│ │
│ ──┬──────┬──────┬──────┬──────┬── │
│ v2.1 v2.2 v2.3 v2.4 v2.5 │
│ │
│ 핫픽스는 별도 브랜치에서 즉시 배포 │
└─────────────────────────────────────────────┘
10. 멀티 클라우드 배포
10.1 Terraform을 이용한 멀티 클라우드
# main.tf - 멀티 클라우드 프로바이더
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
}
}
# AWS 배포
resource "aws_ecs_service" "primary" {
name = "myapp-primary"
cluster = aws_ecs_cluster.main.id
task_definition = aws_ecs_task_definition.app.arn
desired_count = 3
load_balancer {
target_group_arn = aws_lb_target_group.app.arn
container_name = "myapp"
container_port = 8080
}
}
# GCP 배포 (DR)
resource "google_cloud_run_service" "failover" {
name = "myapp-failover"
location = "asia-northeast3"
template {
spec {
containers {
image = "gcr.io/myproject/myapp:latest"
}
}
}
}
11. 실전 퀴즈
Q1: Blue-Green 배포의 가장 큰 장점은?
A) 인프라 비용이 저렴하다 B) 즉시 롤백이 가능하다 C) 구현이 간단하다 D) 트래픽 분할이 가능하다
정답: B
Blue-Green 배포는 두 개의 동일한 환경을 유지하므로, 문제 발생 시 로드밸런서의 트래픽을 이전 환경(Blue)으로 즉시 전환하여 롤백할 수 있습니다. 다만 2배의 인프라 비용이 단점입니다.
Q2: GitOps에서 Git 저장소의 역할은?
A) 코드 백업 저장소 B) CI/CD 파이프라인 실행기 C) 인프라의 단일 진실의 원천(SSOT) D) 모니터링 대시보드
정답: C
GitOps에서 Git 저장소는 인프라와 애플리케이션 상태의 단일 진실의 원천(Single Source of Truth)입니다. 모든 변경은 Git을 통해 이루어지며, ArgoCD/Flux 같은 도구가 Git 상태와 실제 클러스터 상태를 동기화합니다.
Q3: 모노레포 CI에서 "affected" 빌드의 장점은?
A) 모든 프로젝트를 항상 빌드한다 B) 변경된 프로젝트와 영향받는 프로젝트만 빌드하여 시간을 절약한다 C) 빌드 캐시를 무시한다 D) 테스트를 건너뛴다
정답: B
"affected" 빌드는 Git diff를 분석하여 변경된 프로젝트와 그에 의존하는 프로젝트만 선택적으로 빌드/테스트합니다. 이를 통해 대규모 모노레포에서 CI 시간을 크게 단축할 수 있습니다.
Q4: Feature Flag의 "킬 스위치" 용도는?
A) 서버를 종료한다 B) 문제가 있는 기능을 코드 배포 없이 즉시 비활성화한다 C) 데이터베이스를 삭제한다 D) CI 파이프라인을 중단한다
정답: B
킬 스위치는 프로덕션에서 문제가 발생했을 때, 새로운 코드 배포 없이 피처 플래그를 OFF로 전환하여 해당 기능을 즉시 비활성화하는 패턴입니다. 롤백보다 훨씬 빠르게 대응할 수 있습니다.
Q5: SLSA (Supply-chain Levels for Software Artifacts)의 목적은?
A) 코드 성능 최적화 B) 소프트웨어 공급망의 무결성을 보장한다 C) 데이터베이스 보안 D) UI 디자인 검증
정답: B
SLSA는 소프트웨어 공급망 공격을 방지하기 위한 보안 프레임워크입니다. 빌드 프로세스의 출처 증명, 아티팩트 서명, 빌드 환경의 격리 등을 통해 소프트웨어가 변조되지 않았음을 보장합니다.
12. CI/CD 성숙도 체크리스트
CI/CD 성숙도 체크리스트:
Level 1 - 기본
[ ] 자동 빌드 파이프라인
[ ] 자동 테스트 실행
[ ] 코드 리뷰 프로세스
Level 2 - 표준
[ ] 배포 전략 (Rolling/Blue-Green)
[ ] 환경 분리 (dev/staging/prod)
[ ] 시크릿 관리 (Vault/OIDC)
Level 3 - 고급
[ ] GitOps (ArgoCD/Flux)
[ ] Feature Flags
[ ] Canary 배포
[ ] PR Preview 환경
Level 4 - 엘리트
[ ] 파이프라인 보안 (SLSA)
[ ] 자동 롤백
[ ] 모노레포 최적화
[ ] 릴리스 자동화
13. 참고 자료
- DORA Metrics: dora.dev
- ArgoCD Documentation: argo-cd.readthedocs.io
- Flux Documentation: fluxcd.io
- Turborepo Documentation: turbo.build
- Nx Documentation: nx.dev
- LaunchDarkly Docs: docs.launchdarkly.com
- Unleash Documentation: docs.getunleash.io
- SLSA Framework: slsa.dev
- Sigstore / Cosign: sigstore.dev
- Semgrep: semgrep.dev
- Conventional Commits: conventionalcommits.org
- Git Cliff (Changelog): git-cliff.org
- GitHub Actions Docs: docs.github.com/actions
- Kubernetes Deployment Strategies: kubernetes.io/docs
Advanced CI/CD Pipeline Guide 2025: Deployment Strategies, GitOps, Monorepo, Security Pipeline
- Introduction
- 1. Deployment Strategies
- 2. GitOps
- 3. Monorepo CI
- 4. Feature Flags
- 5. Environment Management
- 6. Pipeline Security
- 7. Rollback Strategies
- 8. Pipeline Performance Optimization
- 9. Release Management
- 10. Multi-Cloud Deployment
- 11. Quiz
- 12. CI/CD Maturity Checklist
- 13. References
Introduction
According to the 2024 DORA (DevOps Research and Assessment) report, elite teams deploy multiple times per day with a change failure rate below 5%. Low-performing teams deploy once a month and take weeks to recover. The key differentiator is CI/CD pipeline maturity.
Beyond simple build-test-deploy, modern CI/CD encompasses deployment strategies (Blue-Green, Canary), GitOps, monorepo optimization, feature flags, and security pipelines. This guide systematically covers advanced CI/CD strategies proven in production environments in 2025.
1. Deployment Strategies
1.1 Rolling Update
The most basic deployment method, replacing instances sequentially.
Time ->
Instance 1: [v1] [v1] [v2] [v2] [v2]
Instance 2: [v1] [v1] [v1] [v2] [v2]
Instance 3: [v1] [v1] [v1] [v1] [v2]
Traffic: 100% v1 -> mixed -> 100% v2
# Kubernetes Rolling Update
apiVersion: apps/v1
kind: Deployment
metadata:
name: api-server
spec:
replicas: 3
strategy:
type: RollingUpdate
rollingUpdate:
maxSurge: 1 # Max 1 additional Pod
maxUnavailable: 0 # Zero downtime
template:
spec:
containers:
- name: api
image: myapp:v2
readinessProbe:
httpGet:
path: /health
port: 8080
initialDelaySeconds: 10
periodSeconds: 5
Pros: Simple, minimal extra resources, gradual replacement Cons: Mixed v1/v2 traffic during deployment, difficult instant rollback
1.2 Blue-Green Deployment
Maintain two identical environments (Blue/Green) and switch traffic all at once.
┌─────────────────────────────────────────────┐
│ │
│ Load Balancer │
│ | │
│ v (Before switch: traffic to Blue) │
│ ┌───────────┐ ┌───────────┐ │
│ │ Blue │ │ Green │ │
│ │ (v1) │ │ (v2) │ │
│ │ Active │ │ Standby │ │
│ └───────────┘ └───────────┘ │
│ │
│ After switch: 100% traffic to Green │
│ │
│ ┌───────────┐ ┌───────────┐ │
│ │ Blue │ │ Green │ │
│ │ (v1) │ │ (v2) │ │
│ │ Standby │ │ Active │ │
│ └───────────┘ └───────────┘ │
└─────────────────────────────────────────────┘
# Blue-Green with AWS ALB (GitHub Actions)
name: Blue-Green Deploy
on:
push:
branches: [main]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build and Push Docker Image
run: |
docker build -t myapp:${{ github.sha }} .
docker push myregistry/myapp:${{ github.sha }}
- name: Deploy to Green Environment
run: |
aws ecs update-service \
--cluster production \
--service green-service \
--task-definition myapp:${{ github.sha }}
- name: Run Smoke Tests on Green
run: |
./scripts/smoke-test.sh https://green.myapp.com
- name: Switch Traffic to Green
run: |
aws elbv2 modify-listener \
--listener-arn ${{ secrets.ALB_LISTENER_ARN }} \
--default-actions \
Type=forward,TargetGroupArn=${{ secrets.GREEN_TG_ARN }}
Pros: Instant rollback (switch traffic to Blue), zero downtime Cons: 2x infrastructure cost, complex database migrations
1.3 Canary Deployment
Deploy the new version to a small percentage of traffic first for validation.
Phase 1: 5% traffic to Canary (v2)
┌──────────────────────────────┐
│ v1 v1 v1 v1 v1 v1 v1 v1 v1 │ 95%
│ v2 │ 5%
└──────────────────────────────┘
Phase 2: Expand to 25% after validation
┌──────────────────────────────┐
│ v1 v1 v1 v1 v1 v1 v1 │ 75%
│ v2 v2 v2 │ 25%
└──────────────────────────────┘
Phase 3: 100% after confirming stability
┌──────────────────────────────┐
│ v2 v2 v2 v2 v2 v2 v2 v2 v2 │ 100%
└──────────────────────────────┘
# Canary Deployment with Istio
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: myapp
spec:
hosts:
- myapp.example.com
http:
- route:
- destination:
host: myapp
subset: stable
weight: 95
- destination:
host: myapp
subset: canary
weight: 5
---
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: myapp
spec:
host: myapp
subsets:
- name: stable
labels:
version: v1
- name: canary
labels:
version: v2
Pros: Minimized risk, validation with real traffic, progressive rollout Cons: Implementation complexity, requires metrics-based automation
1.4 Deployment Strategy Comparison
| Strategy | Downtime | Rollback Speed | Cost | Complexity | Best For |
|---|---|---|---|---|---|
| Rolling | None | Slow | Low | Low | General services |
| Blue-Green | None | Instant | High (2x) | Medium | Critical services |
| Canary | None | Fast | Medium | High | High-traffic services |
| A/B Testing | None | Fast | Medium | Very High | Feature experiments |
2. GitOps
2.1 GitOps Principles
┌──────────────────────────────────────────────────────┐
│ GitOps Principles │
│ │
│ 1. Declarative │
│ - System state declared as code │
│ │
│ 2. Versioned │
│ - Git is the Single Source of Truth (SSOT) │
│ │
│ 3. Automated │
│ - Approved changes auto-applied to system │
│ │
│ 4. Self-healing │
│ - Auto-corrects drift between desired/actual state │
└──────────────────────────────────────────────────────┘
2.2 ArgoCD Configuration
# argocd-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: myapp-production
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/k8s-manifests.git
targetRevision: main
path: apps/myapp/overlays/production
destination:
server: https://kubernetes.default.svc
namespace: production
syncPolicy:
automated:
prune: true # Clean up orphaned resources
selfHeal: true # Auto-revert manual changes
allowEmpty: false
syncOptions:
- CreateNamespace=true
- PrunePropagationPolicy=foreground
retry:
limit: 5
backoff:
duration: 5s
factor: 2
maxDuration: 3m
2.3 ArgoCD App-of-Apps Pattern
# root-application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: root-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myorg/k8s-manifests.git
targetRevision: main
path: apps
destination:
server: https://kubernetes.default.svc
# apps/ directory structure
# apps/
# myapp/
# application.yaml
# api-gateway/
# application.yaml
# monitoring/
# application.yaml
# cert-manager/
# application.yaml
2.4 ArgoCD vs Flux Comparison
| Feature | ArgoCD | Flux v2 |
|---|---|---|
| UI Dashboard | Built-in web UI | Weave GitOps (separate) |
| Multi-cluster | Supported | Supported |
| Helm Support | Native | HelmRelease CRD |
| Kustomize | Native | Native |
| Image Auto-update | ArgoCD Image Updater | Built-in |
| Notifications | ArgoCD Notifications | Notification Controller |
| RBAC | Built-in | Uses Kubernetes RBAC |
| Approach | Pull-based | Pull-based |
| Learning Curve | Medium | Medium-High |
2.5 ArgoCD Notification Setup
# argocd-notifications-cm.yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: argocd-notifications-cm
namespace: argocd
data:
service.slack: |
token: $slack-token
trigger.on-sync-succeeded: |
- when: app.status.sync.status == 'Synced'
send: [app-sync-succeeded]
trigger.on-sync-failed: |
- when: app.status.sync.status == 'Unknown'
send: [app-sync-failed]
template.app-sync-succeeded: |
slack:
attachments: |
[{
"color": "#18be52",
"title": "{{.app.metadata.name}} sync succeeded",
"text": "Deployment complete: {{.app.spec.source.targetRevision}}"
}]
template.app-sync-failed: |
slack:
attachments: |
[{
"color": "#E96D76",
"title": "{{.app.metadata.name}} sync failed",
"text": "Error: {{.app.status.conditions}}"
}]
3. Monorepo CI
3.1 Monorepo Structure
monorepo/
apps/
web/ # Next.js frontend
api/ # Express backend
mobile/ # React Native app
packages/
ui/ # Shared UI components
utils/ # Shared utilities
config/ # Shared configuration
turbo.json # Turborepo config
nx.json # Or Nx config
package.json
3.2 Turborepo Configuration
{
"globalDependencies": ["**/.env.*local"],
"pipeline": {
"build": {
"dependsOn": ["^build"],
"outputs": ["dist/**", ".next/**"],
"cache": true
},
"test": {
"dependsOn": ["build"],
"outputs": [],
"cache": true
},
"lint": {
"outputs": [],
"cache": true
},
"deploy": {
"dependsOn": ["build", "test", "lint"],
"cache": false
}
}
}
3.3 Nx Affected Builds
# .github/workflows/monorepo-ci.yml
name: Monorepo CI
on:
pull_request:
branches: [main]
jobs:
affected:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0 # Full history needed
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
- run: npm ci
# Only build/test changed projects
- name: Lint affected
run: npx nx affected --target=lint --base=origin/main
- name: Test affected
run: npx nx affected --target=test --base=origin/main
- name: Build affected
run: npx nx affected --target=build --base=origin/main
# Remote Caching
remote-cache:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- name: Build with remote cache
run: npx turbo build --team=myteam --token=${{ secrets.TURBO_TOKEN }}
env:
TURBO_TEAM: myteam
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
3.4 Turborepo vs Nx vs Bazel
| Feature | Turborepo | Nx | Bazel |
|---|---|---|---|
| Learning Curve | Low | Medium | High |
| Language Support | JS/TS | JS/TS, Go, Rust, etc. | Multi-language |
| Change Detection | File hashes | Project graph | Dependency graph |
| Remote Caching | Vercel RC | Nx Cloud | Remote Execution |
| Config Complexity | Very simple | Medium | Complex |
| Scale Suitability | Medium | Large | Very large |
| Code Generation | None | Built-in Generator | Rules |
4. Feature Flags
4.1 Types of Feature Flags
┌──────────────────────────────────────────────────┐
│ Feature Flag Types │
├──────────────────────────────────────────────────┤
│ │
│ 1. Release Flag │
│ - Hide incomplete features while deploying │
│ - Lifespan: Short (days to weeks) │
│ │
│ 2. Experiment Flag │
│ - A/B testing, feature comparison │
│ - Lifespan: Medium (weeks to months) │
│ │
│ 3. Ops Flag │
│ - System behavior control (kill switch) │
│ - Lifespan: Permanent │
│ │
│ 4. Permission Flag │
│ - Per-user/organization feature access │
│ - Lifespan: Permanent │
└──────────────────────────────────────────────────┘
4.2 Implementation Example
// featureFlags.ts
import { UnleashClient } from 'unleash-proxy-client';
const unleash = new UnleashClient({
url: 'https://unleash.myapp.com/api/frontend',
clientKey: process.env.UNLEASH_CLIENT_KEY!,
appName: 'myapp-frontend',
refreshInterval: 15,
});
unleash.start();
// React Hook
export function useFeatureFlag(flagName: string): boolean {
const [enabled, setEnabled] = useState(false);
useEffect(() => {
setEnabled(unleash.isEnabled(flagName));
const handler = () => {
setEnabled(unleash.isEnabled(flagName));
};
unleash.on('update', handler);
return () => unleash.off('update', handler);
}, [flagName]);
return enabled;
}
// Usage in component
function CheckoutPage() {
const newCheckoutEnabled = useFeatureFlag('new-checkout-flow');
if (newCheckoutEnabled) {
return <NewCheckoutFlow />;
}
return <LegacyCheckoutFlow />;
}
4.3 Progressive Rollout
// Server-side feature flags (LaunchDarkly style)
import LaunchDarkly from 'launchdarkly-node-server-sdk';
const client = LaunchDarkly.init(process.env.LD_SDK_KEY!);
async function getFeatureValue(
flagKey: string,
user: LDUser,
defaultValue: boolean
): Promise<boolean> {
await client.waitForInitialization();
return client.variation(flagKey, user, defaultValue);
}
// Progressive rollout phases:
// Phase 1: Internal employees only (beta-testers group)
// Phase 2: 5% of users
// Phase 3: 25% of users
// Phase 4: 50% of users
// Phase 5: 100% of users
// Kill switch pattern
async function processPayment(order: Order) {
const newPaymentEnabled = await getFeatureValue(
'new-payment-gateway',
{ key: order.userId },
false // Default: disabled
);
if (newPaymentEnabled) {
return newPaymentGateway.process(order);
}
return legacyPaymentGateway.process(order);
}
4.4 LaunchDarkly vs Unleash vs Flagsmith
| Feature | LaunchDarkly | Unleash | Flagsmith |
|---|---|---|---|
| Pricing | Paid (expensive) | Open source + Enterprise | Open source + Cloud |
| Targeting | Very sophisticated | Basic | Sophisticated |
| A/B Testing | Built-in | Separate | Built-in |
| SDK Support | 25+ languages | 15+ languages | 15+ languages |
| Self-hosting | Not available | Available | Available |
| Audit Logs | Supported | Supported | Supported |
5. Environment Management
5.1 Environment Hierarchy
┌─────────────────────────────────────────┐
│ Production │
│ - Real user traffic │
│ - Highest level monitoring │
│ - Change approval process │
├─────────────────────────────────────────┤
│ Staging │
│ - Identical to production config │
│ - QA team testing │
│ - Integration tests │
├─────────────────────────────────────────┤
│ Development │
│ - Latest feature integration │
│ - Auto-deploy from main branch │
├─────────────────────────────────────────┤
│ PR Preview │
│ - Independent environment per PR │
│ - Auto-deleted when PR closes │
└─────────────────────────────────────────┘
5.2 Ephemeral Environments
# .github/workflows/preview.yml
name: PR Preview Environment
on:
pull_request:
types: [opened, synchronize, reopened]
jobs:
deploy-preview:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Deploy Preview
run: |
PREVIEW_URL="pr-${{ github.event.number }}.preview.myapp.com"
helm upgrade --install \
pr-${{ github.event.number }} \
./charts/myapp \
--namespace previews \
--set image.tag=${{ github.sha }} \
--set ingress.host=$PREVIEW_URL \
--set resources.requests.memory=256Mi \
--set resources.requests.cpu=100m
- name: Comment PR with URL
uses: actions/github-script@v7
with:
script: |
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: `Preview deployed: https://pr-${context.issue.number}.preview.myapp.com`
})
cleanup-preview:
if: github.event.action == 'closed'
runs-on: ubuntu-latest
steps:
- name: Delete Preview
run: |
helm uninstall pr-${{ github.event.number }} \
--namespace previews
6. Pipeline Security
6.1 Secrets Management
# GitHub Actions - AWS Auth via OIDC (no long-lived secrets)
name: Secure Deploy
permissions:
id-token: write
contents: read
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# OIDC-based AWS auth (no long-lived secrets needed)
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: arn:aws:iam::123456789012:role/github-actions-role
aws-region: us-east-1
# Secret scanning
- name: Scan for secrets
uses: trufflesecurity/trufflehog@v3
with:
path: ./
extra_args: --only-verified
# Container image scanning
- name: Scan container image
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:${{ github.sha }}
severity: 'CRITICAL,HIGH'
exit-code: '1'
6.2 SLSA (Supply-chain Levels for Software Artifacts)
# SLSA Level 3 - Signed builds + provenance attestation
name: SLSA Build
jobs:
build:
runs-on: ubuntu-latest
permissions:
id-token: write
contents: read
attestations: write
steps:
- uses: actions/checkout@v4
- name: Build
run: npm run build
# Artifact signing with Sigstore
- name: Sign artifact
uses: sigstore/cosign-installer@v3
- name: Sign container image
run: |
cosign sign \
--yes \
myregistry/myapp:${{ github.sha }}
# Generate SLSA provenance attestation
- name: Generate SLSA provenance
uses: slsa-framework/slsa-github-generator/.github/workflows/generator_container_slsa3.yml@v2.0.0
with:
image: myregistry/myapp
digest: ${{ steps.build.outputs.digest }}
6.3 Security Scanning Pipeline
# .github/workflows/security.yml
name: Security Pipeline
on:
pull_request:
branches: [main]
schedule:
- cron: '0 6 * * 1' # Every Monday at 06:00
jobs:
sast:
name: Static Analysis
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Run Semgrep
uses: semgrep/semgrep-action@v1
with:
config: p/owasp-top-ten
dependency-check:
name: Dependency Audit
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm audit --audit-level=high
- name: Snyk Test
uses: snyk/actions/node@master
env:
SNYK_TOKEN: ${{ secrets.SNYK_TOKEN }}
container-scan:
name: Container Security
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Build image
run: docker build -t myapp:scan .
- name: Trivy scan
uses: aquasecurity/trivy-action@master
with:
image-ref: myapp:scan
severity: 'CRITICAL,HIGH'
format: 'sarif'
output: 'trivy-results.sarif'
- name: Upload SARIF
uses: github/codeql-action/upload-sarif@v3
with:
sarif_file: 'trivy-results.sarif'
iac-scan:
name: Infrastructure as Code Scan
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- name: Checkov scan
uses: bridgecrewio/checkov-action@master
with:
directory: ./terraform
framework: terraform
7. Rollback Strategies
7.1 Instant Rollback
# Kubernetes rollback
# Immediately rollback to last successful version
# kubectl rollout undo deployment/myapp
# GitHub Actions auto-rollback
name: Deploy with Auto-Rollback
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Deploy new version
id: deploy
run: |
kubectl set image deployment/myapp \
myapp=myregistry/myapp:${{ github.sha }}
kubectl rollout status deployment/myapp --timeout=300s
- name: Run post-deploy checks
id: healthcheck
run: |
for i in $(seq 1 10); do
STATUS=$(curl -s -o /dev/null -w "%{http_code}" https://myapp.com/health)
if [ "$STATUS" != "200" ]; then
echo "Health check failed: $STATUS"
exit 1
fi
sleep 5
done
- name: Rollback on failure
if: failure()
run: |
echo "Rolling back to previous version..."
kubectl rollout undo deployment/myapp
kubectl rollout status deployment/myapp --timeout=300s
7.2 Database-Aware Rollback
When DB schema changes are part of a deployment:
1. Forward-Compatible Migration (safe)
┌─────────────────────────────────────┐
│ Step 1: Add new column (nullable) │
│ Step 2: Deploy app v2 (uses both) │
│ Step 3: Migrate data │
│ Step 4: Remove old column │
└─────────────────────────────────────┘
2. Expand-Contract Pattern
Phase 1 (Expand): Add new schema, keep old
Phase 2 (Migrate): Transfer data
Phase 3 (Contract): Remove old schema
7.3 Forward-Fix vs Rollback Decision Guide
| Situation | Recommended Strategy | Reason |
|---|---|---|
| Simple bug fix | Forward-Fix | Fix is faster than rollback |
| Critical outage | Instant Rollback | Service recovery is top priority |
| Includes DB migration | Forward-Fix | Risk of data loss on rollback |
| Performance degradation | Canary Rollback | Assess impact before deciding |
8. Pipeline Performance Optimization
8.1 Caching Strategies
# .github/workflows/optimized-ci.yml
name: Optimized CI
jobs:
build:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
# Node.js dependency caching
- uses: actions/setup-node@v4
with:
node-version: 20
cache: 'npm'
# Docker layer caching
- uses: docker/setup-buildx-action@v3
- uses: docker/build-push-action@v6
with:
context: .
push: true
tags: myapp:${{ github.sha }}
cache-from: type=gha
cache-to: type=gha,mode=max
# Turborepo remote caching
- name: Build with cache
run: npx turbo build --cache-dir=.turbo
env:
TURBO_TOKEN: ${{ secrets.TURBO_TOKEN }}
TURBO_TEAM: myteam
8.2 Parallelization Strategy
# Parallel job execution
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run lint
unit-test:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run test:unit
type-check:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run type-check
# Build after all checks pass
build:
needs: [lint, unit-test, type-check]
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
- run: npm ci
- run: npm run build
8.3 Self-Hosted Runners
# Self-hosted runners (ARM64 Mac, etc.)
jobs:
build-ios:
runs-on: [self-hosted, macOS, ARM64]
steps:
- uses: actions/checkout@v4
- name: Build iOS
run: xcodebuild -workspace MyApp.xcworkspace ...
build-android:
runs-on: [self-hosted, Linux, X64]
steps:
- uses: actions/checkout@v4
- name: Build Android
run: ./gradlew assembleRelease
9. Release Management
9.1 Semantic Versioning
MAJOR.MINOR.PATCH (e.g., 2.1.3)
MAJOR: Incompatible API changes
MINOR: Backward-compatible new features
PATCH: Backward-compatible bug fixes
Examples:
1.0.0 -> 1.0.1 (bug fix)
1.0.1 -> 1.1.0 (new feature)
1.1.0 -> 2.0.0 (Breaking Change)
9.2 Automated Release Notes
# .github/workflows/release.yml
name: Release
on:
push:
tags: ['v*']
permissions:
contents: write
jobs:
release:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v4
with:
fetch-depth: 0
- name: Generate Changelog
id: changelog
uses: orhun/git-cliff-action@v3
with:
config: cliff.toml
- name: Create Release
uses: softprops/action-gh-release@v2
with:
body: ${{ steps.changelog.outputs.content }}
draft: false
prerelease: false
9.3 Conventional Commits
# Commit message format
# type(scope): description
feat(auth): add OAuth2.0 login support
fix(cart): resolve quantity update race condition
docs(api): update REST API documentation
chore(deps): upgrade express to v5.0
perf(db): optimize query for order listing
refactor(payment): extract payment strategy pattern
test(checkout): add E2E tests for checkout flow
# Breaking Change notation
feat(api)!: change response format for /orders endpoint
BREAKING CHANGE: The orders endpoint now returns
paginated responses instead of a flat array.
9.4 Release Train Model
┌─────────────────────────────────────────────┐
│ Release Train (bi-weekly releases) │
│ │
│ Week 1: Feature development + Code Freeze │
│ Week 2: QA + Bug fixes + Release │
│ │
│ --+------+------+------+------+-- │
│ v2.1 v2.2 v2.3 v2.4 v2.5 │
│ │
│ Hotfixes deploy immediately from │
│ separate branch │
└─────────────────────────────────────────────┘
10. Multi-Cloud Deployment
10.1 Multi-Cloud with Terraform
# main.tf - Multi-cloud providers
terraform {
required_providers {
aws = {
source = "hashicorp/aws"
version = "~> 5.0"
}
google = {
source = "hashicorp/google"
version = "~> 5.0"
}
}
}
# AWS deployment
resource "aws_ecs_service" "primary" {
name = "myapp-primary"
cluster = aws_ecs_cluster.main.id
task_definition = aws_ecs_task_definition.app.arn
desired_count = 3
load_balancer {
target_group_arn = aws_lb_target_group.app.arn
container_name = "myapp"
container_port = 8080
}
}
# GCP deployment (DR)
resource "google_cloud_run_service" "failover" {
name = "myapp-failover"
location = "us-central1"
template {
spec {
containers {
image = "gcr.io/myproject/myapp:latest"
}
}
}
}
11. Quiz
Q1: What is the biggest advantage of Blue-Green deployment?
A) Lower infrastructure costs B) Instant rollback capability C) Simple implementation D) Traffic splitting capability
Answer: B
Blue-Green deployment maintains two identical environments, so when issues arise, you can instantly switch the load balancer traffic back to the previous environment (Blue). The tradeoff is 2x infrastructure cost.
Q2: What is the role of the Git repository in GitOps?
A) Code backup storage B) CI/CD pipeline runner C) Single Source of Truth (SSOT) for infrastructure D) Monitoring dashboard
Answer: C
In GitOps, the Git repository serves as the Single Source of Truth (SSOT) for infrastructure and application state. All changes go through Git, and tools like ArgoCD/Flux synchronize Git state with the actual cluster state.
Q3: What is the benefit of "affected" builds in monorepo CI?
A) It always builds all projects B) It only builds changed projects and their dependents, saving time C) It ignores build caches D) It skips tests
Answer: B
Affected builds analyze the Git diff to selectively build and test only changed projects and their dependents. This significantly reduces CI time in large monorepos.
Q4: What is the "kill switch" purpose of Feature Flags?
A) Shuts down the server B) Instantly disables a problematic feature without code deployment C) Deletes the database D) Stops the CI pipeline
Answer: B
A kill switch toggles a feature flag to OFF in production when problems occur, instantly disabling that feature without deploying new code. This is much faster than a rollback.
Q5: What is the purpose of SLSA (Supply-chain Levels for Software Artifacts)?
A) Code performance optimization B) Ensures software supply chain integrity C) Database security D) UI design verification
Answer: B
SLSA is a security framework to prevent software supply chain attacks. It ensures software integrity through build provenance attestation, artifact signing, and build environment isolation.
12. CI/CD Maturity Checklist
CI/CD Maturity Checklist:
Level 1 - Basic
[ ] Automated build pipeline
[ ] Automated test execution
[ ] Code review process
Level 2 - Standard
[ ] Deployment strategy (Rolling/Blue-Green)
[ ] Environment separation (dev/staging/prod)
[ ] Secrets management (Vault/OIDC)
Level 3 - Advanced
[ ] GitOps (ArgoCD/Flux)
[ ] Feature Flags
[ ] Canary deployment
[ ] PR Preview environments
Level 4 - Elite
[ ] Pipeline security (SLSA)
[ ] Auto-rollback
[ ] Monorepo optimization
[ ] Release automation
13. References
- DORA Metrics: dora.dev
- ArgoCD Documentation: argo-cd.readthedocs.io
- Flux Documentation: fluxcd.io
- Turborepo Documentation: turbo.build
- Nx Documentation: nx.dev
- LaunchDarkly Docs: docs.launchdarkly.com
- Unleash Documentation: docs.getunleash.io
- SLSA Framework: slsa.dev
- Sigstore / Cosign: sigstore.dev
- Semgrep: semgrep.dev
- Conventional Commits: conventionalcommits.org
- Git Cliff (Changelog): git-cliff.org
- GitHub Actions Docs: docs.github.com/actions
- Kubernetes Deployment Strategies: kubernetes.io/docs