LabHub
배우기 러닝패스 코스

Grafana Dashboards

One Vertical Line Saves Thirty Minutes of Investigation

LabHub 에서 이어서 보기

한국어 원문으로 표시합니다.

목표

오류율 패널 하나짜리 대시보드에 배포와 장애를 주석으로 올려, 그래프가 '언제' 뿐 아니라 '그 때 무슨 일이 있었나' 까지 답하게 만듭니다. 주석은 API 로 남기고 다시 읽어 확인하며, 배포 파이프라인이 자동으로 남기는 기록기도 만듭니다.

왜 중요한가

지표는 값이 변한 시각까지만 답한다. 그 시각에 사람이 무엇을 했는지는 지표 바깥의 사건이라 같은 화면에 없고, 그래서 새벽에 호출받은 사람은 배포 기록과 채팅과 설정 저장소를 오가며 시계를 맞춘다. 조사 시간의 상당 부분이 그 왕복이다. 주석은 그 사건을 같은 시간축 위에 올려 왕복을 없앤다. 다만 주석은 사후에 만들 수 없는 기록이라 그때 남겨야 하고, 그러려면 사람의 손이 아니라 파이프라인이 남겨야 한다. 무엇을 적을지도 미리 정해 두어야 한다 — 다음 사람이 그 자리에서 되돌릴 수 있으려면 버전과 사람과 되돌리는 명령이 주석 안에 있어야 한다.

단계

  1. lab-start-grafana 로 Grafana 를 띄우고, uid 가 gfd-annot 인 대시보드를 만드세요. 패널은 shop-api 의 5xx 비율을 그리는 timeseries 한 장입니다. 그리고 /root/gfd-annotations/01-blind.txt 에 세 줄을 적으세요 — question= 뒤에 이 패널이 답하는 질문, unanswerable= 뒤에 이 패널만으로는 답할 수 없는 질문, reason= 뒤에 왜 답할 수 없는지를 40자 이상으로 적습니다.
  2. POST /api/annotations 로 이 대시보드(dashboardUIDgfd-annot)에 배포 주석 하나를 남기세요. 태그에 deploy 가 있어야 하고, 본문에는 version=vX.Y.Z 형태의 버전이 들어가야 합니다. 시각은 지금부터 30분 전으로 둡니다(밀리초 에포크). 응답에 돌아온 idGET /api/annotations 를 다시 읽어 확인한 뒤, /root/gfd-annotations/02-annot.txt 에 두 줄 id=<그 id>version=<적은 버전> 을 적으세요.
  3. 시작과 끝이 있는 구간 주석을 하나 남기세요. 태그는 incident 이고, 시작은 지금부터 25분 전, 끝은 지금부터 5분 전입니다(따라서 길이는 20분). 본문에는 무엇이 있었는지 한 줄로 적습니다. 그리고 /root/gfd-annotations/03-region.txt 에 두 줄 id=<그 id>duration_min=<구간 길이(분)> 를 적으세요.
  4. 대시보드의 annotations.list 에 주석 질의 두 개를 선언하세요. 하나는 deploy 태그를, 다른 하나는 incident 태그를 가져옵니다. 두 항목 모두 켜져 있어야 하고(enable), 서로 다른 색(iconColor)을 가지며, 대상은 태그로 거르는 형태(target.typetags)여야 합니다. 두 태그를 모두 가진 주석만 가져오는 일이 없도록 한 항목에는 태그를 하나씩만 둡니다.
  5. /root/gfd-annotations/annotate-deploy.sh 를 만드세요. 첫 인자로 버전을 받아 gfd-annot 대시보드에 주석을 남기고, 태그는 deployauto 두 개, 본문에는 version=, by=, rollback= 세 값이 들어갑니다. 환경변수 DRY_RUN=1 이 주어지면 쏘지 않고 보낼 JSON 본문만 표준출력에 찍고 끝나야 합니다(그때 출력은 JSON 하나뿐이어야 합니다). 그리고 그 스크립트로 서로 다른 두 버전을 실제로 기록하세요.
  6. /root/gfd-annotations/annotation-fields.txt 에 배포 주석에 반드시 적을 필드 이름을 한 줄에 하나씩 적으세요 — version, by, rollback 셋은 반드시 들어가야 합니다. 그리고 그 형식을 지키는 주석 하나를 gfd-annot 대시보드에 남기세요. 태그는 deployrunbook 두 개이고, 본문에는 적어 둔 모든 필드가 필드이름=값 형태로 들어가야 합니다. rollback 의 값은 그대로 칠 수 있는 명령이어야 하므로 10자 이상입니다. runbook 태그가 붙은 주석은 이 하나뿐이어야 합니다.
  7. /root/gfd-annotations/07-timeline.tsv 를 만드세요. gfd-annot 대시보드에 달린 모든 주석을 시각 오름차순(같으면 id 오름차순)으로 한 줄씩, 탭으로 나눈 세 칸 <id> <태그 하나> <요약> 으로 적습니다. 둘째 칸은 그 주석에 실제로 붙어 있는 태그 중 하나여야 하고, 셋째 칸은 4자 이상의 요약입니다.
  8. /root/gfd-annotations/08-finding.txt 에 네 줄을 적으세요 — deploy_id= 는 2단계에서 남긴 배포 주석의 id, incident_id= 는 3단계에서 남긴 구간 주석의 id, gap_min= 은 배포 시각과 장애 시작 시각의 차이를 분으로 반올림한 정수(0 이상), verdict= 는 이 두 사건을 이어 내린 결론을 60자 이상으로 적은 문장입니다. 두 시각은 API 에서 다시 읽어 계산하세요.

