Istio 카나리 배포 마스터하기: Jenkins, GitHub Actions 및 ArgoCD를 활용한 전체 CI/CD 파이프라인
Source: Dev.to
CI/CD에서 카나리 배포란?
카나리 배포는 새로운 버전을 천천히 릴리스하고, 소량의 사용자 트래픽으로 테스트한 뒤 트래픽을 단계적으로 늘려가는 방법을 의미합니다.
일반적인 진행 단계:
| 트래픽 분할 | 버전 |
|---|---|
| 100 % → 0 % | v1 → v2 |
| 90 % / 10 % | v1 / v2 |
| 70 % / 30 % | v1 / v2 |
| 50 % / 50 % | v1 / v2 |
| 0 % / 100 % | v1 / v2 |
문제가 감지되면 배포가 즉시 롤백됩니다. CI/CD와 Istio를 결합하면 이 과정을 완전 자동화할 수 있습니다.
Istio 카나리 파이프라인의 핵심 구성 요소
| 구성 요소 | 역할 |
|---|---|
| CI Pipeline | Docker 이미지 빌드, 테스트 실행, 아티팩트 푸시 |
| CD Pipeline | Kubernetes에 배포 |
| Istio VirtualService | 버전 간 트래픽 분할 |
| Istio DestinationRule | 서브셋(v1, v2) 정의 |
| Monitoring (Prometheus) | 장애 감지 |
| Rollback Logic | 필요 시 트래픽을 v1으로 전환 |
파이프라인은 Jenkins, GitHub Actions, ArgoCD 중 하나로 구현할 수 있으며, 모두 동일한 Istio YAML 파일을 사용합니다.
Git 저장소 폴더 구조
istio-microservices/
├── services/
│ └── orders-service/
│ ├── src/
│ └── Dockerfile
├── k8s/
│ └── orders/
│ ├── deployment.yaml
│ ├── service.yaml
│ ├── dest-rule.yaml
│ ├── vs-100-0.yaml
│ ├── vs-90-10.yaml
│ ├── vs-70-30.yaml
│ ├── vs-50-50.yaml
│ └── vs-0-100.yaml
└── ci/
├── Jenkinsfile
└── github-actions.yaml
각 VirtualService 파일은 카나리 롤아웃의 한 단계를 나타냅니다.
Istio 카나리 매니페스트
DestinationRule (subsets)
apiVersion: networking.istio.io/v1beta1
kind: DestinationRule
metadata:
name: orders-service
namespace: microservices
spec:
host: orders-service
subsets:
- name: v1
labels:
version: v1
- name: v2
labels:
version: v2
VirtualService 단계
단계 1 – 100 % v1 (시작점) – vs-100-0.yaml
apiVersion: networking.istio.io/v1beta1
kind: VirtualService
metadata:
name: orders-service
namespace: microservices
spec:
hosts:
- orders-service
http:
- route:
- destination:
host: orders-service
subset: v1
weight: 100
- destination:
host: orders-service
subset: v2
weight: 0
단계 2 – 90 % v1 / 10 % v2 – vs-90-10.yaml
# similar structure, weights 90 and 10
vs-70-30.yaml, vs-50-50.yaml, vs-0-100.yaml 파일은 weight 값을 해당 비율에 맞게 조정하여 생성합니다.
자동 승격을 위한 헬스 메트릭
다음 트래픽 분할로 이동하기 전에 파이프라인은 아래 항목을 확인합니다 (Jenkinsfile 예시).
pipeline {
agent any
environment {
NAMESPACE = 'microservices'
}
stages {
stage('Deploy v2') {
steps {
sh "kubectl apply -f k8s/orders/deployment.yaml -n $NAMESPACE"
}
}
stage('Canary 10%') {
steps {
sh "kubectl apply -f k8s/orders/vs-90-10.yaml -n $NAMESPACE"
}
}
stage('Check Metrics') {
steps {
script {
def errorRate = sh(script: "curl -s http://prometheus/api/v1/query?query=...", returnStdout: true).trim()
if (errorRate.toDouble() > 0.01) {
error "High error rate detected — Rolling back"
}
}
}
}
stage('Shift to 50/50') {
steps {
sh "kubectl apply -f k8s/orders/vs-50-50.yaml -n $NAMESPACE"
}
}
stage('Promote to 100% v2') {
steps {
sh "kubectl apply -f k8s/orders/vs-0-100.yaml -n $NAMESPACE"
}
}
}
post {
failure {
sh "kubectl apply -f k8s/orders/vs-100-0.yaml -n $NAMESPACE"
}
}
}
GitHub Actions 워크플로 (간단, 클라우드‑네이티브)
name: Istio Canary Deployment
on:
push:
branches: [ main ]
jobs:
deploy:
runs-on: ubuntu-latest
steps:
- name: Checkout
uses: actions/checkout@v3
- name: Build Image
run: |
docker build -t myrepo/orders-service:${{ github.run_number }} services/orders-service
docker push myrepo/orders-service:${{ github.run_number }}
- name: Deploy v2
run: |
sed -i "s|image:.*|image: myrepo/orders-service:${{ github.run_number }}|g" k8s/orders/deployment.yaml
kubectl apply -f k8s/orders/deployment.yaml -n microservices
- name: Canary 10%
run: kubectl apply -f k8s/orders/vs-90-10.yaml -n microservices
- name: Wait & Check Prometheus
run: |
sleep 60
ERR=$(curl -s "http://prometheus/api/v1/query?query=sum(rate(istio_requests_total{response_code=~\"5.*\"}[1m]))/sum(rate(istio_requests_total[1m]))")
ERR_VAL=$(echo $ERR | jq '.data.result[0].value[1]' | tr -d '"')
if (( $(echo "$ERR_VAL > 0.01" | bc -l) )); then exit 1; fi
- name: Shift to 50/50
run: kubectl apply -f k8s/orders/vs-50-50.yaml -n microservices
- name: Promote 100% v2
run: kubectl apply -f k8s/orders/vs-0-100.yaml -n microservices
ArgoCD를 활용한 GitOps 버전
ArgoCD가 저장소를 지속적으로 감시하고 Istio 매니페스트를 적용하여 완전 자동화된 GitOps 워크플로를 구현합니다.
ArgoCD Application 정의 (argo-app.yaml)
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: istio-canary-app
namespace: argocd
spec:
project: default
source:
repoURL: https://github.com/myrepo/istio-microservices
path: k8s/orders
destination:
server: https://kubernetes.default.svc/
namespace: microservices
syncPolicy:
automated:
prune: true
selfHeal: true
애플리케이션 배포:
kubectl apply -f argo-app.yaml
트래픽을 전환하려면 원하는 VirtualService 파일(예: vs-90-10.yaml)을 커밋하고 푸시하면 됩니다. ArgoCD가 변화를 감지하고 즉시 적용합니다.
자동 롤백 전략
다음 조건 중 하나라도 만족하면 롤백이 즉시 트리거됩니다:
- 오류율 > 1 %
- p95 레이턴시가 정의된 임계값 초과
- Pod 재시작 횟수 급증
- Prometheus가 감지한 트래픽 이상 징후
실패 시 파이프라인에서 사용하는 롤백 명령:
kubectl apply -f k8s/orders/vs-100-0.yaml -n microservices
CI/CD에서의 가시성
- Grafana – 메트릭 대시보드
- Jaeger – 버전별 분산 트레이싱
- Kiali – 트래픽 그래프 (색상으로 v1 vs v2 구분)
- Prometheus – 원시 메트릭 및 알림
카나리 롤아웃 중 Kiali는 트래픽 분할을 실시간으로 표시해 운영자가 새로운 버전의 영향을 즉시 파악할 수 있게 합니다.
최종 요약
이 가이드에서는 다음을 포함하는 완전한 Istio 카나리 배포 파이프라인을 구축했습니다:
- 자동 Docker 이미지 빌드
- 새로운 마이크로서비스 버전(v2) 배포
- Istio
VirtualService와DestinationRule을 이용한 트래픽 전환 - 승격 전 Prometheus 기반 헬스 체크
- 실패 시 자동 롤백
- ArgoCD를 활용한 GitOps 구현
- Jenkins와 GitHub Actions 예시를 통한 CI/CD 구현
- 관측 스택(Grafana, Jaeger, Kiali, Prometheus)
이러한 패턴은 Netflix, IBM, Red Hat, Airbnb 등 기업의 프로덕션 환경에서도 사용됩니다.