ArgoCD 의 Rollout을 가지고 실제 트래픽 기반으로 배포를 구성하는 방식에 대해서 진행해보겠습니다. 실제 Kubernetes Rolling Update는 단순한 업데이트 제어만 할 뿐 특정 조건에 따라 배포를 하지 않아 실제 서비스에서는 배포한 앱이 장애가 나면 수동으로 롤백해야되는 문제점이 있습니다.
ArgoCD는 이러한 상황에서 조건을 가지고 자동으로 배포가 이루어지고 문제 시 특정 메트릭 조건으로 배포를 제어할 수 있습니다.
가장 많이 사용되는 Canary, Blue/Green 배포에 대해서 알아보겠습니다.
항목 Kubernetes Rolling Update Argo Rollouts 방식
| 리소스 종류 | Deployment 객체 (기본) | Rollout CRD + (선택) AnalysisTemplate, AnalysisRun 등 |
| 주요 설정 필드 | spec.strategy.type = RollingUpdate + rollingUpdate.maxSurge / maxUnavailable | strategy.canary (또는 strategy.blueGreen) + steps (예: setWeight, pause) + trafficRouting + analysis 옵션 |
| 트래픽 제어 | 라우팅 제어 기본 제공 없음 — Pod 교체 순서만 제어 가능 | 트래픽 가중치 제어 가능 (예: “새 버전에 트래픽 10% 먼저”, 단계별 증가) + Service/Ingress/VirtualService 연동 가능 |
| 메트릭 기반 자동화 | 기본 제공 안함. 수동 롤백/승격 중심 | 메트릭 기반 자동 롤백/승격 가능 — 외부 메트릭 제공자 연동 가능 |
| 설정 복잡성 | 낮음 — 익숙한 Deployment 설정 | 높음 — CRD 추가, 트래픽 제어(메쉬/Ingress) 준비, 메트릭/분석 통합 필요 |
| 사용 적합성 | 표준 서비스, 충분한 안정성, 리스크 낮음 | 고가용성/대규모/리스크 민감 서비스, progressive delivery 필요 시 |
| 운영 부담 | 상대적으로 낮음 | 트래픽 제어, 분석 상태 모니터링, 단계별 승격 관리 등 부가 운영 요소 존재 |
Argo Rollout 설치하기
모든 코드는 https://github.com/hanship0530/Learning/tree/main/ci-cd-cookbook/5w/argo-rollout 에 있습니다.
https://hanship.tistory.com/3 앞에서 설명한 ArgoCD 설치하기 글을 참조합니다.
아래의 파일들을 작성하고 commit & push를 해줍니다.
- apps/argo-rollouts/application.yaml 파일
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: argo-rollouts
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: dev
source:
repoURL: <https://github.com/><자신의 Github ID>/argo-rollout.git
targetRevision: main
path: bootstrap/argo-rollouts
destination:
server: <https://kubernetes.default.svc>
namespace: argo-rollouts
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
retry:
limit: 1
backoff:
duration: 5s
factor: 2
maxDuration: 3m
- bootstrap/argo-rollouts/kustomization.yaml
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: argo-rollouts
resources:
- <https://github.com/argoproj/argo-rollouts/releases/latest/download/install.yaml>
- namespace.yaml
labels:
- pairs:
app.kubernetes.io/name: argo-rollouts
app.kubernetes.io/part-of: argo-rollouts
- bootstrap/argo-rollouts/namespace.yaml
apiVersion: v1
kind: Namespace
metadata:
name: argo-rollouts
labels:
app.kubernetes.io/name: argocd-rollouts
app.kubernetes.io/part-of: argocd-rollouts
- 위 사항을 작성하고 commit & push 합니다.
- 확인
kubectl get all -n argo-rollouts
NAME READY STATUS RESTARTS AGE
pod/argo-rollouts-68bffbdf98-4fgtk 1/1 Running 0 23s
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
service/argo-rollouts-metrics ClusterIP 10.96.152.216 <none> 8090/TCP 23s
NAME READY UP-TO-DATE AVAILABLE AGE
deployment.apps/argo-rollouts 1/1 1 1 23s
NAME DESIRED CURRENT READY AGE
replicaset.apps/argo-rollouts-68bffbdf98 1 1 1 23s
kubectl get crd | grep rollouts
rollouts.argoproj.io 2025-11-15T11:11:58Z
kubectl get application argo-rollouts -n argocd
NAME SYNC STATUS HEALTH STATUS
argo-rollouts OutOfSync Healthy
Rollout Extension 설치하기
https://github.com/argoproj-labs/rollout-extension#kustomize-patch 를 참조합니다.
bootstrap/argo-cd/kustomization.yaml 파일에 아래의 항목을 추가하여 commit & push를 해줍니다.
- target:
kind: Deployment
name: argocd-server
patch: |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: argocd-server
spec:
template:
spec:
initContainers:
- name: rollout-extension
image: quay.io/argoprojlabs/argocd-extension-installer:v0.0.8
env:
- name: EXTENSION_URL
value: <https://github.com/argoproj-labs/rollout-extension/releases/download/v0.3.7/extension.tar>
volumeMounts:
- name: extensions
mountPath: /tmp/extensions/
securityContext:
runAsUser: 1000
allowPrivilegeEscalation: false
containers:
- name: argocd-server
volumeMounts:
- name: extensions
mountPath: /tmp/extensions/
volumes:
- name: extensions
emptyDir: {}
추가적으로 프로젝트를 생성해줍니다
- apps/projects/dev.yaml
apiVersion: argoproj.io/v1alpha1
kind: AppProject
metadata:
name: dev
namespace: argocd
spec:
description: Dev Env
sourceRepos:
- '*'
destinations:
- namespace: '*'
server: '*'
clusterResourceWhitelist:
- group: '*'
kind: '*'
namespaceResourceWhitelist:
- group: '*'
kind: '*'
모든 내용을 commit & push 하고 반영해줍니다.

