Grafana — 대시보드는 질문이다 · 변수와 반복 — 복사 대신 드롭다운 · 이론
복사본은 그날부터 따로 늙는다
한 줄 요약
대상이 하나 늘 때마다 대시보드를 복사하면 복사본은 그날부터 따로 늙는다. 변수는 그 복사를 드롭다운 하나로 바꾸고, 패널 반복은 그 드롭다운을 패널 여러 장으로 펼친다.
왜 이게 필요했나
대시보드가 처음 망가지는 방식은 거의 언제나 같다. 잘 만든 대시보드 하나가 있고, 다른 서비스를 보려는 사람이 그걸 복사해 쿼리의 이름만 바꾼다. 일주일 뒤 원본에 패널이 하나 늘고, 한 달 뒤 원본의 쿼리 창이 [5m] 에서 $__rate_interval 로 바뀐다. 복사본은 둘 다 모른다.
이 상태가 무서운 이유는 화면이 멀쩡하다는 데 있다. 복사본도 숫자를 보여 주고 그래프도 그려진다. 다만 원본과 다른 질문에 답하고 있을 뿐이고, 인시던트 때 두 대시보드를 나란히 열어 놓은 사람은 두 숫자가 왜 다른지부터 찾게 된다. 고쳐야 할 자리가 대시보드 수 × 패널 수만큼 있다는 사실도 평소에는 보이지 않는다. 쿼리를 한 번 고칠 일이 생겨야 그때 여덟 군데를 손으로 고치면서 알게 된다.
그래서 이 모듈은 복사본을 먼저 실제로 만들어 본다. 네 벌을 올려 놓고 "이 쿼리를 한 번 고치려면 몇 군데를 고쳐야 하는가" 를 숫자로 적고 시작한다. 그 숫자가 있어야 변수가 무엇을 없애 주는지가 실감난다.
어떻게 동작하나
템플릿 변수는 대시보드 JSON 의 templating.list 배열에 들어간다. 값을 손으로 나열하는 custom 타입과, 데이터소스에 물어보는 query 타입이 있다. 대상 목록처럼 늘어날 수 있는 것은 반드시 query 여야 한다. 손으로 적은 목록은 다섯 번째 대상이 생긴 날 조용히 낡는다.
값을 여러 개 고를 수 있게 하는 순간 한 가지가 바뀐다. 여러 값이 선택된 변수를 쿼리에 끼워 넣으려면 그 값들을 문자열 하나로 만들어야 하는데, 그 방법을 데이터소스가 정한다. 공식 문서는 Prometheus 와 InfluxDB 는 정규식을 쓰므로 (값1|값2|값3) 으로 펼쳐지고 값마다 정규식 이스케이프가 걸린다고 적는다. 그러니 쿼리의 매처도 함께 바뀌어야 한다. label="$var" 는 값이 하나일 때만 맞고, 여러 값을 받으려면 label=~"$var" 로 써야 한다. 이걸 안 바꾸면 값 하나를 고를 때는 잘 되다가 둘을 고르는 순간 빈 그래프가 된다. 사람은 대개 "데이터가 없네" 로 읽고 넘어간다.
전체 선택(includeAll)에는 딸린 설정이 하나 더 있다. allValue 를 비워 두면 Grafana 가 모든 값을 이어 붙여 하나의 긴 문자열을 만들고, 값을 적어 두면(예: .+) 그 문자열이 대신 들어간다. 대상이 수백 개인 곳에서는 뒤쪽이 훨씬 싸다. 다만 이스케이프가 걸리지 않으므로 그 값이 데이터소스에서 유효한지는 사람이 책임져야 한다.
패널 반복은 여기서부터 시작된다. 패널에 repeat 을 걸고 여러 값 변수를 지정하면 Grafana 가 선택된 값마다 패널을 한 장씩 만든다. 가로로 펼칠지 세로로 펼칠지(repeatDirection), 한 줄에 몇 장까지 둘지(maxPerRow)도 함께 정한다. 반복된 패널 안에서 변수는 그 패널의 값 하나로 풀리므로, 제목에 변수를 넣어 두면 어느 대상의 그림인지 제목이 알려 준다.
변수가 다른 변수에 기대게 만들 수도 있다. 두 번째 변수의 쿼리 안에 첫 번째 변수를 쓰면 Grafana 가 그 연결을 알아채고 앞의 값이 바뀔 때 뒤의 값을 다시 읽는다. 여기서 두 가지가 중요하다. 하나는 순서 — templating.list 의 앞에 있는 변수가 먼저 풀리므로, 기대는 쪽이 뒤에 있어야 한다. 다른 하나는 갱신 시점 — 대시보드를 열 때만 다시 읽을지, 시간 범위가 바뀔 때도 다시 읽을지를 고른다. 시간 범위에 따라 후보가 달라지는 변수를 앞쪽 설정으로 두면, 어제를 보러 간 사람이 오늘의 목록을 보게 된다.
편리한 만큼 값을 치른다. 반복 패널 한 장은 옵션 수만큼의 패널이 되고, 패널마다 쿼리가 최소 한 개씩 날아간다. 반복 패널이 둘이고 옵션이 각각 넷과 셋이면 화면에는 일곱 장이 그려지고 고정 패널까지 합치면 여덟 장이다. 대상이 마흔 개인 환경이라면 같은 대시보드가 여든 장이 된다. 그래서 반복을 쓰는 대시보드에는 펼쳐지는 패널 수의 상한을 정해 두고, 그 위로는 목록을 좁히는 변수를 먼저 달거나 대시보드를 나누는 편이 낫다.
마지막으로 이 환경에서 무엇을 확인할 수 있고 무엇은 확인할 수 없는지 적어 둔다. 이 실습의 채점은 대시보드 JSON 모델과 실제 쿼리 결과로만 한다 — 변수가 선언됐는가, 타입이 무엇인가, 값 목록이 데이터소스에서 실제로 채워지는가, 패널의 쿼리가 변수를 쓰는가, 그 쿼리가 값을 내는가. 반대로 화면에 패널이 정말 몇 장 그려졌는지는 판정할 수 없다. 반복은 브라우저가 대시보드를 그릴 때 일어나는 일이고 이 파드에는 이미지 렌더러 플러그인이 없다. 서버가 돌려주는 대시보드 JSON 에는 반복되기 전의 패널 한 장만 들어 있고, 변수의 options 배열도 비어(null) 돌아온다. 그래서 옵션 수는 변수 선언이 아니라 데이터소스에 직접 물어서 세야 한다. 반복이 실제로 어떻게 보이는지는 웹 미리보기로 눈으로 확인하는 수밖에 없다.
현장에서 만나는 모습
한 팀은 서비스가 열두 개였고 대시보드도 열두 개였다. 장애가 나서 쿼리 하나를 고쳐야 했는데, 고친 사람이 여섯 개만 고치고 퇴근했다. 다음 주 다른 사람이 나머지 여섯 개 중 하나를 보고 "여기는 괜찮다" 고 판단했다. 같은 코드가 도는 서비스였다.
반대로 반복을 너무 믿다 생긴 일도 있다. 파드 이름을 변수로 잡고 전체 선택을 기본값으로 둔 대시보드가 있었는데, 오토스케일링이 파드를 이백 개까지 늘린 날 그 대시보드를 연 사람의 브라우저가 멈췄다. 변수의 목록을 좁히는 두 번째 변수(네임스페이스)를 앞에 달고 기본값을 하나로 바꾼 뒤에야 다시 쓸 수 있게 됐다. 반복은 공짜가 아니라 옵션 수만큼 곱해지는 비용이다.
다음 실습에서 할 것
먼저 대상마다 복사된 대시보드 네 벌을 실제로 올려 고쳐야 할 자리가 몇 군데인지 센다. 그다음 질의 변수를 하나 만들어 값 목록이 데이터에서 채워지는지 확인하고, 여러 값 선택과 전체 선택을 켠 뒤 쿼리의 매처를 정규식으로 바꾼다. 패널 반복으로 대상 수만큼 패널이 생기게 하고, 그 변수에 기대는 두 번째 변수를 더해 순서와 갱신 시점을 정한다. 마지막으로 펼쳐지는 패널 수를 세어 상한을 적고, 복사판으로 남아 있는 낡은 대시보드를 변수 하나로 합친 뒤 합친 패널이 원래 네 패널과 같은 답을 내는지 증명한다.