Перейти к основному содержимому

Миграция Grafana из SQLite в PostgreSQL

·797 слов·4 минут
Гайды
Юрий Семеньков
Автор
Юрий Семеньков
DevOps, tech, geek, mentor
Оглавление

Иногда может случиться так, что Grafana перестает показывать графики, показывает в веб-интерфейсе ошибки. Зайдя в логи сервиса ты можешь увидеть частые сообщения:

error="database is locked"

Что за ошибка?
#

Опишу так, как это понял я.

По умолчанию Grafana использует в качестве базы данных файл SQLite, и все было бы хорошо, если бы не версия 8.0.0, в которой разработчики перелопатили систему alert-ов. При увеличении количества настроенных алертов база данных может не справляться с нагрузкой и блокироваться.

Даже разработчики подтверждают такую проблему:

Первое решение, временное
#

Скорее всего первое, что тебе попадется в Google по этому запросу, это статья в community Графаны с советом забекапить SQLite базу данных в новый файл, поменять их местами и перезапустить Графану.

sqlite3 grafana.db '.clone grafana-new.db'
mv grafana.db grafana-old.db
mv grafana-new.db grafana.db

Такое приходилось делать, когда внезапно перезагружаешь контейнер или машину с графаной. И оно действительно работает.

Но спустя пару месяцев наши разработчики решили добавить десяток алертов, что привело к не выходящей из состояния блокировки базы данных.

Пришлось прибегнуть к

Второе решение, постоянное
#

Это переехать на другую базу данных. Выбираем PostgreSQL.

В моем случае Grafana развернута в контейнере с помощью docker-compose, таким образом мы просто развернем рядом еще один контейнер с базой данных. Но есть проблема, мы же хотим сначала перенести SQLite БД в PostgreSQL.

Поднимаем контейнер с PostgreSQL 13, подключаем к нему директорию, в которой он будет хранить данные. Я сделаю это с помощью docker-compose.

Создаю директорию для хранения данных:

mkdir -p /var/lib/postgresql/data

Можно также воспользоваться docker volume.

Создаю docker-compose.yml:

version: '3.9'

services:
  postgres:
    image: postgres:13.10-alpine3.17
    restart: always
    container_name: postgres-grafana
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=superstrongpassword
    ports:
      - '127.0.0.1:5432:5432'
    volumes: 
      - /var/lib/postgresql/data:/var/lib/postgresql/data

Запускаю его:

docker-compose up -d

Зайдем в PostgreSQL и создадим новую БД:

docker exec -ti postgres-grafana /bin/sh
psql
CREATE DATABASE grafana;

Теперь нам нужно создать в базе данных таблицы с нужными схемами данных. Для этого мы запустим Grafana и подключим ее к свежей базе. Потом выключим. Добавляю в docker-compose.yml новый сервис:

grafana:
    image: grafana/grafana:version
    container_name: grafana
    user: "2017"
    volumes:
      - /var/lib/grafana:/var/lib/grafana
    environment:
      GF_DATABASE_TYPE: postgres
      GF_DATABASE_HOST: postgres:5432
      GF_DATABASE_NAME: grafana
      GF_DATABASE_USER: postgres
      GF_DATABASE_PASSWORD: superstrongpassword
      GF_DATABASE_SSL_MODE: disable
    ports:
      - 3000:3000

Запускаем и мониторим логи, дожидаясь завершения миграций:

docker logs -f grafana

После того, как миграции закончатся, можно выключить Grafana и приступить к переносу БД SQLite в PostgreSQL.

docker-compose stop grafana

Перенос с помощью pgloader
#

Ориентировался я на статью.

TL;DR у меня не получилось

Первым делом я решил воспользоваться утилитой pgloader, которую можно установить из стандартных репозиториев:

apt install pgloader

Disclaimer: именно из-за pgloader пришлось разворачивать PostgreSQL 13, а не 14. Дело в том, что в 14 версии начали использовать метод шифрования паролей по умолчанию scram-sha-256 вместо md5. pgloader не умеет с ним работать. Можно изменить, но это лишние действия.