참고

그래프는 '언제' 까지만 답한다

lab-start-grafana 로 Grafana 를 띄우고, uid 가 gfd-annot 인 대시보드를 만드세요. 패널은 shop-api 의 5xx 비율을 그리는 timeseries 한 장입니다. 그리고 /root/gfd-annotations/01-blind.txt 에 세 줄을 적으세요 — question= 뒤에 이 패널이 답하는 질문, unanswerable= 뒤에 이 패널만으로는 답할 수 없는 질문, reason= 뒤에 왜 답할 수 없는지를 40자 이상으로 적습니다.

Grafana 기동에는 20~40초가 걸립니다. curl -s http://127.0.0.1:3000/api/health"database": "ok" 를 줄 때까지 기다리세요.

5xx 비율은 개수가 아니라 비율입니다. 5xx 요청의 초당 건수를 전체 요청의 초당 건수로 나눕니다. promq "<PromQL>" 로 먼저 던져 보고 숫자가 나오는지 확인하세요.

패널 타입이 timeseries 여야 하는 이유가 다음 단계에서 드러납니다. 공식 문서는 주석을 지원하는 시각화가 Time series, State timeline, Candlestick 이라고 적습니다 — 숫자 한 칸짜리 패널에는 사건을 올릴 자리가 없습니다.

배포를 주석으로 남기고 다시 읽어 확인한다

POST /api/annotations 로 이 대시보드(dashboardUIDgfd-annot)에 배포 주석 하나를 남기세요. 태그에 deploy 가 있어야 하고, 본문에는 version=vX.Y.Z 형태의 버전이 들어가야 합니다. 시각은 지금부터 30분 전으로 둡니다(밀리초 에포크). 응답에 돌아온 idGET /api/annotations 를 다시 읽어 확인한 뒤, /root/gfd-annotations/02-annot.txt 에 두 줄 id=<그 id>version=<적은 버전> 을 적으세요.

필수 필드는 text 하나입니다. dashboardUID 를 적지 않으면 조직 전체 주석이 되어 이 대시보드로 거를 수 없습니다.

curl -s -X POST -H 'Content-Type: application/json' \
  -d '{"dashboardUID":"gfd-annot","time":1700000000000,"tags":["deploy"],"text":"..."}' \
  http://127.0.0.1:3000/api/annotations
curl -sG http://127.0.0.1:3000/api/annotations --data-urlencode 'dashboardUID=gfd-annot' | jq