설치된것을 확인할 수 있습니다.
Rollout Test를 위한 Prometheus 설치하기
ArgoCD에서 Prometheus를 연동하여 트래픽의 http status 가 200 으로 일정시간동안 유지시 배포가 되도록 설정하기 위한 Prometheus를 설치해줍니다.
argocd 설치하기에서 생성한 github repository인 argo-rollout 레포에서 이어서 작업합니다.
prometheus 설치외에 기존에 배포한 ingress-nginx도 metric 설정을 해줍니다.
아래에 명시된 파일들을 생성하고 commit & push 를 해줍니다.
- apps/prometheus/application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: prometheus
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: infra
sources:
# Helm chart 소스
- repoURL: <https://prometheus-community.github.io/helm-charts>
chart: kube-prometheus-stack
targetRevision: "61.0.0"
helm:
releaseName: prometheus
includeCRDs: true
values: |
# Prometheus 설정
prometheus:
prometheusSpec:
retention: 30d
storageSpec:
volumeClaimTemplate:
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 50Gi
serviceMonitorSelectorNilUsesHelmValues: false
podMonitorSelectorNilUsesHelmValues: false
ruleSelectorNilUsesHelmValues: false
# 모든 ServiceMonitor를 선택하도록 명시적으로 설정 (빈 selector = 모든 것 선택)
serviceMonitorSelector: {}
podMonitorSelector: {}
# 모든 네임스페이스의 ServiceMonitor를 찾을 수 있도록 설정 (빈 selector = 모든 네임스페이스)
serviceMonitorNamespaceSelector: {}
podMonitorNamespaceSelector: {}
# Service 생성 (Argo Rollouts에서 접근 가능하도록)
service:
type: ClusterIP
port: 9090
serviceAccount:
create: true
# 리소스 제한 (kind 환경에 맞게 조정)
resources:
requests:
memory: 512Mi
cpu: 200m
limits:
memory: 1Gi
cpu: 500m
# Ingress 설정 (별도로 관리하므로 비활성화)
ingress:
enabled: false
# Grafana 설정 (선택사항)
grafana:
enabled: true
adminPassword: admin # 프로덕션에서는 Secret 사용 권장
service:
type: ClusterIP
port: 80
resources:
requests:
memory: 128Mi
cpu: 100m
limits:
memory: 256Mi
cpu: 200m
# Alertmanager 설정
alertmanager:
enabled: true
alertmanagerSpec:
storage:
volumeClaimTemplate:
spec:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 2Gi # kind 환경에 맞게 조정
resources:
requests:
memory: 128Mi
cpu: 100m
limits:
memory: 256Mi
cpu: 200m
# Node Exporter
nodeExporter:
enabled: true
# Kube State Metrics
kubeStateMetrics:
enabled: true
# Prometheus Operator
prometheusOperator:
enabled: true
resources:
requests:
memory: 128Mi
cpu: 100m
limits:
memory: 256Mi
cpu: 200m
# 기본 ServiceMonitor 생성
defaultRules:
create: true
# 네임스페이스 설정
namespaceOverride: monitoring
# Certificate 및 Ingress 소스 (kustomization)
- repoURL: <https://github.com/><자신의 Github ID>/argo-rollout.git
targetRevision: main
path: bootstrap/prometheus
destination:
server: <https://kubernetes.default.svc>
namespace: monitoring
ignoreDifferences:
# CRD annotation 크기 제한 문제로 인해 CRD를 ArgoCD 관리에서 완전히 제외
# CRD는 Helm chart가 설치하되, ArgoCD는 동기화하지 않음
- group: apiextensions.k8s.io
kind: CustomResourceDefinition
name: alertmanagers.monitoring.coreos.com
- group: apiextensions.k8s.io
kind: CustomResourceDefinition
name: prometheuses.monitoring.coreos.com
- group: apiextensions.k8s.io
kind: CustomResourceDefinition
name: prometheusagents.monitoring.coreos.com
- group: apiextensions.k8s.io
kind: CustomResourceDefinition
name: thanosrulers.monitoring.coreos.com
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- CreateNamespace=true
- ServerSideApply=true # CRD annotation 크기 제한 문제 해결
- RespectIgnoreDifferences=true # ignoreDifferences 설정 존중
retry:
limit: 1
backoff:
duration: 5s
factor: 2
maxDuration: 3m
- apps/ingress-nginx/kustomization.yaml 를 아래와 같이 수정
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: ingress-nginx
resources:
- <https://raw.githubusercontent.com/kubernetes/ingress-nginx/main/deploy/static/provider/kind/deploy.yaml>
- servicemonitor.yaml
patches:
- target:
kind: Deployment
name: ingress-nginx-controller
patch: |-
apiVersion: apps/v1
kind: Deployment
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
spec:
template:
metadata:
annotations:
prometheus.io/scrape: "true"
prometheus.io/port: "10254"
spec:
nodeSelector:
kubernetes.io/os: linux
ingress-ready: "true"
containers:
- name: controller
ports:
- containerPort: 10254
name: metrics
protocol: TCP
- target:
kind: Service
name: ingress-nginx-controller
patch: |-
apiVersion: v1
kind: Service
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/component: controller
spec:
ports:
- name: metrics
port: 10254
protocol: TCP
targetPort: metrics
- target:
kind: ConfigMap
name: ingress-nginx-controller
patch: |-
apiVersion: v1
kind: ConfigMap
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
data:
enable-ssl-passthrough: "true"
# kind 환경에서 localhost를 address로 설정
publish-status-address: "localhost"
# 메트릭 활성화 (기본값이지만 명시적으로 설정)
enable-metrics: "true"
# 호스트별 메트릭 수집 활성화 (host 레이블을 위해 필요)
metrics-per-host: "true"
patchesJson6902:
- target:
group: apps
version: v1
kind: Deployment
name: ingress-nginx-controller
namespace: ingress-nginx
path: metrics-args-patch.json
- apps/ingress-nginx/metrics-args-patch.json 생성
[
{
"op": "add",
"path": "/spec/template/spec/containers/0/args/-",
"value": "--enable-metrics=true"
},
{
"op": "add",
"path": "/spec/template/spec/containers/0/args/-",
"value": "--metrics-per-host=true"
}
]
- apps/ingress-nginx/servicemonitor.yaml 생성
apiVersion: monitoring.coreos.com/v1
kind: ServiceMonitor
metadata:
name: ingress-nginx-controller
namespace: ingress-nginx
labels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/part-of: ingress-nginx
release: prometheus
spec:
selector:
matchLabels:
app.kubernetes.io/name: ingress-nginx
app.kubernetes.io/component: controller
endpoints:
- port: metrics
interval: 30s
path: /metrics
scheme: http
namespaceSelector:
matchNames:
- ingress-nginx
- host 추가
# host 추가
echo "127.0.0.1 prometheus.example.com" | sudo tee -a /etc/hosts
Canary Test
Canary 배포를 테스트해보겠습니다.
생성해야 할 파일들은 아래와 같습니다.
- analysis-template.yaml : 배포 매트릭 체크를 위한 analysis template
- cacary.yaml : rollout 파일
- certificate.yaml : tls
- ingress.yaml : ingress 생성을 위함
- service.yaml : 서비스 파일
시나리오는 다음과 같습니다.
- rollout-demo를 blue로 배포
- rollout-demo를 yellow로 수정 후 3분 동안 200 status 가 80% 이상 유지되면 20%, 40%, 60%, 80%, 100% 배포를 한다
- 2번 이상 실패 시 롤백한다.
이전에 만들어둔 argo-rollout repository에서 작업합니다. 아래의 파일들을 생성하고 commit & push 를 진행해줍니다.
- rollouts/canary-test/analysis-template.yaml
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: rollouts-demo-analysis
spec:
args:
# Prometheus 주소를 환경에 맞게 수정하세요
# 예: <http://prometheus-kube-prometheus-prometheus.monitoring.svc:9090>
- name: prometheus-address
value: <http://prometheus-kube-prometheus-prometheus.monitoring.svc:9090>
# 앱 이름 (기본값: rollouts-demo)
- name: app-name
value: rollouts-demo
# Ingress 호스트명 (환경에 맞게 수정)
- name: ingress-host
value: rollouts-demo.example.com
# Ingress 서비스 이름
- name: ingress-service
value: rollouts-demo
metrics:
# Ingress HTTP 200 응답 지속성 확인 - 3분 동안 지속적으로 HTTP 200 응답이 있어야 함
# 이 메트릭은 3분 동안 매 30초마다 확인하여 HTTP 200 응답 비율이 80% 이상인지 확인합니다
- name: ingress-http200-duration
interval: 30s
count: 6 # 6번 확인 (30초 * 6 = 3분)
successCondition: result[0] >= 0.80 # HTTP 200 응답 비율이 80% 이상
failureLimit: 2 # 2번 실패하면 롤백
provider:
prometheus:
address: "{{args.prometheus-address}}"
query: |
# Ingress를 통한 HTTP 200 응답 비율 (3분 윈도우)
# rollouts-demo만 필터링 (host로 필터링)
(
sum(rate(nginx_ingress_controller_response_duration_seconds_count{
host="{{args.ingress-host}}",
status="200"
}[3m]))
/
sum(rate(nginx_ingress_controller_response_duration_seconds_count{
host="{{args.ingress-host}}"
}[3m]))
) or vector(0)
# Ingress HTTP 200 응답 수 확인 - 최소 요청 수 확인 (트래픽이 있는지 확인)
- name: ingress-http200-count
interval: 30s
count: 6 # 3분 동안 확인
successCondition: result[0] >= 0.1 # 초당 0.1 개 이상의 요청이 있어야 함
failureLimit: 6 # 모든 체크에서 실패해야 롤백 (더 관대하게)
provider:
prometheus:
address: "{{args.prometheus-address}}"
query: |
# 3분 동안의 HTTP 200 응답 수 (rollouts-demo만)
sum(rate(nginx_ingress_controller_response_duration_seconds_count{
host="{{args.ingress-host}}",
status="200"
}[3m])) * 180
# Ingress 레이턴시 메트릭 (P95) - Ingress를 통한 응답 시간 모니터링
- name: ingress-latency-p95
interval: 30s
count: 6 # 3분 동안 확인
successCondition: result[0] <= 1000 # P95 레이턴시가 1000ms 이하
failureLimit: 3
provider:
prometheus:
address: "{{args.prometheus-address}}"
query: |
# Ingress를 통한 P95 레이턴시 (밀리초) - rollouts-demo만
# 메트릭이 없을 경우 NaN 방지
(
histogram_quantile(0.95,
sum(rate(nginx_ingress_controller_response_duration_seconds_bucket{
host="{{args.ingress-host}}"
}[3m])) by (le)
) * 1000
) or vector(0)
- rollouts/canary-test/canary.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: rollouts-demo
spec:
replicas: 5
strategy:
canary:
# Analysis를 사용하여 트래픽 기반 자동 배포
# 각 단계에서 메트릭을 확인하고 조건을 만족하면 자동으로 다음 단계로 진행
analysis:
templates:
- templateName: rollouts-demo-analysis
args:
- name: prometheus-address
value: <http://prometheus-kube-prometheus-prometheus.monitoring.svc:9090> # 환경에 맞게 수정
- name: app-name
value: rollouts-demo
- name: ingress-host
value: rollouts-demo.example.com # Ingress 호스트명 수정
- name: ingress-service
value: rollouts-demo # Ingress 서비스 이름
startingStep: 2 # 2단계부터 analysis 시작
successfulRunHistoryLimit: 3
unsuccessfulRunHistoryLimit: 3
steps:
- setWeight: 20
- pause:
duration: 30s # 30초 대기 후 자동 진행 (또는 analysis 완료 시 자동 진행)
- setWeight: 40
- pause:
duration: 10s # 최소 대기 시간
- analysis:
templates:
- templateName: rollouts-demo-analysis
args:
- name: prometheus-address
value: <http://prometheus-kube-prometheus-prometheus.monitoring.svc:9090>
- name: app-name
value: rollouts-demo
- name: ingress-host
value: rollouts-demo.example.com
- name: ingress-service
value: rollouts-demo
- setWeight: 60
- pause:
duration: 10s
- analysis:
templates:
- templateName: rollouts-demo-analysis
args:
- name: prometheus-address
value: <http://prometheus-kube-prometheus-prometheus.monitoring.svc:9090>
- name: app-name
value: rollouts-demo
- name: ingress-host
value: rollouts-demo.example.com
- name: ingress-service
value: rollouts-demo
- setWeight: 80
- pause:
duration: 10s
- analysis:
templates:
- templateName: rollouts-demo-analysis
args:
- name: prometheus-address
value: <http://prometheus-kube-prometheus-prometheus.monitoring.svc:9090>
- name: app-name
value: rollouts-demo
- name: ingress-host
value: rollouts-demo.example.com
- name: ingress-service
value: rollouts-demo
revisionHistoryLimit: 2
selector:
matchLabels:
app: rollouts-demo
template:
metadata:
labels:
app: rollouts-demo
spec:
containers:
- name: rollouts-demo
image: argoproj/rollouts-demo:blue
ports:
- name: http
containerPort: 8080
protocol: TCP
resources:
requests:
memory: 32Mi
cpu: 5m
- apps/canary-test/certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: rollouts-demo-tls
namespace: default
spec:
secretName: rollouts-demo-tls
issuerRef:
name: selfsigned-issuer
kind: ClusterIssuer
dnsNames:
- rollouts-demo.example.com
duration: 8760h # 1 year
renewBefore: 720h # 30 days
- apps/canary-test/ingress.yaml
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rollouts-demo-ingress
namespace: default
annotations:
# SSL 리다이렉트 (HTTP도 허용하도록 false로 설정, 또는 HTTPS만 사용하려면 true)
nginx.ingress.kubernetes.io/ssl-redirect: "false"
# 메트릭 수집을 위한 annotation (Prometheus가 메트릭을 수집할 수 있도록)
prometheus.io/scrape: "true"
prometheus.io/port: "10254"
spec:
ingressClassName: nginx
tls:
- hosts:
- rollouts-demo.example.com
secretName: rollouts-demo-tls
rules:
- host: rollouts-demo.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: rollouts-demo
port:
number: 80
- apps/canary-test/service.yaml
apiVersion: v1
kind: Service
metadata:
name: rollouts-demo
spec:
ports:
- port: 80
targetPort: 8080 # Rollout 컨테이너의 실제 포트
protocol: TCP
name: http
selector:
app: rollouts-demo
그리고 나서 application을 생성해줍니다. 테스트를 위해 image 를 argocd에서 sync하는 옵션은 끄기로 한다.
- apps/canary-test/application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: canary-test
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: dev
source:
repoURL: <https://github.com/><자신의 Github ID>/argo-rollout.git
targetRevision: main
path: rollouts/canary-test
destination:
server: <https://kubernetes.default.svc>
namespace: default
ignoreDifferences:
# kubectl patch로 변경한 image를 ArgoCD가 되돌리지 않도록 설정
- group: argoproj.io
kind: Rollout
name: rollouts-demo
namespace: default
jsonPointers:
- /spec/template/spec/containers/0/image
syncPolicy:
automated:
prune: false
selfHeal: false
syncOptions:
- RespectIgnoreDifferences=true
- 호스트 추가
echo "127.0.0.1 rollouts-demo.example.com" | sudo tee -a /etc/hosts
앱이 배포 된 이후 prometheus에서 아래의 메트릭이 조회되는지 확인을 하고 canary 배포를 진행한다.
rollouts-demo.example.com 창을 열어두고 http://prometheus.example.com/ 에서 메트릭 조회를 해본다.
sum(rate(nginx_ingress_controller_response_duration_seconds_count{host="rollouts-demo.example.com"}[3m]))