Создаю файл-скрипт для переноса БД:

load database
  from sqlite:///var/lib/grafana.db
  into postgresql://postgres:superstrongpassword@127.0.0.1/grafana
  with data only, reset sequences
  set work_mem to '16MB', maintenance_work_mem to '512 MB';

Запускаем утилиту:

pgloader script.load

По идее, после этого должно все работать. Но нет. У меня перестала работать авторизация. После логина выбрасывало обратно на ввод логина/пароля.

Перенос с помощью grafana-migrate
#

Как я смог понять проблему — Grafana записывает некоторые значения в БД в виде hex, что не очень хорошо переносится в PostgreSQL с помощью pgloader.

grafana-migrate — это самописная утилита, которая лежит в github https://github.com/wbh1/grafana-sqlite-to-postgres

Disclaimer: если перед этим ты делал что-то с базой через pgloader, то лучше будет удалить БД, создать снова и провести миграции.

Скачиваем бинарник с утилитой:

wget https://github.com/wbh1/grafana-sqlite-to-postgres/releases/download/v2.2.3/grafana-migrate_linux_amd64-v2.2.3

Формируем команду и запускаем утилиту:

./grafana-migrate /var/lib/grafana/grafana.db 'postgres://postgres:superstrongpassword@127.0.0.1:5432/grafana?sslmode=disable'

Здесь возникает подводный камень:

У меня grafana.db весит 150 мегабайт.

  • На сервере с HDD дисками процедура миграции БД не закончилась за 12 часов.
  • На сервере с SSD дисками это было быстрее, но я не стал ждать дольше часа.
  • На сервере с nvme диском эта процедура заняла чуть меньше 30 минут.

После этого я просто перенес директорию с данными /var/lib/postgresql/data с “быстрого” сервера на другой, где должна была крутиться Grafana.

Полезности
#

Давай доформируем окончательно наш docker-compose.yml файл:

version: '3.9'

services:
  postgres:
    image: postgres:13.10-alpine3.17
    restart: always
    container_name: postgres-grafana
    environment:
      - POSTGRES_USER=postgres
      - POSTGRES_PASSWORD=superstrongpassword
    ports:
      - '127.0.0.1:5432:5432'
    volumes: 
      - /var/lib/postgresql/data:/var/lib/postgresql/data
    healthcheck:
      test: ["CMD-SHELL", "pg_isready -U postgres"]
      interval: 5s
      timeout: 5s
      retries: 5
  grafana:
    image: grafana/grafana:9.0.4
    container_name: grafana
    user: "2017"
    depends_on:
      postgres:
        condition: service_healthy
    volumes:
      - /var/lib/grafana:/var/lib/grafana
    environment:
      GF_DATABASE_TYPE: postgres
      GF_DATABASE_HOST: postgres:5432
      GF_DATABASE_NAME: grafana
      GF_DATABASE_USER: postgres
      GF_DATABASE_PASSWORD: superstrongpassword
      GF_DATABASE_SSL_MODE: disable
    ports:
      - 127.0.0.1:3000:3000

Я добавил healthcheck для сервиса postgres, который раз в 5 секунд проверяет, доступна ли база данных. Это удобно на этапе запуска:

  • если Grafana запустится до того, как запустится postgres - возникнет ошибка. Параметр depends_on будет ждать, пока сервис postgres не перейдет в состояние healthy.

Так же я закрепил контейнер с Grafana за интерфейсом 127.0.0.1. У меня уже настроен Nginx reverse proxy, который будет проксировать запросы извне, на 127.0.0.1:3000 - в Grafana.


🌈 Надеюсь, тебе понравилась статья. Рекомендую подписаться на канал в Телеграме, чтобы не пропускать полезную информацию:

👉 Телеграм канал

Related

Apache Airflow: деплой DAG файлов из git
·1037 слов·5 минут
Гайды
Как настроить деплой DAG файлов для Apache Airflow из git с помощью GitHub Actions и Ansible
Перенос git репозитория
·135 слов·1 минута
Софт Гайды
Как посмотреть внешний IP в Linux
·126 слов·1 минута
Гайды