본문 바로가기

Infrastructure/Grafana

Grafana API 활용하기 (2)

 

이전 포스팅에선 간단하게 Grafana API 를 활용하는 방법에 대해서 살펴봤습니다.

이번엔 이 API 를 사용해 만들어둔 대시보드를 백업하고, 이를 이용해 원복해보는 과정을 진행해 볼 것 입니다.

 

- Grafana resources 백업

 

Grafana Lab 에서 제공하는 모든 HTTP API 는 여기에서 확인할 수 있습니다.

이 중 대시보드를 백업하기 위해선 최소 4개의 API 를 사용해 필요한 정보를 조회해야 합니다.

 

  • /api/datasources
  • /api/folders
  • /api/search
  • /api/dashboards/uid/:{uid}

Grafana 에서 대시보드를 만들 때, 일반적으로 datasources 를 먼저 세팅하고 이를 사용해 대시보드를 구성하게 됩니다.

이 datasources 정보를 /api/datasources API 를 사용해서 조회하게 되는데 이 정보를 같이 저장해두지 않으면 이후에 백업한 정보를 바탕으로 대시보드를 원복하더라도 datasources 에 의한 메트릭이 없어 불러온 쿼리가 아예 날라갈 수 있습니다.

 

 

특별히 폴더 구분을 하지않고 대시보드를 만들었다면 /api/folders API 는 필요없을 수 있습니다.

하지만 위처럼 폴더를 구분해서 대시보드를 세팅했다면, 이를 그대로 추후에 원복하기 위해서 folders 정보까지 조회해서 저장해두는게 필요합니다.

 

/api/search API 는 모든 대시보드 데이터를 조회하는데 필요합니다. 이를 이용해서 대시보드들의 uid 를 조회하고 이 uid 를 사용해 /api/dashboards/uid/:{uid} API 로 각 대시보드의 상세 정보를 조회할 수 있습니다. 상세 코드로 확인해보겠습니다.

 

 

테스트를 위해 Prometheus 를 localhost 에서 띄우고 이를 datasources 에 추가해뒀습니다.

 

const axios = require('axios');
const fs = require('fs');

const token = '';

(async () => {
  const { data } = await axios({
    method: 'GET',
    url: 'http://localhost:3000/api/datasources',
    headers: { Authorization: `Bearer ${token}` },
  });
  fs.writeFileSync('datasources.json', JSON.stringify(data));
})();

 

코드는 이전 포스팅에서 다뤘던 내용과 거의 동일합니다. 나중에 원복할 때 활용하기 위해 조회한 데이터를 datasources.json 파일에 저장해두었습니다. 생성된 datasources.json 파일을 열어보면, 배열의 형태로 datasources 정보가 들어있을 겁니다.

추가로 /api/search + /api/dashboards/uid/:{uid} 예시 코드를 보도록 하겠습니다.

 

const axios = require('axios');

const token = '';

(async () => {
  const { data: dashboardData } = await axios({
    method: 'GET',
    url: 'http://localhost:3000/api/search',
    headers: { Authorization: `Bearer ${token}` },
  });

  for (const metadata of dashboardData) {
    console.info(metadata);
  }
})();

/*
{ id: 47,
  uid: '0AE8Sm_7z',
  title: 'test-folder',
  uri: 'db/test-folder',
  url: '/dashboards/f/0AE8Sm_7z/test-folder',
  slug: '',
  type: 'dash-folder',
  tags: [],
  isStarred: false }
{ id: 48,
  uid: 'ox5QIm_7k',
  title: 'Test dashboard',
  uri: 'db/test-dashboard',
  url: '/d/ox5QIm_7k/test-dashboard',
  slug: '',
  type: 'dash-db',
  tags: [],
  isStarred: false,
  folderId: 47,
  folderUid: '0AE8Sm_7z',
  folderTitle: 'test-folder',
  folderUrl: '/dashboards/f/0AE8Sm_7z/test-folder' }
*/

 