배포를 시작해본다. 현재 상태는 blue 이며 화면에서 처럼 Error 율을 조정할 수 있다.
3분 동안 성공 비율이 80% 이상이면 배포가 진행된다. 에러 비율을 30%로 조정해본다.

yellow로 배포해본다.
kubectl patch rollout rollouts-demo -n default --type='json' -p='[
{
"op": "replace",
"path": "/spec/template/spec/containers/0/image",
"value": "argoproj/rollouts-demo:yellow"
}
]'
revision이 2로 되었으며 실제 20%가 배포되었다.


현재 설정은 아래와 같다. 30s 동안 대기 후 자동으로 처리되며 pause.duration: {}는 수동으로 한다. failureLimit 2 는 2번 정도 실패하면 롤백을 진행한다.
- failureLimit: 2
- pause.duration: 30s 로
Error rate를 6% 로 조정하니 배포가 순차적으로 진행된다.


이후 다시 Error 비율을 28%로 늘리니 Blue로 완전히 롤백되었다.


Revision 이 다시 자동으로 1로 돌아갔다.
다시 배포를 하기 위해 이번에는 Error Rate 를 5% 로 하고 배포를 진행해본다.
kubectl patch rollout rollouts-demo -n default --type='json' -p='[
{
"op": "replace",
"path": "/spec/template/spec/containers/0/image",
"value": "argoproj/rollouts-demo:yellow"
}
]'
rollout.argoproj.io/rollouts-demo patched (no change)
진행 시 successCondition: result[0] 초당 1개의 요청은 있어야 하기에 창을 항상 켜놓는다.