시각 단위를 틀리는 실수가 가장 흔합니다. 초 단위로 넣으면 1970년대 어딘가에 찍혀 화면에서 사라집니다. 30분 전은 $(( ($(date +%s) - 1800) * 1000 )) 입니다.

버전은 다음 단계들에서도 씁니다. 배포 이력은 /opt/lab/gfd/gfd-annotations/releases.tsv 에 있습니다.

구간 주석으로 장애 시간을 표시한다

시작과 끝이 있는 구간 주석을 하나 남기세요. 태그는 incident 이고, 시작은 지금부터 25분 전, 끝은 지금부터 5분 전입니다(따라서 길이는 20분). 본문에는 무엇이 있었는지 한 줄로 적습니다. 그리고 /root/gfd-annotations/03-region.txt 에 두 줄 id=<그 id>duration_min=<구간 길이(분)> 를 적으세요.

구간 주석은 점 주석과 같은 자리에 만듭니다. 다른 점은 timeEnd 를 함께 보낸다는 것뿐입니다. 공식 문서는 Grafana 6.4 부터 구간이 timetimeEnd 를 가진 항목 하나로 표현된다고 적습니다.

두 시각을 각각 date 로 따로 계산하면 초가 어긋나 길이가 20분에서 밀립니다. 기준 시각을 한 번만 구해 놓고 거기서 빼세요.

NOW=$(date +%s)
echo $(( (NOW - 1500) * 1000 )) $(( (NOW - 300) * 1000 ))

채점기는 duration_min 을 그대로 믿지 않고 주석의 두 시각에서 다시 계산해 대조합니다.

태그로 갈라 대시보드가 가져오게 한다

대시보드의 annotations.list 에 주석 질의 두 개를 선언하세요. 하나는 deploy 태그를, 다른 하나는 incident 태그를 가져옵니다. 두 항목 모두 켜져 있어야 하고(enable), 서로 다른 색(iconColor)을 가지며, 대상은 태그로 거르는 형태(target.typetags)여야 합니다. 두 태그를 모두 가진 주석만 가져오는 일이 없도록 한 항목에는 태그를 하나씩만 둡니다.

대시보드 JSON 의 annotations.list 는 항목 배열입니다. 항목 하나가 화면 위쪽의 토글 하나가 되고, 이름이 그 토글의 이름입니다.

내장 주석 데이터소스를 가리키려면 datasource{"type": "grafana", "uid": "-- Grafana --"} 로 둡니다.

curl -s http://127.0.0.1:3000/api/dashboards/uid/gfd-annot \
  | jq '.dashboard.annotations.list'

종류가 섞이면 토글이 쓸모없어집니다. 배포만 보고 싶을 때 장애 구간까지 함께 켜지면 결국 아무도 토글을 쓰지 않습니다.

파이프라인이 자동으로 남기게 만든다

/root/gfd-annotations/annotate-deploy.sh 를 만드세요. 첫 인자로 버전을 받아 gfd-annot 대시보드에 주석을 남기고, 태그는 deployauto 두 개, 본문에는 version=, by=, rollback= 세 값이 들어갑니다. 환경변수 DRY_RUN=1 이 주어지면 쏘지 않고 보낼 JSON 본문만 표준출력에 찍고 끝나야 합니다(그때 출력은 JSON 하나뿐이어야 합니다). 그리고 그 스크립트로 서로 다른 두 버전을 실제로 기록하세요.

자동 기록기는 바쁜 날에도 빠지지 않는 것이 전부입니다. 그래서 형식을 고정하고, 사람이 손으로 부르는 일이 없게 만듭니다.

찍어 보는 모드를 두는 이유는 두 가지입니다. 파이프라인 안에서만 도는 스크립트는 고장 났을 때 확인하기 어렵고, 시험이 부작용 없이 돌 수 있어야 하기 때문입니다. 채점기도 이 모드로 본문을 검사합니다 — 그리고 그 전후로 주석 수가 늘지 않는지도 함께 봅니다.

본문을 만들 때 문자열을 손으로 이어 붙이면 따옴표에서 깨집니다. jq -n --arg 로 만드세요. 시각을 숫자로 넣으려면 --argjson 입니다.

