Всем доброго дня! Пишу здесь впервые. На написание меня этой статьи побудило желание рассказать людям об эффективном способе миграции от внутренней базы данных sqlite3 к внешней БД PostgreSQL. Подобной статьи на Хабре я не нашел, поэтому надеюсь будет полезно.
Я перечитал много статей на эту тему и попробовал различные варианты, но получилось у меня только с одним. Спасибо этому человеку: Oodcode. Так же расскажу про остальные способы и что из них вышло.
Предпосылки
Изначально причиной миграции стали ошибки алертов, приходящие из Grafana (~130 штук). А именно: failed to build query 'A': [sqlstore.max-retries-reached] retry 1: database is locked.
Видимо столько алертов слишком сильно грузили внутреннюю БД и она редко выходила из состояния locked
. Про миграцию писали как на сторонних форумах, так и на форуме Grafana, как о решении этой проблемы.
Подготовка
Grafana хранит все данные во внутренней бд sqlite3 grafana.db.
Необходимо подготовить нашу внешнюю БД Postgres и создать схему и таблицы, чтобы было куда переносить.
Поднимаем docker контейнер с Postgres 16:
docker run --name my_postgres
-e POSTGRES_DB=grafana
-e POSTGRES_USER=grafana
-e POSTGRES_PASSWORD=mypassword
-v /path/to/your/data:/var/lib/postgresql/data
-p 5432:5432
-d postgres:16
Далее необходимо остановить Grafana, временно подключить ее к нашей бд, чтобы создать схему и таблицы.
docker run --name my_grafana
-e GF_DATABASE_TYPE=postgres
-e GF_DATABASE_HOST=HOST:5432
-e GF_DATABASE_NAME=grafana
-e GF_DATABASE_USER=grafana
-e GF_DATABASE_PASSWORD=mypassword
-p 3000:3000
-d grafana/grafana
Для удобства можно подключиться к новой БД и проверить, что все создалось:

Пока наша Grafana остановлена, создайте бэкап grafana.db и можно вернуть Grafana в рабочее состояние.
Теперь мы имеем на руках:
-
Копию grafana.db
-
Подготовленную БД Postgres
Миграция
Способа имеется два:
-
grafana-migrator (не получилось)
Pgloader
Устанавливаем на хост pgloader:
sudo apt update
sudo apt install pgloader
Создаем файл grafana.load
с таким содержанием (не забудь изменить данные для подключения Postgres):
load database
from sqlite:///path-to-grafana.db
into postgresql://grafana:mypassword@host:5432/grafana?sslmode=prefer
with data only, reset sequences
set work_mem to '16MB', maintenance_work_mem to '512 MB';
Запускаем этот конфиг:
pgloader grafana.load
По итогу у нас вылезут ошибки и это нормально. Вывод примерно такой:
2025-04-29T16:15:13.213561-04:00 ERROR Database error 23505: duplicate key value violates unique constraint "org_pkey" DETAIL: Key (id)=(1) already exists. CONTEXT: COPY org, line 1 2025-04-29T16:15:13.233584-04:00 ERROR Database error 23505: duplicate key value violates unique constraint "user_pkey1" DETAIL: Key (id)=(1) already exists. CONTEXT: COPY user, line 1 2025-04-29T16:15:13.258421-04:00 ERROR Database error 23505: duplicate key value violates unique constraint "migration_log_pkey" DETAIL: Key (id)=(1) already exists. CONTEXT: COPY migration_log, line 1 ...
Теперь, когда мы видим с какими таблицами у нас возникли ошибки при миграции данных, мы составим список. Сейчас нам необходимо полностью очистить БД Postgres, снова подключить Grafana к БД для создания схем и таблиц и остановить Grafana.
Возьмем таблицы из нашего списка, их необходимо очистить. Мой список получился такой:
TRUNCATE TABLE alert_configuration;
TRUNCATE TABLE alert_configuration_history;
TRUNCATE TABLE signing_key;
TRUNCATE TABLE"user";
TRUNCATE TABLE org;
TRUNCATE TABLE org_user;
TRUNCATE TABLE dashboard_acl;
TRUNCATE TABLE cache_data;
TRUNCATE TABLE kv_store;
TRUNCATE TABLE migration_log;
TRUNCATE TABLE server_lock;
После этого снова запускаем миграцию:
pgloader grafana.load
Утилита выдаст WARNING'и (это нормально) и итоговый отчет:
2023-05-29T15:24:21.045861-04:00 LOG report summary reset
table name errors rows bytes total time
--------------------------- --------- --------- --------- --------------
fetch 0 0 0.000s
fetch meta data 0 63 0.044s
Drop Foreign Keys 0 0 0.000s
--------------------------- --------- --------- --------- --------------
"user" 0 20 4.2 kB 0.530s
migration_log 0 487 81.1 kB 0.562s
org 0 1 0.1 kB 0.546s
dashboard_tag 0 1 0.0 kB 1.023s
dashboard_provisioning 0 0 1.093s
api_key 0 0 1.517s
quota 0 0 1.585s
star 0 5 0.0 kB 0.814s
session 0 0 2.090s
org_user 0 20 1.1 kB 1.070s
playlist_item 0 0 2.058s
dashboard 0 36 1.0 MB 1.420s
alert 0 12 21.0 kB 2.549s
annotation 0 4490 902.4 kB 2.831s
data_source 0 2 0.5 kB 1.555s
dashboard_snapshot 0 1 6.1 kB 1.968s
plugin_setting 0 0 2.042s
playlist 0 0 2.493s
preferences 0 3 0.3 kB 2.600s
alert_notification 0 6 1.6 kB 2.944s
test_data 0 0 3.071s
team 0 6 0.3 kB 3.533s
dashboard_acl 0 12 0.7 kB 3.642s
login_attempt 0 0 4.112s
alert_notification_state 0 22 0.8 kB 4.214s
user_auth_token 0 12 3.8 kB 4.607s
temp_user 0 9 1.2 kB 4.703s
annotation_tag 0 0 5.115s
alert_instance 0 16 4.6 kB 5.137s
alert_rule_version 0 302 548.1 kB 5.674s
library_element 0 0 5.595s
ngalert_configuration 0 0 6.066s
data_keys 0 110 21.5 kB 6.111s
role 0 28 3.1 kB 6.533s
user_role 0 19 0.6 kB 6.532s
query_history 0 1 0.3 kB 7.007s
query_history_star 0 0 6.989s
secrets 0 2 0.4 kB 7.472s
entity_event 0 0 7.464s
file 0 0 8.040s
seed_assignment 0 0 7.973s
folder 0 0 8.446s
dashboard_version 0 406 14.8 MB 4.523s
team_member 0 22 1.2 kB 3.185s
tag 0 0 3.709s
user_auth 0 19 33.9 kB 4.238s
server_lock 0 4 0.2 kB 4.762s
cache_data 0 0 4.839s
alert_rule_tag 0 0 5.298s
short_url 0 2 0.3 kB 5.343s
alert_rule 0 15 26.0 kB 5.791s
alert_configuration 0 1 3.1 kB 5.826s
library_element_connection 0 0 6.253s
kv_store 0 5 0.5 kB 6.292s
permission 0 160 13.1 kB 6.720s
team_role 0 6 0.2 kB 6.786s
builtin_role 0 3 0.2 kB 7.238s
provenance_type 0 0 7.297s
alert_image 0 0 7.713s
correlation 0 0 7.783s
dashboard_public 0 0 8.211s
file_meta 0 0 8.265s
alert_configuration_history 0 19 78.7 kB 8.362s
--------------------------- --------- --------- --------- --------------
COPY Threads Completion 0 4 8.694s
Reset Sequences 0 55 0.837s
Create Foreign Keys 0 0 0.000s
Install Comments 0 0 0.000s
--------------------------- --------- --------- --------- --------------
Total import time ✓ 6285 17.5 MB 9.532s
После этого можно подключить Grafana к БД Postgres и продолжать работу :)
Grafana-migrator
Этот способ намного проще, но с Grafana 11.3.5 и PostgreSQL 16 решение не сработало. Но это не мешает попробовать вам.
Это утилита из github: https://github.com/wbh1/grafana-sqlite-to-postgres
Скачиваем бинарник, делаем его исполняемым и запускаем с grafana.db:
chmod +x grafana-migrate_linux_amd64-v2.2.5
./grafana-migrate_linux_amd64-v2.2.5 /var/lib/grafana/grafana.db 'postgres://grafana:
mypassword@localhost:5432
/grafana?sslmode=disable'
Но у меня вылезала похожая ошибка:
INFO[2024-07-25T14:48:29+03:00] SQLlite file: grafana.db
INFO[2024-07-25T14:48:29+03:00] Dump directory: /tmp
INFO[2024-07-25T14:48:29+03:00] sqlite3 command exists
INFO[2024-07-25T14:48:30+03:00] sqlite3 database dumped to /tmp/grafana.sql
INFO[2024-07-25T14:48:33+03:00] CREATE statements removed from dump file
INFO[2024-07-25T14:48:43+03:00] sqlite3 dump sanitized
INFO[2024-07-25T14:48:48+03:00] migration_log statements removed
INFO[2024-07-25T14:48:49+03:00] char keyword transformed
INFO[2024-07-25T14:48:50+03:00] hex-encoded data values wrapped for insertion
FATAL[2024-07-25T14:48:51+03:00] pq: invalid input syntax for type bigint: "AbiGL-yVz" INSERT INTO "playlist" VALUES(3,'Live Managment','5m',5,'AbiGL-yVz',0,0) - failed to import dump file to Postgres.
P. S. Я бы хотел привести больше скринов и выводов из консоли, но к моменту написания статьи этого уже нет. Пару моментов позаимствовал у Oodcode и из официального репозитория grafana‑migrator.
Автор: Sanches166