Blue/Green 배포
Blue, Green 두 개를 배포하고 200 응답을 받은 비율이 80% 이상일 경우 Green으로 온전히 배포하는 테스트를 진행해보겠습니다.
동일하게 현재 Repository에서 아래의 파일들을 생성하고 commit & push 를 진행해줍니다.
- rollouts/blue-green-test/analysis-template.yaml
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: rollouts-demo-bg-analysis
spec:
args:
# Prometheus 주소를 환경에 맞게 수정하세요
- name: prometheus-address
value: <http://prometheus-kube-prometheus-prometheus.monitoring.svc:9090>
# 앱 이름
- name: app-name
value: rollouts-demo-bg
# Active Ingress 호스트명
- name: ingress-host-active
value: rollouts-demo-bg-active.example.com
# Preview Ingress 호스트명
- name: ingress-host-preview
value: rollouts-demo-bg-preview.example.com
metrics:
# Ingress HTTP 200 응답 비율 확인 - 80% 이상이어야 함
# 20% 단계 분석용 메트릭 (Preview 서비스 분석)
- name: ingress-http200-ratio-20
interval: 30s
count: 6 # 6번 확인 (30초 * 6 = 3분)
successCondition: result[0] >= 0.80 # HTTP 200 응답 비율이 80% 이상
failureLimit: 2 # 2번 실패하면 롤백
provider:
prometheus:
address: "{{args.prometheus-address}}"
query: |
# Preview Ingress를 통한 HTTP 200 응답 비율 (3분 윈도우)
(
sum(rate(nginx_ingress_controller_response_duration_seconds_count{
host="{{args.ingress-host-preview}}",
status="200"
}[3m]))
/
sum(rate(nginx_ingress_controller_response_duration_seconds_count{
host="{{args.ingress-host-preview}}"
}[3m]))
) or vector(0)
# 60% 단계 분석용 메트릭 (Preview 서비스 분석)
- name: ingress-http200-ratio-60
interval: 30s
count: 6 # 6번 확인 (30초 * 6 = 3분)
successCondition: result[0] >= 0.80 # HTTP 200 응답 비율이 80% 이상
failureLimit: 2 # 2번 실패하면 롤백
provider:
prometheus:
address: "{{args.prometheus-address}}"
query: |
# Preview Ingress를 통한 HTTP 200 응답 비율 (3분 윈도우)
(
sum(rate(nginx_ingress_controller_response_duration_seconds_count{
host="{{args.ingress-host-preview}}",
status="200"
}[3m]))
/
sum(rate(nginx_ingress_controller_response_duration_seconds_count{
host="{{args.ingress-host-preview}}"
}[3m]))
) or vector(0)
# 100% 단계 분석용 메트릭 (Preview 서비스 분석)
- name: ingress-http200-ratio-100
interval: 30s
count: 6 # 6번 확인 (30초 * 6 = 3분)
successCondition: result[0] >= 0.80 # HTTP 200 응답 비율이 80% 이상
failureLimit: 2 # 2번 실패하면 롤백
provider:
prometheus:
address: "{{args.prometheus-address}}"
query: |
# Preview Ingress를 통한 HTTP 200 응답 비율 (3분 윈도우)
(
sum(rate(nginx_ingress_controller_response_duration_seconds_count{
host="{{args.ingress-host-preview}}",
status="200"
}[3m]))
/
sum(rate(nginx_ingress_controller_response_duration_seconds_count{
host="{{args.ingress-host-preview}}"
}[3m]))
) or vector(0)
- rollouts/blue-green-test/blue-green.yaml
apiVersion: argoproj.io/v1alpha1
kind: Rollout
metadata:
name: rollouts-demo-bg
spec:
replicas: 3
strategy:
blueGreen:
# Active 서비스는 현재 프로덕션 트래픽을 받는 서비스
activeService: rollouts-demo-bg-active
# Preview 서비스는 새 버전(green)의 트래픽을 받는 서비스
previewService: rollouts-demo-bg-preview
# Auto Promotion: 분석이 성공하면 자동으로 green을 active로 전환
autoPromotionEnabled: true
# Promotion Policy: 분석이 성공하면 자동으로 전환
scaleDownDelaySeconds: 30 # 전환 후 30초 후에 이전 버전(blue) 제거
# Analysis를 사용하여 트래픽 기반 자동 배포
# HTTP 200 응답이 80% 이상일 때 자동으로 green을 active로 전환
# 20%, 60%, 100% 세 단계로 분석 수행
prePromotionAnalysis:
templates:
- templateName: rollouts-demo-bg-analysis
args:
- name: prometheus-address
value: <http://prometheus-kube-prometheus-prometheus.monitoring.svc:9090>
- name: app-name
value: rollouts-demo-bg
- name: ingress-host-active
value: rollouts-demo-bg-active.example.com
- name: ingress-host-preview
value: rollouts-demo-bg-preview.example.com
successfulRunHistoryLimit: 3
unsuccessfulRunHistoryLimit: 3
# Post Promotion Analysis: 전환 후에도 모니터링 (Active 서비스 분석)
postPromotionAnalysis:
templates:
- templateName: rollouts-demo-bg-analysis
args:
- name: prometheus-address
value: <http://prometheus-kube-prometheus-prometheus.monitoring.svc:9090>
- name: app-name
value: rollouts-demo-bg
- name: ingress-host-active
value: rollouts-demo-bg-active.example.com
- name: ingress-host-preview
value: rollouts-demo-bg-preview.example.com
successfulRunHistoryLimit: 3
unsuccessfulRunHistoryLimit: 3
revisionHistoryLimit: 2
selector:
matchLabels:
app: rollouts-demo-bg
template:
metadata:
labels:
app: rollouts-demo-bg
spec:
containers:
- name: rollouts-demo-bg
image: argoproj/rollouts-demo:blue
ports:
- name: http
containerPort: 8080
protocol: TCP
resources:
requests:
memory: 32Mi
cpu: 5m
- rollouts/blue-green-test/certificate.yaml
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: rollouts-demo-bg-active-tls
namespace: default
spec:
secretName: rollouts-demo-bg-active-tls
issuerRef:
name: selfsigned-issuer
kind: ClusterIssuer
dnsNames:
- rollouts-demo-bg-active.example.com
duration: 8760h # 1 year
renewBefore: 720h # 30 days
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
name: rollouts-demo-bg-preview-tls
namespace: default
spec:
secretName: rollouts-demo-bg-preview-tls
issuerRef:
name: selfsigned-issuer
kind: ClusterIssuer
dnsNames:
- rollouts-demo-bg-preview.example.com
duration: 8760h # 1 year
renewBefore: 720h # 30 days
- rollouts/blue-green-test/ingress.yaml
# Active 서비스용 Ingress (프로덕션 트래픽)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rollouts-demo-bg-active-ingress
namespace: default
annotations:
# SSL 리다이렉트 (HTTP도 허용하도록 false로 설정, 또는 HTTPS만 사용하려면 true)
nginx.ingress.kubernetes.io/ssl-redirect: "false"
# 메트릭 수집을 위한 annotation (Prometheus가 메트릭을 수집할 수 있도록)
prometheus.io/scrape: "true"
prometheus.io/port: "10254"
spec:
ingressClassName: nginx
tls:
- hosts:
- rollouts-demo-bg-active.example.com
secretName: rollouts-demo-bg-active-tls
rules:
- host: rollouts-demo-bg-active.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: rollouts-demo-bg-active # Active 서비스로 트래픽 라우팅
port:
number: 80
---
# Preview 서비스용 Ingress (테스트 트래픽)
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: rollouts-demo-bg-preview-ingress
namespace: default
annotations:
nginx.ingress.kubernetes.io/ssl-redirect: "false"
# 메트릭 수집을 위한 annotation (Prometheus가 메트릭을 수집할 수 있도록)
prometheus.io/scrape: "true"
prometheus.io/port: "10254"
spec:
ingressClassName: nginx
tls:
- hosts:
- rollouts-demo-bg-preview.example.com
secretName: rollouts-demo-bg-preview-tls
rules:
- host: rollouts-demo-bg-preview.example.com
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: rollouts-demo-bg-preview # Preview 서비스로 트래픽 라우팅
port:
number: 80
- rollouts/blue-green-test/service.yaml
apiVersion: v1
kind: Service
metadata:
name: rollouts-demo-bg-active
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app: rollouts-demo-bg
---
apiVersion: v1
kind: Service
metadata:
name: rollouts-demo-bg-preview
spec:
ports:
- port: 80
targetPort: 8080
protocol: TCP
name: http
selector:
app: rollouts-demo-bg
- apps/blue-green-test/application.yaml
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: blue-green-test
namespace: argocd
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
project: dev
source:
repoURL: <https://github.com/hanship0530/argo-rollout.git>
targetRevision: main
path: rollouts/blue-green-test
destination:
server: <https://kubernetes.default.svc>
namespace: default
ignoreDifferences:
# kubectl patch로 변경한 image를 ArgoCD가 되돌리지 않도록 설정
- group: argoproj.io
kind: Rollout
name: rollouts-demo-bg
namespace: default
jsonPointers:
- /spec/template/spec/containers/0/image
syncPolicy:
automated:
prune: false
selfHeal: false
syncOptions:
- RespectIgnoreDifferences=true
- host 추가
echo "127.0.0.1 rollouts-demo-bg-active.example.com" | sudo tee -a /etc/hosts
echo "127.0.0.1 rollouts-demo-bg-preview.example.com" | sudo tee -a /etc/hosts
위와 같이 설정을 하고 commit & push를 합니다. 그러면 argocd에서 배포된 앱을 확인 할 수 있습니다.

