LabHub
배우기 러닝패스 코스

Grafana — 대시보드는 질문이다 · 대시보드를 코드로 — 바뀐 것을 읽을 수 있게 · 이론

버전은 남았는데 무엇이 바뀌었는지는 아무도 몰랐다

LabHub 에서 이어서 보기

한 줄 요약

대시보드를 코드로 관리한다는 말의 핵심은 파일에 두는 것이 아니라 바뀐 것을 읽고 되돌릴 수 있게 만드는 것이다.

왜 이게 필요했나

장애 다음 날 대시보드가 달라져 있다. 누가 고쳤는지는 알 수 없고, 무엇이 달라졌는지도 알 수 없다. Grafana 는 버전을 남기지만, 두 판의 JSON 을 내려받아 견주면 수백 줄이 통째로 다르게 나온다. 저장할 때마다 바뀌는 필드가 섞여 있어서다. 그래서 "버전이 남아 있다" 는 사실과 "무엇이 바뀌었는지 안다" 는 사실 사이에는 꽤 먼 거리가 있다.

옮길 때도 마찬가지다. 잘 만든 대시보드 JSON 을 다른 환경에 그대로 올리면 패널이 전부 빈다. 화면에는 오류가 없고 그냥 비어 있다. 대시보드가 데이터소스를 이름이 아니라 uid 로 가리키는데, 자동 생성된 uid 는 환경마다 다르기 때문이다. 이 사실을 모르면 하루를 쓴다.

어떻게 동작하나

Grafana 의 대시보드는 저장될 때마다 새 버전이 만들어지고, 저장 요청에 함께 보낸 메시지가 그 버전에 붙는다([대시보드 HTTP API](https://grafana.com/docs/grafana/latest/developer-resources/api-reference/http-api/dashboard/)). 메시지를 비워 두면 목록에는 시각만 남는다. 그리고 첫 저장의 메시지는 Grafana 가 스스로 덮어쓴다 — 직접 확인하지 않으면 "메시지를 적었는데 왜 안 남지" 로 한참을 헤맨다.

두 판을 읽을 수 있게 만들려면 정규화가 필요하다. 저장할 때마다 달라지는 것은 대시보드 최상위의 version·id 같은 필드다. 이것들을 걷어 내고 키를 정렬해서 내놓으면, 그때부터 diff 는 사람이 읽는 물건이 된다. 정규화 함수가 갖춰야 할 성질은 두 가지다 — 같은 입력에 늘 같은 출력을 내고(결정적), 휘발 필드만 다른 두 판을 같은 것으로 만든다.

| 무엇을 | 왜 |
| --- | --- |
| 최상위 version·id 를 뺀다 | 저장할 때마다 바뀌어 diff 를 덮는다 |
| 키를 정렬한다 | 순서가 흔들리면 같은 내용도 달라 보인다 |
| 패널의 id 는 남긴다 | 패널을 가리키는 이름이라 의미가 있다 |

옮기는 문제는 데이터소스 변수로 푼다. datasource 타입의 템플릿 변수를 하나 만들어 두고 패널이 그 변수를 가리키게 하면, 환경이 달라져도 고칠 자리가 한 곳이다([변수 문서](https://grafana.com/docs/grafana/latest/visualizations/dashboards/variables/)). 없는 uid 로 질의가 나가면 Grafana 는 404 를 돌려주는데, 이 응답은 브라우저 개발자 도구에서만 보이고 패널에는 그냥 빈 그래프로 나타난다.

여기까지 오면 한 가지 성질이 더 필요해진다. 파일과 화면이 같은지 스스로 물을 수 있어야 한다. 저장소에 대시보드를 넣어 두기만 하고 그것이 실제로 화면과 같은지 아무도 확인하지 않으면, 두 쪽은 조용히 갈라진다. 정규화 함수가 이미 있으므로 이 검사는 짧다 — 화면에서 받아 정규화한 것과 파일을 정규화한 것을 견주면 된다. 그리고 그 검사기도 양방향으로 시험해야 한다. 같은 것을 주면 통과하고 다른 것을 주면 떨어지는지 확인하지 않으면, 무엇을 주어도 통과하는 검사기를 믿고 지내게 된다.

찾을 수 있게 만드는 일도 코드로 관리하는 일의 일부다. 대시보드가 수십 개가 되면 어느 것을 열어야 할지가 문제가 되고, 그때 기대는 것이 폴더와 태그다. 둘 다 대시보드 JSON 과 프로비저닝 설정에 적히므로, 파일이 원본이 된 뒤에는 태그 하나를 붙이는 일조차 파일을 고쳐 반영해야 한다. 번거로워 보이지만 그 번거로움이 바로 "누가 언제 무엇을 왜" 가 남는 값이다.

마지막은 원본을 어디에 둘 것인가다. 프로비저닝으로 제공되는 대시보드는 화면에서도 API 로도 저장할 수 없고, 저장을 시도하면 400 과 함께 거절된다([프로비저닝 문서](https://grafana.com/docs/grafana/latest/administration/provisioning/)). 불편해 보이지만 이것이 이 방식의 핵심이다 — 화면과 파일이 갈라질 길 자체를 없앤다. 그때부터 대시보드를 바꾸는 유일한 길은 파일을 고치고 다시 읽히게 하는 것이고, 그 길에는 코드 리뷰가 붙는다.

현장에서 만나는 모습

한 팀은 대시보드를 저장소에 넣어 두고도 반년 뒤에 화면과 파일이 완전히 달라져 있었다. 파일에서 제공하지 않고 그냥 백업으로 올려 두기만 했기 때문이다. 아무도 파일을 고칠 이유가 없었고, 화면에서 고치는 것을 막는 것도 없었다. 프로비저닝으로 바꾸고 나서야 파일이 원본이 됐다.

다른 팀은 스테이징에 대시보드를 옮겼다가 "데이터가 안 나온다" 로 이틀을 썼다. 쿼리도 맞고 Prometheus 도 멀쩡했다. 패널의 datasource.uid 가 운영 환경에서 자동 생성된 값이었고 스테이징에는 그런 uid 가 없었다. 데이터소스 변수로 빼고 나서는 옮기는 일이 파일 복사로 끝났다.

이 환경에서 판정할 수 있는 것과 없는 것

이 파드의 Grafana 는 진짜로 돌지만 이미지 렌더러가 없어 화면 그림 자체는 검사할 수 없다. 대신 버전 API·프로비저닝 상태·저장 거절 응답·대시보드 JSON 모델은 전부 확인할 수 있고, 이 실습의 판정은 그 범위 안에서 한다. 저장소 쪽(리뷰·CI)은 이 파드에 git 이 없어 다루지 않는다 — 대신 "저장소에 무엇을 올려야 한 벌이 되는가" 를 목록으로 남기는 데까지 간다.

다음 실습에서 할 것

대시보드를 올리고 저장 메시지를 붙여 한 번 더 저장한 뒤, 버전 목록이 실제로 무엇을 남기는지 확인한다. 정규화 스크립트를 만들어 두 버전의 차이를 사람이 읽을 수 있게 뽑고, 데이터소스를 변수로 빼서 옮길 수 있게 만든다. 그 다음 대시보드를 파일에서 제공되게 바꾸고, 저장이 막히는 응답을 직접 받아 본다. 마지막에는 태그 하나를 붙이는 일을 파일을 고쳐서 해내고, 파일과 화면이 같은지 스스로 보는 검사기까지 만든다.