LabHub
배우기 러닝패스 코스

Grafana — ダッシュボードは問いだ

縦線1本が調査の30分を消す

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}'

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