배포 이력은 /opt/lab/gfd/gfd-annotations/releases.tsv 에 있습니다.

다음 사람이 그 자리에서 행동할 수 있는가

/root/gfd-annotations/annotation-fields.txt 에 배포 주석에 반드시 적을 필드 이름을 한 줄에 하나씩 적으세요 — version, by, rollback 셋은 반드시 들어가야 합니다. 그리고 그 형식을 지키는 주석 하나를 gfd-annot 대시보드에 남기세요. 태그는 deployrunbook 두 개이고, 본문에는 적어 둔 모든 필드가 필드이름=값 형태로 들어가야 합니다. rollback 의 값은 그대로 칠 수 있는 명령이어야 하므로 10자 이상입니다. runbook 태그가 붙은 주석은 이 하나뿐이어야 합니다.

주석의 내용은 취향이 아니라 계약입니다. 새벽 세 시에 그 주석을 본 사람이 다른 창을 열지 않고 다음 행동을 할 수 있어야 합니다. 커밋 해시 하나만 적힌 주석은 그 사람을 저장소로 보냅니다.

되돌리는 명령을 적어 두는 것이 특히 중요합니다. 배포한 사람이 자고 있어도 다른 사람이 되돌릴 수 있어야 하고, 그러려면 명령이 주석 안에 있어야 합니다. 실제 명령은 /opt/lab/gfd/gfd-annotations/releases.tsv 에 있습니다.

채점기는 여러분이 적어 둔 필드 목록을 읽고, 그 목록대로 주석이 채워졌는지 대조합니다.

주석을 시간순으로 다시 읽어 조사 기록을 만든다

/root/gfd-annotations/07-timeline.tsv 를 만드세요. gfd-annot 대시보드에 달린 모든 주석을 시각 오름차순(같으면 id 오름차순)으로 한 줄씩, 탭으로 나눈 세 칸 <id> <태그 하나> <요약> 으로 적습니다. 둘째 칸은 그 주석에 실제로 붙어 있는 태그 중 하나여야 하고, 셋째 칸은 4자 이상의 요약입니다.

정렬 기준을 채점기와 맞춰야 합니다. jqsort_by(.time, .id) 를 쓰면 같은 밀리초에 찍힌 주석도 순서가 흔들리지 않습니다.

curl -sG http://127.0.0.1:3000/api/annotations --data-urlencode 'dashboardUID=gfd-annot' \
  | jq -r 'sort_by(.time, .id)[] | [(.id|tostring), .tags[0], .text] | @tsv'

이 표가 조사 기록의 뼈대입니다. 시간순으로 늘어놓고 나면 '배포 → 오류 → 되돌림' 같은 순서가 눈에 들어오고, 그 순서가 곧 원인 가설입니다.

배포와 장애를 이어 결론을 적는다

/root/gfd-annotations/08-finding.txt 에 네 줄을 적으세요 — deploy_id= 는 2단계에서 남긴 배포 주석의 id, incident_id= 는 3단계에서 남긴 구간 주석의 id, gap_min= 은 배포 시각과 장애 시작 시각의 차이를 분으로 반올림한 정수(0 이상), verdict= 는 이 두 사건을 이어 내린 결론을 60자 이상으로 적은 문장입니다. 두 시각은 API 에서 다시 읽어 계산하세요.

채점기는 두 id 를 API 로 다시 읽어 간격을 스스로 계산하고 여러분이 적은 값과 대조합니다. 그래서 손으로 어림한 숫자는 통과하지 않습니다.

curl -sG http://127.0.0.1:3000/api/annotations --data-urlencode 'dashboardUID=gfd-annot' \
  | jq -c '.[] | {id, time, timeEnd, tags}'

결론은 '배포 때문이다' 로 단정할 필요가 없습니다. 간격이 짧다는 것은 의심할 근거이지 증거가 아닙니다. 다음 사람이 무엇을 먼저 확인해야 하는지까지 적으면 그 주석은 조사 기록이 됩니다.