현재 구성은 test-folder 폴더 하위에 Test dashboard 대시보드가 하나만 존재하는 상태입니다. 여기서 /api/search API 를 통해 얻은 결과를 보면 대시보드 데이터는 두 개가 조회되는데 title 을 보면 폴더도 여기에 같이 조회되고 type 이 dash-folder 로 구분되는걸 알 수 있습니다. folder 는 이미 /api/folders API 로 조회하고 있기 때문에 이 API 에선 필요없는 정보이므로, type 이 dash-folder 인 메타데이터는 생략하고 그 외의 데이터만 uid 를 통해 추가 조회하도록 합니다.

 

const axios = require('axios');
const fs = require('fs');

const token = '';

(async () => {
  const { data: dashboardData } = await axios({
    method: 'GET',
    url: 'http://localhost:3000/api/search',
    headers: { Authorization: `Bearer ${token}` },
  });
  const dashboards = [];

  for (const metadata of dashboardData) {
    const { uid, type } = metadata;

    if (type === 'dash-folder') {
      continue;
    }

    const { data } = await axios({
      method: 'GET',
      url: `http://localhost:3000/api/dashboards/uid/${uid}`,
      headers: { Authorization: `Bearer ${token}` },
    });
    dashboards.push(data);
  }

  fs.writeFileSync('dashboards.json', JSON.stringify(dashboards));
})();

 

type 이 dash-folder 인 메타데이터는 생략하고 그 외의 대시보드들만 uid 를 통해 dashboards 배열에 넣은 후 dashboards.json 파일에 저장한 코드입니다. dashboards.json 파일을 열어보면, 배열의 형태로 대시보드 정보가 들어가있는 걸 확인할 수 있습니다.

 

- Grafana 원복

 

위의 조회 API 를 통해 백업하는 과정은 search -> uid 과정만 빼면 각각 개별로 진행해도 무방하지만, 저장한 json 파일을 읽어 원복하는 과정은 datasources -> folders -> dashboards 순서를 지켜줘야 합니다. datasources 를 원복하는 예시 코드를 보도록 하겠습니다.

 

const axios = require('axios');
const fs = require('fs');

const token = '';

(async () => {
  const datasources = JSON.parse(fs.readFileSync('datasources.json', 'utf8'));

  for (const data of datasources) {
    await axios({
      method: 'POST',
      url: 'http://localhost:3000/api/datasources',
      headers: { Authorization: `Bearer ${token}` },
      data,
    });
  }
})();

 

코드는 간단합니다. 위에서 datasources.json 파일에 저장해두었던 정보를 다시 읽어서, /api/datasources API 를 POST method 로 호출하면 끝입니다. 위 코드를 실행한 후 Grafana 를 확인해보면, 이전에 생성했던 Prometheus datasources 가 원복된걸 볼 수 있습니다. 물론 지금은 테스트 상황이므로 기존에 존재하던 동일한 datasources 를 제거하지 않은 상황이라면 409 에러가 발생할 수 있습니다.

 

위와 동일한 방식으로 /api/folders POST -> /api/dashboards/db POST API 를 활용해 폴더, 대시보드 순서로 Grafana resources 를 원복할 수 있습니다.

 

이번 포스팅에서 Grafana API 를 활용해 대시보드를 백업, 원복하는 과정을 알아본 이유는 제가 팀에서 운영하고 있던 Grafana 대시보드를 개발자의 실수로 인해 통째로 날려먹은 일이 두번정도 있었기 때문입니다.

팀 내에서 운영하는 대시보드이다보니 Role 을 타이트하게 관리하지도 않았고 삭제는 너무나 쉽습니다. 사람에 의한 실수가 발생할 여지가 많다는 것이죠. Grafana 는 내부적으로 특별한 설정을 하지 않는다면 SQLite 에 관련 데이터가 저장되긴 합니다만, UI 에서 제거된 경우 SQLite 에도 데이터가 남아있지 않아 이를 의존해 대시보드를 원복하기란 거의 불가능했습니다.

 

따라서 datasources, folders, dashboards 파일을 S3 에 백업해두도록 코드를 만들고 하루에 한 번 배치를 돌리고 있습니다.

이후 Grafana 에 문제가 생긴다면 S3 에 백업해둔 json 파일을 바탕으로 대시보드들을 최소 하루 전 버전으로 롤백할 수 있게 되었습니다.

'Infrastructure > Grafana' 카테고리의 다른 글

Grafana 를 좀 더 잘 활용해보자  (0) 2022.01.15
Grafana API 활용하기 (1)  (0) 2022.01.02