Terraform grafana_slo로 SLO-as-Code 구현하기: GitOps 파이프라인 단계별 구현
태그: DevOps / 인프라 / SRE / Observability
"이 SLO가 언제, 왜 바뀌었지?" — 온콜 중에 이 질문에 아무도 답할 수 없다면, SLO가 UI 어딘가에 조용히 존재한다는 신호입니다. UI는 SLO의 무덤입니다 — 변경 이력도, 리뷰도, 롤백도 없는. SLO는 팀이 지켜야 할 신뢰성 계약인데, 그 계약서가 클릭 몇 번에 수정될 수 있다면 신뢰 기반의 SRE 문화를 만들기 어렵습니다.
SLO-as-Code는 이 계약서를 Git에 올리고, PR로 검토하고, CI/CD로 배포함으로써 SLO 관리의 투명성과 일관성을 확보하는 접근 방식입니다. Grafana의 공식 Terraform 프로바이더(grafana/grafana)가 제공하는 grafana_slo 리소스를 활용하면 SLI 쿼리, 목표값, 경보 규칙을 HCL 코드로 선언적으로 정의하고 버전 관리할 수 있습니다.
이 글에서 다루는 내용:
grafana_slo의 핵심 쿼리 타입과 SLO 구성 요소- 재사용 가능한 Terraform 모듈 설계와 환경별 관리
- PR 자동 플랜과 순차 배포를 포함한 GitHub Actions GitOps 파이프라인
- 기존 UI SLO를 코드로 전환하는 마이그레이션 절차
- Knowledge Graph 연동 등 고급 기능 활용법
사전 지식: Terraform 기본 문법(리소스, 변수, 모듈)과 PromQL 기초 지식이 있다면 약 1시간 안에 파이프라인을 구성할 수 있습니다. 완전 입문자라면 HashiCorp의 Terraform Get Started 튜토리얼을 먼저 살펴보시는 것을 권장합니다.
핵심 개념
SLO를 구성하는 네 가지 핵심 요소
SLO-as-Code를 작성하기 전에 SLO를 구성하는 개념을 명확히 이해하는 것이 도움이 됩니다.
| 개념 | 설명 | 예시 |
|---|---|---|
| SLI (Service Level Indicator) | 서비스 품질을 측정하는 지표 | HTTP 5xx 제외 성공 요청 비율 |
| SLO (Service Level Objective) | SLI에 대한 목표값 | 99.9% 가용성을 30일간 유지 |
| Error Budget | 1 - SLO 목표값으로 허용 가능한 오류 여유분 |
99.9% SLO → 0.1% (월 43.2분) |
| Burn Rate | 에러 버짓이 소진되는 속도 | Burn Rate 2 = 15일 만에 버짓 소진 |
Burn Rate란? Burn Rate 1은 30일 준수 기간 동안 에러 버짓이 정확히 소진되는 속도입니다. Burn Rate가 2라면 버짓의 절반인 15일 만에 소진되므로 즉각적인 대응이 필요합니다.
grafana_slo가 지원하는 SLI 쿼리 타입
Grafana는 SLI를 정의하는 네 가지 쿼리 타입을 제공합니다.
| 타입 | 설명 | 적합한 경우 |
|---|---|---|
ratio |
성공 요청 / 전체 요청 비율 | HTTP 가용성, 에러율 측정 |
freeform |
임의 PromQL 표현식 | 지연시간, 복합 조건 측정 |
threshold |
임계값 기반 측정 | 특정 값 초과 여부 판단 |
grafana_queries |
Grafana 패널 쿼리 재활용 | 기존 대시보드 쿼리 연동 |
grafana_queries 타입은 이미 만들어진 대시보드 패널 쿼리를 SLI로 그대로 재활용할 수 있어, 초기 마이그레이션 시 유용합니다.
# grafana_queries 타입: 기존 대시보드 패널 쿼리를 SLI로 재활용
resource "grafana_slo" "panel_query_slo" {
name = "Checkout API Availability (Dashboard Query)"
description = "기존 대시보드 패널 쿼리를 SLI로 재활용"
query {
type = "grafana_queries"
grafana_queries {
success_query {
query_type = "instant"
ref_id = "A"
expr = "sum(http_requests_total{service=\"checkout\",status!~\"5..\"})"
}
total_query {
query_type = "instant"
ref_id = "B"
expr = "sum(http_requests_total{service=\"checkout\"})"
}
}
}
objectives {
value = 0.999
window = "30d"
}
destination_datasource {
uid = var.datasource_uid
}
}Multi-window Alerting 구조
Grafana SLO 경보는 Google SRE Workbook에서 제안한 다중 윈도우 방식을 따릅니다.
Multi-window Alerting: 짧은 시간 내 에러 버짓을 급격히 소진하는 fastburn(심각도: critical)과, 낮은 속도로 꾸준히 소진하는 slowburn(심각도: warning)을 동시에 감지합니다. 두 조건을 모두 충족할 때만 알람이 발생하므로 오탐(false positive)을 대폭 줄일 수 있습니다.
grafana_slo 리소스 기본 구조
이제 개념을 이해했으니, 실제 grafana_slo 리소스를 살펴보겠습니다.
grafana_slo 리소스는 SLI 쿼리, 목표값, 데이터소스, 레이블, 경보를 하나의 블록에서 정의합니다. destination_datasource.uid를 하드코딩하기보다 data "grafana_data_source" 블록으로 동적 참조하는 것이 모범 사례입니다. 하드코딩된 UID는 환경 이전이나 데이터소스 재생성 시 오류 원인이 됩니다.
terraform {
required_providers {
grafana = {
source = "grafana/grafana"
version = ">= 3.5.0"
}
}
}
provider "grafana" {
url = var.grafana_url
auth = var.grafana_service_account_token
}
# 데이터소스를 동적으로 참조 (하드코딩 대신 권장)
data "grafana_data_source" "prometheus" {
name = "grafanacloud-prom"
}
# Ratio 방식: HTTP 가용성 SLO
resource "grafana_slo" "api_availability" {
name = "API Availability SLO"
description = "HTTP 5xx 제외 성공 요청 비율"
query {
type = "ratio"
ratio {
success_metric = "http_requests_total{status!~\"5..\"}"
total_metric = "http_requests_total"
group_by_labels = ["service", "env"]
}
}
objectives {
value = 0.999
window = "30d"
}
destination_datasource {
uid = data.grafana_data_source.prometheus.uid
}
label {
key = "team"
value = "platform"
}
alerting {
fastburn {
annotation {
key = "summary"
value = "에러 버짓 급속 소진 중"
}
label {
key = "severity"
value = "critical"
}
}
slowburn {
annotation {
key = "summary"
value = "에러 버짓 지속 소진 중"
}
label {
key = "severity"
value = "warning"
}
}
}
}grafana_slo 리소스를 생성하면 Grafana가 자동으로 Recording Rules(SLI 집계용 Prometheus 규칙), 에러 버짓 대시보드, fastburn/slowburn 알람 규칙을 생성합니다. 이 자동 생성 리소스들은 Terraform이 직접 관리하지 않으므로 SLO 삭제 시 함께 정리됩니다.
지연시간처럼 ratio 방식으로 표현하기 어려운 SLI는 freeform 타입으로 정의할 수 있습니다.
# Freeform 방식: P99 지연시간 SLO
resource "grafana_slo" "latency_slo" {
name = "API P99 지연시간 SLO"
description = "P99 응답시간 200ms 이하 유지"
query {
type = "freeform"
freeform {
query = "sum(rate(http_request_duration_seconds_bucket{le=\"0.2\"}[$__rate_interval])) / sum(rate(http_request_duration_seconds_count[$__rate_interval]))"
}
}
objectives {
value = 0.95
window = "7d"
}
destination_datasource {
uid = data.grafana_data_source.prometheus.uid
}
}
$__rate_interval과 freeform 쿼리:$__rate_interval은 Grafana가 제공하는 내장 변수로, 스크레이프 간격에 맞게rate()계산 범위를 자동 조정합니다.terraform apply시 Grafana 백엔드는 이 변수를 SLO 엔진이 내부적으로 사용하는 평가 윈도우(예: 5분, 30분)로 런타임에 치환합니다. 단,promtool이나curl /api/v1/query처럼 Grafana 외부 도구로 쿼리를 직접 실행하면 이 변수가 치환되지 않아 오류가 발생합니다. 코드화 전에 반드시 Grafana Explore 패널에서 쿼리를 먼저 검증하는 것을 권장합니다.
실전 적용
개념을 이해했으니 이제 실제 코드를 작성해 보겠습니다. 기본 모듈 설계부터 CI/CD 파이프라인, 마이그레이션까지 단계별로 살펴봅니다.
예시 1: 재사용 가능한 SLO 모듈 설계
여러 서비스의 SLO를 관리할 때는 grafana_slo 리소스를 직접 반복 작성하기보다 Terraform 모듈로 추상화하는 것을 권장합니다. 플랫폼 팀이 모듈을 제공하고, 개발 팀이 변수만 채워 SLO를 셀프서비스로 생성하는 패턴입니다.
디렉토리 구조:
slo-gitops/
├── modules/
│ └── grafana-slo/
│ ├── main.tf # grafana_slo 리소스 정의
│ ├── variables.tf # 입력 변수 선언
│ └── outputs.tf # 출력값 선언
├── envs/
│ ├── staging/
│ │ ├── backend.tf # S3 원격 상태 설정
│ │ ├── main.tf
│ │ └── terraform.tfvars
│ └── production/
│ ├── backend.tf
│ ├── main.tf
│ └── terraform.tfvars
└── .github/
└── workflows/
└── slo-deploy.yml모듈 변수 선언 (modules/grafana-slo/variables.tf):
variable "service_name" {
type = string
description = "SLO 이름에 사용할 서비스 식별자"
}
variable "team" {
type = string
description = "담당 팀 이름 (레이블 및 설명에 사용)"
}
variable "slo_target" {
type = number
default = 0.999
description = "SLO 목표값 (0.0 ~ 1.0)"
}
variable "success_metric" {
type = string
description = "성공 요청을 나타내는 PromQL 메트릭"
}
variable "total_metric" {
type = string
description = "전체 요청을 나타내는 PromQL 메트릭"
}
variable "datasource_uid" {
type = string
description = "Prometheus 데이터소스 UID"
}모듈 리소스 정의 (modules/grafana-slo/main.tf):
resource "grafana_slo" "this" {
name = "${var.service_name} Availability"
description = "Managed by Terraform - team: ${var.team}"
query {
type = "ratio"
ratio {
success_metric = var.success_metric
total_metric = var.total_metric
}
}
objectives {
value = var.slo_target
window = "30d"
}
destination_datasource {
uid = var.datasource_uid
}
label {
key = "team"
value = var.team
}
label {
key = "managed"
value = "terraform"
}
alerting {
fastburn {
label {
key = "severity"
value = "critical"
}
}
slowburn {
label {
key = "severity"
value = "warning"
}
}
}
}모듈 출력값 (modules/grafana-slo/outputs.tf):
output "slo_id" {
value = grafana_slo.this.id
description = "생성된 SLO의 UUID"
}
output "slo_name" {
value = grafana_slo.this.name
description = "생성된 SLO의 이름"
}S3 백엔드 설정 (envs/production/backend.tf):
terraform {
backend "s3" {
bucket = "my-terraform-state"
key = "slo/production/terraform.tfstate"
region = "ap-northeast-2"
encrypt = true
# Terraform 1.9 이하: DynamoDB 잠금 사용
dynamodb_table = "terraform-lock"
# Terraform 1.10+: 네이티브 S3 잠금 (위 dynamodb_table 대신 사용 가능)
# use_lockfile = true
}
}Terraform State: Terraform이 관리하는 인프라의 현재 상태를 저장하는 파일입니다. Terraform 1.9 이하에서는 동시 수정 방지를 위해 DynamoDB 잠금이 필수였지만, 1.10부터
use_lockfile = true옵션으로 S3 네이티브 잠금을 사용할 수 있어 DynamoDB 테이블이 불필요해졌습니다. 어떤 방식을 선택하든 원격 백엔드 구성은 팀 협업의 첫 번째 단계입니다.
프로덕션 환경에서 모듈 호출 (envs/production/main.tf):
data "grafana_data_source" "prometheus" {
name = "grafanacloud-prom"
}
module "checkout_slo" {
source = "../../modules/grafana-slo"
service_name = "checkout-api"
team = "payments"
slo_target = 0.999
success_metric = "http_requests_total{service=\"checkout\",status!~\"5..\"}"
total_metric = "http_requests_total{service=\"checkout\"}"
datasource_uid = data.grafana_data_source.prometheus.uid
}
module "auth_slo" {
source = "../../modules/grafana-slo"
service_name = "auth-service"
team = "identity"
slo_target = 0.9995
success_metric = "http_requests_total{service=\"auth\",status!~\"5..\"}"
total_metric = "http_requests_total{service=\"auth\"}"
datasource_uid = data.grafana_data_source.prometheus.uid
}PromQL 메트릭 이름 확인 방법:
success_metric과total_metric에 들어갈 메트릭 이름은 서비스마다 다릅니다.kubectl exec -it <pod> -- curl localhost:8080/metrics또는 Grafana Explore 패널에서 실제 메트릭을 조회한 후 코드에 반영하는 것을 권장합니다.
| 구성 요소 | 역할 |
|---|---|
variables.tf 분리 |
변수 정의와 리소스 로직을 분리해 모듈 재사용성 향상 |
outputs.tf 분리 |
SLO ID를 다른 모듈(알람, 대시보드)에서 참조 가능 |
backend.tf 분리 |
환경별 상태 파일 경로를 명확하게 관리 |
managed = "terraform" 레이블 |
UI에서 무단 변경된 SLO를 식별하는 가드레일 |
예시 2: GitHub Actions GitOps 파이프라인
PR이 열리면 staging/production 각각에 대해 terraform plan을 실행해 변경 내역을 PR 코멘트로 게시하고, main 브랜치에 머지되면 staging → production 순으로 순차 배포되는 파이프라인입니다.
name: SLO Deploy
on:
push:
branches: [main]
paths: ["envs/**", "modules/**"]
pull_request:
branches: [main]
paths: ["envs/**", "modules/**"]
env:
TF_VAR_grafana_url: ${{ secrets.GRAFANA_URL }}
TF_VAR_grafana_token: ${{ secrets.GRAFANA_SERVICE_ACCOUNT_TOKEN }}
jobs:
plan:
runs-on: ubuntu-latest
if: github.event_name == 'pull_request'
strategy:
matrix:
env: [staging, production]
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
with:
terraform_version: "1.9.x"
- name: Configure AWS Credentials (S3 backend)
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ap-northeast-2
- name: Terraform Init
run: terraform init
working-directory: envs/${{ matrix.env }}
- name: Terraform Plan
id: plan
run: |
terraform plan -no-color -out=tfplan
terraform show -no-color tfplan > plan_output.txt
working-directory: envs/${{ matrix.env }}
- name: Comment Plan on PR
uses: actions/github-script@v7
with:
script: |
const fs = require('fs');
let output = fs.readFileSync('envs/${{ matrix.env }}/plan_output.txt', 'utf8');
// GitHub PR 코멘트는 65,536자 제한이 있으므로 초과 시 잘라냄
if (output.length > 60000) {
output = output.substring(0, 60000) + '\n...(출력이 길어 잘렸습니다. 전체 내용은 Actions 로그를 확인하세요)';
}
const body = `#### Terraform Plan — ${{ matrix.env }}\n\`\`\`\n${output}\n\`\`\``;
github.rest.issues.createComment({
issue_number: context.issue.number,
owner: context.repo.owner,
repo: context.repo.repo,
body: body
});
# Staging 먼저 적용
apply-staging:
runs-on: ubuntu-latest
if: github.ref == 'refs/heads/main' && github.event_name == 'push'
environment: staging
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ap-northeast-2
- run: terraform init
working-directory: envs/staging
- run: terraform apply -auto-approve
working-directory: envs/staging
# Staging 성공 후 Production 적용 (순차 배포)
apply-production:
runs-on: ubuntu-latest
needs: apply-staging
environment: production
steps:
- uses: actions/checkout@v4
- uses: hashicorp/setup-terraform@v3
- name: Configure AWS Credentials
uses: aws-actions/configure-aws-credentials@v4
with:
role-to-assume: ${{ secrets.AWS_ROLE_ARN }}
aws-region: ap-northeast-2
- run: terraform init
working-directory: envs/production
- run: terraform apply -auto-approve
working-directory: envs/production
environment: production: GitHub Actions의 Environment Protection Rules를 활용하면 특정 Reviewer의 승인 없이 apply가 실행되지 않도록 추가 게이트를 설정할 수 있습니다. SLO 목표값 변경처럼 민감한 변경에 특히 유용합니다.
AWS 외 환경 사용 시: S3 백엔드 대신 Terraform Cloud HCP를 사용한다면
AWS_ROLE_ARN시크릿 대신TFE_TOKEN을 사용하고hashicorp/setup-terraform액션의cli_config_credentials_token을 설정할 수 있습니다. GCS(Google Cloud Storage) 백엔드를 사용하는 경우에는google-github-actions/auth액션으로 인증을 구성할 수 있습니다.
예시 3: 기존 UI SLO를 코드로 마이그레이션
Grafana는 2025년부터 UI에서 생성한 SLO를 HCL 형식으로 내보내는 기능을 공식 지원합니다. "UI 먼저 → 코드로 이전"하는 Brownfield 전환 경로가 공식화된 것입니다.
# 1단계: 기존 SLO를 HCL 형식으로 내보내기
curl -H "Authorization: Bearer $GRAFANA_TOKEN" \
"https://your-org.grafana.net/api/plugins/grafana-slo-app/resources/v1/slo?format=hcl" \
-o existing_slos.tf
# 또는 Grafana UI에서: SLO 상세 페이지 → More > Export
# 2단계: Terraform state에 기존 SLO 등록 (재생성 없이 관리 시작)
terraform import grafana_slo.api_availability <SLO_UUID>
# 3단계: plan으로 코드와 실제 상태의 drift 확인
terraform plan내보낸 HCL을 모듈 구조에 맞게 리팩터링한 후 terraform import로 state에 등록하면, 기존 SLO를 삭제·재생성하지 않고 코드 관리를 시작할 수 있습니다.
고급 주제
Knowledge Graph SLO 연동 (2025~2026 신기능)
기본 기능을 익혔다면, Grafana의 Knowledge Graph 연동으로 더 풍부한 SLO 컨텍스트를 활용할 수 있습니다.
GA 상태 안내: Knowledge Graph SLO 연동은
grafana/grafana프로바이더 v3.7.0 이상이 필요하며, Grafana Cloud의 Asserts 기능이 활성화된 환경에서만 동작합니다.search_expression속성은 현재 GA(Generally Available) 단계이지만, 지원 범위가 Grafana Cloud로 제한될 수 있으므로 자체 호스팅 환경에서 사용하기 전에 공식 문서에서 최신 지원 범위를 확인하는 것을 권장합니다.
grafana_slo_provenance = "asserts" 레이블을 추가하면 SLO가 특정 서비스 엔티티에 연결되어, 알람 발생 시 RCA Workbench로 직접 이동해 근본 원인 분석을 수행할 수 있습니다.
# grafana/grafana provider >= 3.7.0 필요, Asserts 기능 활성화 환경에서만 동작
resource "grafana_slo" "entity_slo" {
name = "Checkout API Availability (Knowledge Graph)"
description = "Knowledge Graph 연동 SLO"
query {
type = "ratio"
ratio {
success_metric = "http_requests_total{service=\"checkout\",status!~\"5..\"}"
total_metric = "http_requests_total{service=\"checkout\"}"
}
}
objectives {
value = 0.999
window = "30d"
}
destination_datasource {
uid = data.grafana_data_source.prometheus.uid
}
label {
key = "grafana_slo_provenance"
value = "asserts"
}
# 연결할 서비스 엔티티 지정 (provider >= 3.7.0, Asserts 활성화 필요)
search_expression = "service.name=\"checkout-api\" AND environment=\"production\""
}장단점 분석
장점
| 항목 | 내용 |
|---|---|
| 버전 관리 | SLO 변경 이력이 Git 히스토리로 추적되어 언제, 왜 변경됐는지 감사 가능 |
| 리뷰 프로세스 | PR 기반 코드 리뷰로 SLO 목표값·쿼리 변경 시 팀 승인 절차 자동화 |
| 환경 일관성 | staging/production SLO를 동일 모듈로 관리해 환경 간 설정 불일치 방지 |
| 셀프서비스 | Terraform 모듈 추상화로 개발팀이 플랫폼팀 의존 없이 SLO 생성 가능 |
| Drift 감지 | terraform plan으로 UI에서의 무단 변경을 즉시 탐지 |
| 자동화 | CI/CD로 배포 자동화, 수동 클릭 실수 제거 |
단점 및 주의사항
| 항목 | 내용 | 대응 방안 |
|---|---|---|
| 러닝 커브 | Terraform 및 PromQL에 익숙하지 않은 팀은 초기 학습 비용 발생 | 재사용 모듈 제공 + 내부 가이드 문서화 |
| 상태 파일 관리 | Terraform state에 민감 정보가 포함될 수 있음 | S3 암호화 + DynamoDB 잠금(또는 1.10+ use_lockfile) 구성 필수 |
| UI 동기화 문제 | UI에서 직접 수정하면 코드와 실제 상태가 diverge | 팀 규칙으로 UI 직접 수정 금지, managed=terraform 레이블로 식별 |
| PromQL 복잡성 | $__rate_interval 같은 내장 변수는 Grafana 외부에서 테스트 불가 |
Grafana Explore에서 쿼리 검증 후 코드화 |
| 자동 생성 리소스 | 대시보드·알람 규칙은 Terraform이 직접 관리하지 않음 | SLO 삭제 전 자동 생성 리소스 영향 확인 |
| Grafana Cloud 종속 | SLO 플러그인이 활성화된 환경에서만 동작 | 자체 호스팅 시 grafana-slo-app 플러그인 활성화 필요. 플러그인 지원 범위가 Cloud와 다를 수 있으므로 공식 플러그인 문서에서 기능 가용성을 확인하는 것을 권장합니다 |
| 멀티 환경 복잡도 | 수십 개 서비스 SLO 관리 시 모듈 설계가 복잡해짐 | 네이밍 컨벤션·디렉토리 구조 사전 정의 권장 |
⚠️ 실무에서 가장 흔한 실수
아래 세 가지는 실제 운영 환경에서 가장 자주 발생하는 문제입니다. 미리 인지하고 팀 내 규칙으로 만들어두면 온콜 피로를 줄일 수 있습니다.
-
로컬 state 파일 사용:
terraform.tfstate를 로컬에 두면 팀원 간 상태 불일치가 발생합니다. 프로젝트 시작 시 원격 백엔드(backend.tf)를 가장 먼저 구성하는 것을 권장합니다. -
UI에서 임시 수정 후 코드 반영 누락: 인시던트 대응 중 UI에서 SLO를 변경하고 코드 반영을 잊으면 다음
terraform apply시 변경이 되돌아갑니다.terraform plan을 정기적으로 실행해 drift를 조기에 감지하는 것이 중요합니다. -
모든 서비스에 동일한 SLO 목표값 적용: 99.9%가 항상 정답이 아닙니다. 서비스 중요도, 에러 버짓 소화 이력을 바탕으로 서비스별 목표값을 차별화하는 것을 권장합니다.
slo_target변수를 서비스별로 다르게 설정하는 것이 바로 이를 위한 것입니다.
마치며
SLO 변경에 팀 전체가 서명하는 문화를 만드는 것 — SLO-as-Code는 그 첫 걸음입니다. 신뢰성 목표를 코드로 선언하고, PR로 검토하고, CI/CD로 배포함으로써 SLO 관리의 투명성과 팀 간 신뢰를 동시에 확보할 수 있습니다.
지금 바로 시작할 수 있는 3단계:
-
(약 5분) 기존 SLO를 HCL로 내보내기 —
curl "https://your-org.grafana.net/api/plugins/grafana-slo-app/resources/v1/slo?format=hcl" -H "Authorization: Bearer $GRAFANA_TOKEN" -o existing_slos.tf명령으로 현재 SLO를 코드로 추출해볼 수 있습니다. Grafana UI에서 SLO를 열고More > Export를 클릭하는 방법도 있습니다. -
(약 30분) 재사용 모듈 구성 및 import — 위 예시의
modules/grafana-slo구조를 참고해 모듈을 작성한 뒤,terraform import grafana_slo.<name> <SLO_UUID>명령으로 기존 SLO를 state에 등록하고terraform plan으로 drift가 없는지 확인해볼 수 있습니다. -
(약 20분) GitHub Actions 워크플로 추가 — 레포지토리에
.github/workflows/slo-deploy.yml을 추가하고GRAFANA_URL,GRAFANA_SERVICE_ACCOUNT_TOKEN,AWS_ROLE_ARN시크릿을 등록하면, PR마다 plan 결과가 자동으로 코멘트로 게시되는 GitOps 파이프라인이 바로 활성화됩니다.
이 시리즈의 다른 글
다음 글: Sloth와 pyrra를 활용한 Kubernetes 네이티브 SLO 관리 — Prometheus Operator와 CRD 기반 접근 방식을 Grafana SLO와 비교해봅니다.
참고 자료
처음 시작한다면 아래 두 가지를 먼저 살펴보는 것을 권장합니다:
- ⭐ grafana_slo Resource | Terraform Registry — 리소스 스키마의 공식 레퍼런스
- ⭐ Provision SLO resources using Terraform | Grafana Cloud 공식 문서 — 공식 설정 가이드
추가 자료:
- Configure Knowledge Graph SLOs using Terraform | Grafana 공식 문서
- Export Grafana SLOs into HCL Format | Grafana What's New (2025)
- Best Practices for Grafana SLOs | Grafana Cloud 문서
- Alerting on SLOs | Google SRE Workbook
- Automate Terraform with GitHub Actions | HashiCorp Developer
- How to Use Terraform with GitOps | Spacelift
- grafana-slo-app Plugin 문서 — Terraform 프로비저닝