에러 버짓 자동화: GitOps 배포 게이트로 SLO 위반을 차단하는 실전 구현 가이드
Argo Rollouts · Sloth · GitHub Actions 단계별 구성
"이 코드, 배포해도 될까?" — 모든 엔지니어링 팀이 반복하는 질문입니다. SLO 대시보드 숫자를 직접 확인하고, 팀 슬랙에 물어보고, 결국 사람이 판단합니다. 이 과정은 느리고 주관적이며, 심야 장애를 막아주지도 못합니다.
에러 버짓 정책 자동화는 이 질문을 시스템이 대신 답하게 만드는 방식입니다. Prometheus가 계산한 번 레이트를 CI/CD 파이프라인이 실시간으로 읽고, 미리 합의된 임계값을 초과하면 배포를 자동으로 차단합니다. 사람의 판단을 기다리는 것이 아니라, 팀이 코드로 명문화한 계약을 시스템이 집행합니다. 이 글에서는 에러 버짓의 핵심 개념부터 Argo Rollouts, Sloth, GitHub Actions, Flagger를 활용한 실전 GitOps 게이트 구성까지 단계별로 살펴봅니다.
이 글을 읽고 나면 기존 CI/CD 파이프라인에 번 레이트 기반 배포 게이트를 추가하고, SLO 위반 시 배포가 자동으로 차단되는 GitOps 환경을 구성할 수 있습니다. 단, 이 글은 Kubernetes 기본 개념(Pod, Deployment, kubectl)에 익숙한 독자를 전제로 작성되었습니다. 서비스 메시(Istio) 기반 예시는 해당 환경을 운영 중인 팀에만 해당됩니다.
핵심 개념
에러 버짓이란 무엇인가
에러 버짓(Error Budget)은 SLO 목표값에서 허용되는 "불신뢰성의 양"을 정량화한 개념입니다. 99.9% 가용성 SLO를 예로 들면, 한 달(30일 = 43,200분) 기준으로 약 43.2분의 다운타임이 허용됩니다.
에러 버짓 = (1 - SLO 목표값) × 측정 기간
예시: (1 - 0.999) × 43,200분 = 43.2분/월핵심 인사이트: 에러 버짓은 "얼마나 실패해도 되는가"가 아니라 "혁신과 안정성 사이에서 얼마나 빠르게 달릴 수 있는가"를 정의하는 연료 게이지입니다. 버짓이 풍부할 때는 빠르게 달리고, 소진될수록 속도를 줄이는 것이 핵심 원리입니다.
번 레이트: 소진 속도를 수치화하기
번 레이트(Burn Rate)는 에러 버짓이 얼마나 빠르게 소진되고 있는지를 나타냅니다. 번 레이트 1.0은 30일 동안 버짓이 정확히 소진되는 정상 속도를 의미합니다.
다음 표는 Google SRE Workbook 권장 기준을 기반으로 한 단계별 대응입니다.
| 번 레이트 | 의미 | 권장 대응 |
|---|---|---|
| 1.0x | 정상 페이스로 소진 | 모니터링 유지 |
| 2.0x | 예산의 2배 속도 소진 | 로그 경고 기록 |
| 5.0x | 예산의 5배 속도 소진 | 티켓 생성, 조사 시작 |
| 10.0x | 예산의 10배 속도 소진 | 온콜 엔지니어 호출 |
| 14.4x | 1시간 내 버짓 5% 소진 | 패스트 번 알림 (Google SRE 기준) |
| 20.0x+ | 극도로 빠른 소진 | 배포 자동 차단 |
용어 정의: 패스트 번(Fast Burn) 은 번 레이트 14.4x가 1시간 이상 지속되는 상태입니다. 이 속도가 계속되면 5일 안에 월간 버짓이 전부 소진됩니다. Google SRE Workbook은 이 상태를 즉각적인 알림 기준으로 권장합니다.
에러 버짓 정책: 팀 간 운영 계약
에러 버짓 정책(Error Budget Policy)은 "버짓이 얼마나 소진되었을 때 어떤 행동을 취할 것인가"를 SRE·개발·제품 팀 간에 사전 합의한 문서입니다. 자동화 이전에는 대시보드 숫자에 불과했지만, SLOs-as-Code 방식이 확산되면서 이 정책을 파이프라인에 직접 삽입하는 방식이 표준으로 자리잡고 있습니다.
핵심 자동화 흐름은 아래와 같이 이어집니다.
SLI 측정
↓
Prometheus 기록 (Recording Rule)
↓
번 레이트 계산
↓
정책 평가 (임계값 비교)
↓
배포 차단 또는 허용배포 게이트(Deployment Gate)는 이 흐름의 마지막 단계에서 동작하며, GitOps 환경에서는 다음 세 위치에 삽입할 수 있습니다.
- Git PR 승인 단계 (GitHub Actions Status Check)
- Argo CD PreSync/PostSync Hook
- Argo Rollouts AnalysisRun 단계
SLOs-as-Code: SLO를 코드로 관리하기
SLO 정의를 YAML 파일로 코드화하고 Git에 버전 관리하는 방식이 빠르게 확산되고 있습니다. 이 방식은 SLO 변경 이력을 코드 리뷰 프로세스로 관리할 수 있게 해주며, Kubernetes Operator와 결합하면 Prometheus Recording Rule과 Alert Rule을 자동으로 생성합니다.
| 도구 | 역할 | 특징 |
|---|---|---|
| Sloth | Prometheus SLO 규칙 자동 생성 | CLI + Kubernetes Operator, OpenSLO 호환 |
| Pyrra | SLO → PrometheusRule 자동 변환 | Kubernetes Operator 방식 |
| OpenSLO | SLO 선언형 YAML 표준 스펙 | 공급업체 중립적 |
| Nobl9 sloctl | GitLab·GitHub CI 통합 CLI | 상용 플랫폼 연동 |
실전 적용
예시 1: Argo Rollouts 카나리 게이트 — Prometheus SLO 기반 자동 롤백
Argo Rollouts는 Kubernetes-native 롤아웃 컨트롤러로, 카나리 배포의 각 단계에서 AnalysisRun을 생성해 Prometheus 쿼리 결과를 평가합니다. 실패 조건이 충족되면 자동으로 롤백하고 배포를 중단합니다. 서비스 메시 의존성 없이 Kubernetes 클러스터만으로 동작한다는 점이 특징입니다.
# k8s/analysis/slo-analysis-template.yaml
apiVersion: argoproj.io/v1alpha1
kind: AnalysisTemplate
metadata:
name: slo-analysis
namespace: production
spec:
metrics:
- name: error-rate
interval: 60s
successCondition: result[0] < 0.01 # 에러율 1% 미만
failureLimit: 3 # 3회 연속 실패 시 롤백
provider:
prometheus:
address: http://prometheus.monitoring.svc.cluster.local:9090
query: |
sum(rate(http_requests_total{status=~"5.."}[5m]))
/
sum(rate(http_requests_total[5m]))
- name: latency-p99
interval: 60s
successCondition: result[0] < 0.3 # P99 300ms 미만 (초 단위)
failureLimit: 3
provider:
prometheus:
address: http://prometheus.monitoring.svc.cluster.local:9090
query: |
histogram_quantile(0.99,
rate(http_duration_seconds_bucket[5m]))| 필드 | 역할 |
|---|---|
interval |
메트릭 측정 주기 (60초마다 Prometheus 쿼리 실행) |
successCondition |
이 조건을 만족해야 카나리 단계 진행 |
failureLimit |
이 횟수만큼 실패하면 자동 롤백 트리거 |
provider.prometheus.query |
실제 PromQL 쿼리 — SLI 정의의 핵심 |
카나리 트래픽 흐름은 다음과 같이 진행됩니다.
10% 트래픽 전환 → AnalysisRun 실행 → SLO 통과
→ 30% 트래픽 전환 → AnalysisRun 실행 → SLO 통과
→ ... → 100% 전환 완료
(임의 단계에서 SLO 실패 → 즉시 0%로 롤백)실무 팁:
address필드에는 클러스터 내 DNS가 안정적으로 해석되도록http://서비스명.네임스페이스.svc.cluster.local:포트형식의 FQDN을 사용하는 것을 권장합니다. 네임스페이스를 생략한 단축 주소는 크로스-네임스페이스 환경에서 DNS 해석에 실패할 수 있습니다.
예시 2: Sloth + GitHub Actions — PR 단계의 번 레이트 배포 게이트
Sloth로 SLO를 YAML로 정의하고, GitHub Actions에서 Prometheus 번 레이트를 조회해 임계값 초과 시 배포 단계를 차단하는 패턴입니다.
Step 1: Sloth로 SLO 정의
# slo/api-availability.yaml
apiVersion: sloth.slok.dev/v1
kind: PrometheusServiceLevel
metadata:
name: api-availability
namespace: monitoring
spec:
service: "api-service"
slos:
- name: "availability"
objective: 99.9 # 99.9% 가용성 SLO
sli:
events:
error_query: |
sum(rate(http_requests_total{code=~"5.."}[{{.window}}]))
total_query: |
sum(rate(http_requests_total[{{.window}}]))
alerting:
name: APIAvailabilityBurnRate
pageAlert:
labels:
severity: critical
team: platformsloth generate -i slo/api-availability.yaml | kubectl apply -f - 명령을 실행하면 Prometheus Recording Rule과 Alert Rule이 자동으로 생성됩니다.
중요: Sloth가 생성하는 Recording Rule 이름은 버전에 따라 다를 수 있습니다.
kubectl get prometheusrule -n monitoring -o yaml명령으로 실제 생성된 규칙 이름을 확인한 후 아래 GitHub Actions 쿼리에 반영하세요.
Step 2: GitHub Actions 배포 게이트
# .github/workflows/deploy.yml
name: Deploy with Error Budget Gate
on:
push:
branches: [main]
jobs:
check-error-budget:
runs-on: ubuntu-latest
steps:
- name: Check Error Budget Burn Rate
env:
PROMETHEUS: ${{ secrets.PROMETHEUS_URL }}
run: |
BURN_RATE=$(curl -sf "$PROMETHEUS/api/v1/query" \
--data-urlencode \
"query=slo:error_budget_burn_rate:ratio_rate1h" \
| jq -r '.data.result[0].value[1]')
# Prometheus 응답이 없거나 빈 값이면 fail-safe로 차단
if [[ -z "$BURN_RATE" || "$BURN_RATE" == "null" ]]; then
echo "::error::Prometheus에서 번 레이트 값을 가져오지 못했습니다. 배포를 차단합니다."
exit 1
fi
echo "현재 번 레이트: ${BURN_RATE}x"
if (( $(echo "$BURN_RATE > 10" | bc -l) )); then
echo "::error::에러 버짓 번 레이트 ${BURN_RATE}x가 임계값(10x)을 초과했습니다."
echo "::error::배포를 차단합니다. SLO 상태를 확인해주세요."
exit 1
fi
echo "에러 버짓 상태 정상. 배포를 진행합니다."
deploy:
needs: check-error-budget # 게이트 통과 후에만 실행
runs-on: ubuntu-latest
steps:
- name: Deploy to Kubernetes
run: kubectl apply -f k8s/용어 보충:
slo:error_budget_burn_rate:ratio_rate1h는 Sloth가 자동 생성하는 Recording Rule 이름 예시입니다. Recording Rule은 복잡한 PromQL 계산 결과를 사전에 저장해 쿼리 성능을 높이는 Prometheus 기능입니다. 빈 값 검사 가드([[ -z "$BURN_RATE" ]])는 게이트가 오류 상황에서 자동으로 열려버리는(fail-open) 문제를 방지하는 필수 안전 장치입니다.
예시 3: Flagger + Istio — 서비스 메시 기반 자동 카나리
전제 조건: 이 예시는 클러스터에 Istio 서비스 메시가 설치되어 있는 경우에만 해당합니다. 서비스 메시를 사용하지 않는 환경이라면 예시 1(Argo Rollouts)을 참고하세요.
두 도구는 같은 역할(카나리 SLO 게이트)을 하지만 접근 방식이 다릅니다. 환경에 맞는 도구를 선택하는 데 참고할 수 있습니다.
| 구분 | Argo Rollouts | Flagger |
|---|---|---|
| 의존성 | Kubernetes만 필요 | Istio, Linkerd 등 서비스 메시 필요 |
| 트래픽 제어 | Rollout 리소스로 직접 제어 | VirtualService 자동 생성으로 제어 |
| 생태계 통합 | Argo CD와 긴밀하게 통합 | Flux CD와 기본 통합 |
| 적합한 환경 | 서비스 메시 없는 Kubernetes 환경 | Istio/Linkerd 기반 마이크로서비스 환경 |
Flagger는 Canary 오브젝트를 감지하면 Istio VirtualService를 자동으로 생성해 트래픽을 점진적으로 이동시킵니다. 각 단계에서 Prometheus 메트릭을 측정하고, 임계값 초과 시 즉시 원래 버전으로 복원합니다.
# canary/api-canary.yaml
apiVersion: flagger.app/v1beta1
kind: Canary
metadata:
name: api-service
namespace: production
spec:
targetRef:
apiVersion: apps/v1
kind: Deployment
name: api-service
service:
port: 80
analysis:
interval: 1m # 1분마다 분석
threshold: 5 # 5회 실패 시 롤백
maxWeight: 50 # 최대 50% 카나리 트래픽
stepWeight: 10 # 10%씩 점진 증가
metrics:
- name: request-success-rate
thresholdRange:
min: 99 # 성공률 99% 이상 (백분율 기준, 0~100 범위)
interval: 1m
- name: request-duration
thresholdRange:
max: 500 # P99 지연시간 500ms 이하 (밀리초 기준)
interval: 1m| 단계 | 트래픽 비율 | 동작 |
|---|---|---|
| 1단계 | 10% | Prometheus 메트릭 측정, SLO 평가 |
| 2단계 | 20% | 이전 단계 통과 후 트래픽 증가 |
| ... | ... | 반복 |
| 최종 성공 | 100% | 카나리 → 프라이머리로 완전 전환 |
| 실패 시 | 0% | 즉시 롤백, Kubernetes 이벤트 기록 |
단위 주의:
request-success-rate의thresholdRange.min: 99는 Flagger 내장 메트릭 기준으로 백분율(%)입니다. 커스텀 메트릭을 직접 정의할 때는 PromQL 쿼리가 반환하는 값의 단위(소수점 비율 vs 백분율)를 반드시 확인하고 임계값을 설정하세요.
예시 4: 다중 윈도우 번 레이트 알림 — Google SRE 권장 패턴
단일 짧은 윈도우만 사용하면 일시적 스파이크에 반응하거나(노이즈), 장기 저하를 놓치는(느린 반응) 문제가 발생합니다. Google SRE Workbook은 짧은 윈도우와 긴 윈도우를 AND 조건으로 결합해 두 가지 패턴을 모두 감지하는 방식을 권장합니다.
# prometheus/slo-alerts.yaml
groups:
- name: slo.rules
rules:
# 패스트 번 알림: 1시간 + 5분 윈도우 조합
- alert: ErrorBudgetFastBurn
expr: |
(
slo:error_budget_burn_rate:ratio_rate1h > 14.4
and
slo:error_budget_burn_rate:ratio_rate5m > 14.4
)
for: 2m
labels:
severity: critical
annotations:
summary: "패스트 번 감지: 번 레이트 {{ $value }}x"
description: "현재 속도로 계속되면 5일 내 월간 버짓 소진"
# 슬로우 번 알림: 6시간 + 30분 윈도우 조합
- alert: ErrorBudgetSlowBurn
expr: |
(
slo:error_budget_burn_rate:ratio_rate6h > 6
and
slo:error_budget_burn_rate:ratio_rate30m > 6
)
for: 15m
labels:
severity: warning
annotations:
summary: "슬로우 번 감지: 번 레이트 {{ $value }}x"
description: "장기간 낮은 번 레이트가 지속되어 버짓이 조용히 소진 중"| 알림 유형 | 윈도우 조합 | 임계값 | 감지 대상 |
|---|---|---|---|
| 패스트 번 | 1h + 5m | 14.4x | 급격한 장애, 즉각 대응 필요 |
| 슬로우 번 | 6h + 30m | 6x | 장기 지속되는 낮은 수준의 성능 저하 |
용어 보충: 슬로우 번(Slow Burn) 은 번 레이트가 낮지만 장기간 지속되어 조용히 버짓을 소진하는 패턴입니다. 짧은 윈도우만으로는 감지하기 어렵기 때문에 6시간 이상의 긴 윈도우와 함께 AND 조건으로 사용하는 것을 권장합니다.
장단점 분석
장점
| 항목 | 내용 |
|---|---|
| 자동화된 신뢰성 보호 | 야간·주말에도 사람의 판단 없이 SLO 위반 시 배포 자동 차단 |
| 개발 속도와 안정성 균형 | 버짓이 충분할 때는 빠른 배포, 위험 시 자동 제동 |
| 팀 간 객관적 기준 | 배포 가능 여부가 주관적 판단이 아닌 데이터 기반 결정으로 전환 |
| 감사 추적 가능 | GitOps 환경에서 모든 배포 결정이 Git 이력으로 기록됨 |
| 점진적 위험 완화 | Progressive Delivery와 결합 시 프로덕션 위험 최소화 |
단점 및 주의사항
| 항목 | 내용 | 대응 방안 |
|---|---|---|
| 오탐(False Positive) | 너무 엄격한 임계값은 정상 배포도 차단 | 번 레이트 임계값을 점진적으로 조정, 초기에는 경고만 발생 |
| 초기 구축 복잡도 | Prometheus, Argo Rollouts, 알림 규칙 등 인프라 투자 필요 | Sloth/Pyrra로 보일러플레이트 최소화 |
| 잘못된 SLI 정의 | 잘못된 SLI는 전체 게이트 시스템을 무의미하게 만듦 | SLI 정의 전 팀 전체 리뷰 및 문서화 필수 |
| 윈도우 선택 문제 | 짧은 윈도우는 노이즈, 긴 윈도우는 느린 반응 | Google SRE 권장 다중 윈도우 조합 활용 |
용어 보충: SLI(Service Level Indicator) 는 실제로 측정되는 지표(예: HTTP 성공률, P99 지연시간)이며, SLO 는 이 SLI가 달성해야 할 목표값(예: 성공률 99.9% 이상)입니다. SLI가 잘못 정의되면 SLO도, 번 레이트 계산도 모두 의미를 잃습니다.
도입 시 팀 내 준비사항
에러 버짓 정책 자동화는 기술적 구성만으로 완성되지 않습니다. 자동 배포 차단이 팀에 실질적인 효과를 내려면 다음과 같은 조직적 준비가 선행되어야 합니다.
- SLO 목표값 합의: 서비스 오너·제품팀과 현실적인 SLO 수치를 먼저 합의하는 것이 중요합니다. 합의 없이 기술 구성만 먼저 진행하면 자동 차단이 발동될 때마다 팀 내 갈등이 생깁니다.
- 핫픽스 예외 경로 문서화: 보안 패치나 P0 장애 대응 배포까지 게이트가 차단하면 오히려 더 큰 장애로 이어질 수 있습니다. 게이트 우회 절차(예: 특정 Git 태그 또는 레이블 사용)를 팀이 합의해 문서화해두는 것이 중요합니다.
- 점진적 문화 적응: 처음에는 차단 대신 경고 알림만 발생하도록 구성하고, 팀이 데이터에 익숙해진 후에 실제 차단 정책으로 전환하는 것을 권장합니다.
실무에서 가장 흔한 실수
-
SLO 목표값을 너무 높게 설정하는 것 — 99.999%와 같은 목표는 월간 에러 버짓이 26초에 불과해 버짓이 항상 소진 상태가 됩니다. 현실적인 목표값(99.5%~99.9%)부터 시작하는 것을 권장합니다.
-
번 레이트 체크에 fail-safe 가드를 생략하는 것 — Prometheus가 응답하지 않거나 쿼리 결과가 비어 있을 때 게이트가 자동으로 열려버리는(fail-open) 버그가 발생할 수 있습니다. 예시 2의 빈 값 검사 가드(
[[ -z "$BURN_RATE" ]])를 반드시 포함하세요. -
단일 짧은 윈도우만 사용하는 것 — 5분 윈도우만 모니터링하면 일시적 스파이크에도 게이트가 트리거되어 신뢰성이 떨어집니다. Google SRE Workbook 권장대로 1h+5m(패스트 번)과 6h+30m(슬로우 번) 조합을 사용하는 것이 좋습니다.
마치며
에러 버짓 정책 자동화의 핵심은 "배포 가능 여부"를 팀의 암묵적 판단에서 시스템이 집행하는 객관적 계약으로 전환하는 것입니다. 이 전환은 하루아침에 이루어지지 않지만, 작은 곳에서부터 시작해 점진적으로 확장해 나갈 수 있습니다.
지금 바로 시작해볼 수 있는 단계:
-
서비스 오너·제품팀과 현실적 SLO 목표값을 먼저 합의하세요. 99.9% vs 99.5% 중 어느 수준이 팀의 배포 속도와 비즈니스 요구 사이에서 균형을 맞추는지 논의하는 것이 기술 구성보다 선행되어야 합니다.
-
기존 서비스에서 SLI 하나를 정의하고 2주간 관찰해보세요.
sum(rate(http_requests_total{status=~"5.."}[5m])) / sum(rate(http_requests_total[5m]))쿼리를 Grafana 대시보드에 추가하면, 현실적인 SLO 목표값 설정의 기준이 되는 실측 데이터를 확보할 수 있습니다. -
Sloth로 SLO를 YAML로 코드화하고 Git에 커밋해보세요.
sloth generate -i slo/api-availability.yaml | kubectl apply -f -명령 하나로 Prometheus Recording Rule과 Alert Rule이 자동 생성되는 과정을 직접 확인해보실 수 있습니다. -
기존 CI/CD 파이프라인에 번 레이트 체크 단계를 추가하되, 처음에는
exit 1대신 경고 메시지만 출력하도록 구성해보세요. 팀이 데이터에 익숙해진 후 실제 차단 정책으로 전환하면 문화적 저항을 최소화하면서 자동화를 도입할 수 있습니다.
다음 글 (연재 예정): Argo Rollouts의
AnalysisTemplate을 활용해 카나리 배포에서 A/B 테스트와 SLO 기반 자동 롤백을 동시에 구현하는 Progressive Delivery 심화 가이드
참고 자료
- Google SRE Workbook — Error Budget Policy
- Google SRE Workbook — Alerting on SLOs (Prometheus)
- Google SRE Workbook — Implementing SLOs
- Argo Rollouts — Analysis & Progressive Delivery 공식 문서
- Argo Rollouts — Prometheus Analysis 공식 문서
- Flagger 공식 문서
- Flagger — Istio Canary Deployments 튜토리얼
- GitHub — slok/sloth: Prometheus SLO Generator
- GitHub — pyrra-dev/pyrra: SLOs with Prometheus
- Nobl9 — CI/CD Integration Guide
- OpenSLO 스펙 문서 (Nobl9)
- Datadog — Burn Rate Alerts 공식 문서
- GitOps in 2025: From Old-School Updates to the Modern Way | CNCF
- Error Budgets 2.0 — Agentic AI for SLO-Apprehensive Deployment | DZone
- Error Budgets in Practice: A Data-Driven Approach | DEV Community
- GitOps using Flux and Flagger | InfraCloud