green로 배포를 진행해봅니다.
kubectl patch rollout rollouts-demo-bg -n default --type='json' -p='[
{
"op": "replace",
"path": "/spec/template/spec/containers/0/image",
"value": "argoproj/rollouts-demo:green"
}
]'
rollout.argoproj.io/rollouts-demo-bg patched
![]() active |
![]() preview |
preview와 active가 blue, green 으로 배포된 것을 볼 수 있습니다.
active의 error rate를 26% 로 수정합니다.
revision 2 가 배포됨을 볼 수 있고 아래의 pod 조회를 통해서 rollouts-demo-bg-59f7f685b5(blue), rollouts-demo-bg-84c464fb4(green) 각 3개 씩 배포된 것을 확인 할 수 있습니다.
Analysis 2-pre에서는 Revision 2에 대한 분석을 각 단계별로 진행합니다.
pre는 대부분의 request가 성공인 반면, post는 모두 실패합니다.

![]() |
![]() |
kubectl get pods -l app=rollouts-demo-bg
NAME READY STATUS RESTARTS AGE
rollouts-demo-bg-59f7f685b5-tx4vj 1/1 Running 0 3m51s
rollouts-demo-bg-59f7f685b5-vtbjv 1/1 Running 0 3m51s
rollouts-demo-bg-59f7f685b5-w7hxt 1/1 Running 0 3m51s
rollouts-demo-bg-84c464fb4-bnkgj 1/1 Running 0 2m44s
rollouts-demo-bg-84c464fb4-gcvd9 1/1 Running 0 2m44s
rollouts-demo-bg-84c464fb4-qtvkb 1/1 Running 0 2m44s
요건을 충족하지 못해 Rollback 됩니다.

![]() active |
![]() preview |
activate는 그대로 blue 이며, preview 503 에러가 발생합니다.
다시 blue로 전환 후 green으로 재배포 하며 이번에는 Error Rate를 5%로 조정해보겠습니다.
kubectl patch rollout rollouts-demo-bg -n default --type='json' -p='[
{
"op": "replace",
"path": "/spec/template/spec/containers/0/image",
"value": "argoproj/rollouts-demo:blue"
}
]'
# 적용 후
kubectl patch rollout rollouts-demo-bg -n default --type='json' -p='[
{
"op": "replace",
"path": "/spec/template/spec/containers/0/image",
"value": "argoproj/rollouts-demo:green"
}
]'
![]() |
![]() |
4번의 배포로 인해 희망하는 상태는 Revision4이며 Revision 분석결과를 지켜봅니다.
![]() |
![]() |
Analysis 4-pre 가 정상적으로 끝난 후 post가 실행됩니다.
이번에는 정상적으로 배포되었습니다. 성공조건과 트래픽 조건을 통해 배포 제어를 진행할 수 있습니다.


'스터디 > [gasida] ci-cd 스터디 1기' 카테고리의 다른 글
| OpenLDAP + KeyCloak + Argo CD + Jenkins (0) | 2025.11.23 |
|---|---|
| ArgoCD ApplicationSet (0) | 2025.11.23 |
| ArgoCD + Ingress + Self Managed (0) | 2025.11.16 |
| 4주차: Argo (0) | 2025.11.09 |
| 3주차: Jenkins + ArgoCD (0) | 2025.11.01 |









