Привет, любители Хабра! Сегодня я решил поделиться своим вариантом бекапа данных из MySql и рассказать о том как его можно использовать для контроля версий в Git. И если вам интересно узнать, как можно контролировать состояние базы данных на всех этапах разработки, или просто делать правильные бекапчики базы своих проектиков и разворачивать из в любой момент времени, тогда прошу к прочтению!
Что это?
Это набор скриптов написанных на BASH, что позволяет им работать практически на любой машине в которой работает данная оболочка, предназначенный для облегчения создания и разворачивания бекапов. Изначальная идея была в том чтобы можно было создавать контрольные точки БД при написании проекта командой разработчиков, и хранить его в гите, я знаю что есть более серьезные вещи для такой цели, и это решение никак не претендует на их место.
Для кого?
К примеру вы предпочитаете разрабатывать сайт сразу на хостинге заказчика и контролировать ход разработки и изменения в БД. Либо у вас мало денег (или жаба душит) чтобы тратить их на хорошие продукты контроля версий БД. Вы также можете использовать проект в качестве бекапера данных по определенным правилам, который можно использовать по крону. И конечно пригодится если вы начинающий разработчик и только начинаете осваивать азы разработки, и у вас периодически происходит 500-я и вы не знаете почему. Либо вы разрабатываете продукт командой и хотите автоматически при пуше в мастер синхронизировать его с продакшеном для оценки заказчика.
Рассмотрим пример стандартной разработки сайта на стороне хостера (большинство случаев):
- Есть сервер, на котором крутится проект и скорее всего это либо локальная машина, либо хостинг клиента текущего проекта.
- Есть локальный компьютер, за которым вы работаете и по традиции там же храните файлики и снимки состояний.
- И Продакшен, это то куда сливается итоговый продукт — но он может являтся и 1-м пунктом просто другой папкой.
Как с этим работать?
Для того, чтобы соблюсти контроль версии базы данных используя гит, очевидно нужно получать ее дампы на некоторых этапах, где то их хранить, и при переключении веток учитывать этот момент. Для этого я использовал хуки гита, которые представляют из себя файлики соответствующих скриптов (они должны быть установлены на локальном компьютере, где используется git). В зависимости от настроек конфигурационного файла процесс работы может выглядеть следующим образом:
Создаем ветку (автоматически произошел бекап) и переключаемся, работаем, добавляем файлики, создаем комит (автоматически произошел бекап)…
переключились на мастер верку, произшло переключения БД на предыдущее состояние…
вернулись в разработку, слили ветки, запушили. Т.е. бекапы автоматом создаются при комитах,
либо принудительно перед чекаутом, поведение настраивается в конфиге. Вы можете вручную вызывать экспорт либо импорт БД на сервере, с вашего локального компа, запуская соответствующий скрипт.
У каждого скрипта можно получить справку классическим путем через аргумент -h либо --help.
Я не рекомендую бекапить всю БД, гит не любит больших файлов, да и в большинстве случаев это и не нужно. Поэтому вы можете легко настроить используя config.ini
Так как настройки используются и на серверной стороне (на которой поднят mySql) и клиентской (комп разработчика), то за настройку отвечает один и тот же файл. И Конечно это может быть один и тот же компьютер, если вы ведете разработку локально.
Что можно настраивать для создания дампа
- Настройки подключения к БД и пути храния дампов
- Указание провайдера, который сможет не только получить данные подключения к БД, но
и правильно очистить кеш на сервере при переключении веток. - Экспорт всей БД
- Список таблиц которые нужно исключить из экспорта
- Либо экспорт определенных таблиц
- Сохранение структуры без вставки данных у определенных таблиц
- Указание полей у таблиц значения которых не должны экспортироваться, и должны
быть заменены значениями по умолчанию. - Отдельные наборы правил в одном конфиге, что позволит делать различные бекапы по CRON-у
Для того чтобы облегчить процесс создания дампов. Я использовал файлы — провайдеры. И настроил (пока один единственный) для CMS MODX revolution. На его основе можно написать такой же провайдер для любой CMS.
Краткие шаги к началу работы
Скачаем проект, рекомендую положить в папку рядом с .git, либо внутрь проекта, скрипт все равно найдет git
[git clone ](https://github.com/Setest/.git-db-watcher)
установим права на запуск на локальном компе и сервере
chmod +x install.sh;
ставим локально
./install.sh
ставим на сервере, где не нужны хуки
./install.sh -nh
Теперь необходимо внести правки в config.ini
. Для примера вот так:
;общий раздел
[hooks]
; H_CHECK_DB_HASH_BEFORE_CHECKOUT=1
; импорт файла БД даже если checkout происходит на эту же ветку
; также это правило распростроняется при переключении на вновь созданную ветку
; через git checkout -b new_branch_name
H_CHECKOUT_FORCE=0
; автоматическое добавление файла БД при каждом комите
H_CHECKOUT_EVERCOM=1
;автоматическая очистка директории кеша после переключения БД
H_CHECKOUT_CLEARCACHE=1
[common]
;результирующий файл в который будут экспортироваться данные
EXPORT_FILE="db.sql"
;на локальном компе используется из хуков гита и ручного экспорта БД
;через запуск файла ./export.sh
[develop]
;скрипт запуска db_export.sh на сервере
CLI_DB_EXPORT="ssh host '/path/to/project/on/server/.git-db-watcher/db_export.sh'"
CLI_DB_IMPORT="ssh host '/path/to/project/on/server/.git-db-watcher/db_import.sh'"
;только на сервере
[server]
PHP_PATH="/usr/local/bin/php"
CONFIG_INC_PATH="/path/to/project/on/server/core/config/config.inc.php"
PROVIDER=modx
DB_TABLES_INCLUDE=site_content
DB_TABLES_AUTOPREFIX=1
[server_full_site]
PHP_PATH="/usr/local/bin/php"
CONFIG_INC_PATH="/path/to/project/on/server/core/config/config.inc.php"
; '' - берет данные из настроек с префиксом DB_CONFIG_ иначе из файла лежащего
; папке providers
PROVIDER=modx
;не обязательно но можно указать настройки вручную если нет провайдера
DB_CONFIG_HOST=
DB_CONFIG_TYPE=
DB_CONFIG_USER=
DB_CONFIG_PASSWORD=
DB_CONFIG_CONNECTION_CHARSET=
DB_CONFIG_DBASE=
DB_CONFIG_TABLE_PREFIX=
DB_CONFIG_DATABASE_DSN=
;если указаны то будут экспортированы только эти таблицы (разделитель пробел)
;заворачивать строку в кавычки нельзя
; DB_TABLES_INCLUDE=manager_log register_messages user_attributes
; DB_TABLES_INCLUDE=site_content
;таблицы исключаемые из экспорта
; DB_TABLES_EXCLUDE=session register_messages mse2_words ec_messages
;добавление префиксов, взятых из файла конфигурации, к именам таблиц
DB_TABLES_AUTOPREFIX=1
;таблицы из которых будет удалены запросы на INSERT
DB_TABLES_REMOVE_INSERT="manager_log session register_messages"
; DB_TABLES_REMOVE_INSERT="manager_log"
;список таблиц поля которых будут выставлены по умолчанию
; DB_TABLES_DEFAULT=user_attributes users
DB_TABLES_DEFAULT=user_attributes
;список полей соответствующих таблице, значения кот будут выставлены
;по умолчанию в соответствие с со структурой таблицы, это не обязательно и
; можно не указывать
DB_TABLES_DEFAULT_user_attributes=sessionid logincount lastlogin thislogin
; DB_TABLES_DEFAULT_users=session_stale
;получает только пользователей, с удалением лишних данных
[only_users]
DB_TABLES_INCLUDE=user user_attributes
EXPORT_FILE="users.sql"
DB_TABLES_DEFAULT=user_attributes user
DB_TABLES_DEFAULT_user_attributes=sessionid logincount lastlogin thislogin
DB_TABLES_DEFAULT_users=session_stale
Если все настроено правильно можно запустить ./export.sh
и у вас должен
появиться дамп БД на локальном компе и на сервере.
Остальные вопросы
Мне нужно сохранить результат на сервере в другое место:
./db_export.sh --output 1>./xxx.sql
Хочу производить экспорт на сервере используя данные своего раздела файла конфигурации:
./db_export.sh -с=only_users --output 1>./users.sql
Хочу импортировать файл БД, но не хочу это делать через перехватчики GIT-а?
./import.sh
./import.sh EXPORT_FILE=site_name.sql
./import.sh DB_BACKUP_FILE=/.../../site_name.sql
./import.sh --config=site DB_BACKUP_FILE=./site_name.sql
A как производить импорт находясь на сервере?
./db_import.sh < db_backup/db.sql
В разных проектах я использую CMS xxx и мне надоело каждый раз вводить данные
для управления БД, как можно упростить процесс?
Для этого нужно написать свой файл провайдера по аналогии с имеющимися.
Я создал задание CRON и конфигурацию с использованием провайдера php, но оно
не выполняется, либо кеш сайта CMS не очищается, в чем может быть дело?
В зависимости от настроек сервера и самого задания, задания CRON могут запускаться совсем в другом окружении, в котором путь к php препроцессору может отличаться и как следствие, запускать совсем другую версию php не совместимую с той, на которой работает ваша CMS.
Послесловие
Я никогда не писал на BASH скрипты и поэтому вероятно наговнокодил, я уверен, тут есть грамотные ребята, которые в случае заинтересованности смогут добавить свои правки. Я же буду развивать проект по мере поступающего интереса и выявлении ошибок в работе.
И не стоит сразу вонять, что ничего не работает, возможно вы не смогли разобраться в том как произвести правильную настройку и установку (в особенности если вы работаете на Windows, все же BASH это линуксовая среда).
Инструкция по установке и использованию лежит в README. Я старался сразу писать на английском, но и из-за моего любительского уровня, возможно будет не все понятно, в дальнейшем напишу на русском. Если есть желание внести правки в перевод или код, форкайте на здоровье! A если есть хорошие советы — поделитесь.
P.S: если вы дочитали до саааааамого низа, значит Вам стало интересно и не терпится попробовать :-)
Комментарии (12)
andreymal
28.04.2019 18:35+1У меня почему-то никогда не возникало необходимости обновлять БД при переключении веток. Если я делаю какую-нибудь фичу с изменением схемы БД, то она чаще всего быстренько вливается в мастер и дальше живётся как обычно. Если всё же приспичит менять схему и не вливать в мастер, то я просто создам отдельную временную базу и не буду париться ни с какими синхронизациями
Контроль структуры таблиц осуществляется через миграции в любой ORM, как уже отметили выше. Бэкапы же данных храниться в git не должны (максимум — небольшой набор фикстур для начальной инициализации свежесозданной БД). Так что всё это выглядит довольно бессмысленно
происходит 500-я и вы не знаете почему
Дык логи читать надо
Для того, чтобы соблюсти контроль версии базы данных используя гит, очевидно нужно получать ее дампы
Не нужно, потому что миграции всё контролируют сами
rsashka
28.04.2019 18:45При хранении дампа БД в Git есть проблема нещадного разрастания размера коммитов, если сама БД довольно большая (например, в случае рабочего сайта с CMS).
А если скрипт упаковать, то он будет хранится обычным бинарным файлом.setest1 Автор
29.04.2019 17:50Есть такое, но если правильно настроить конфиг размер будет сильно уменьшен.
apapacy
28.04.2019 20:14Согласен со всеми кто против такого подхода. За маленьким исключением. Существует достаточно специфический класс сайтов это типа визитка без контента типа новостная лента и т.п. то есть практически статика. Но при разработке юзается cms с хранением в базе данных. Да там хранить дампы в git вполне допустимо т.к. ещё раз повторю это практически статика.
Автор намекает что имеет дело именно с такими сайтами просто не акцентировал на этом внимание. Хотя этот момент очень важен исходя из такого нестандартного решенияrsashka
28.04.2019 20:36+1Для таких сайтов достаточно единственного скрипта без какой либо интеграции с git. Это проще и значительно понятнее.
Например для Drupal 7#!/bin/bash # one argument: the file of config.php file d7config=$1 if [ ! -f "$d7config" ]; then echo "File '$d7config' not found." exit fi db=`cat $d7config | grep " 'database' => '" | awk -F"'" '{print $4}'` if [ -z $db ]; then echo "Database name not found in $d7config." exit fi user=`cat $d7config | grep " 'username' => '" | awk -F"'" '{print $4}'` if [ -z $user ]; then echo "Database user not found in $d7config." exit fi pw=`cat $d7config | grep " 'password' => '" | awk -F"'" '{print $4}'` if [ -z $pw ]; then echo "Database credentials not found in $d7config." exit fi #pr=`cat $d7config | grep " 'prefix' => '" | awk -F"'" '{print $4}'` tables_cmd="" ignore_cmd="" for t in "%cache%" "%history" "%search_%" "%sessions" "%watchdog" "%accesslog" do for t2 in `mysql $db --user=$user --password=$pw -Bse "show tables like \"$t\";"` do tables_cmd="$tables_cmd $t2" ignore_cmd="$ignore_cmd --ignore-table=$db.$t2" done done # Дамп данных без временных данных и кеша, одна строка данных в строке, без даты создания дампа, без создания БД. Добавление и удаление таблиц и все в одну транзакцию mysqldump --user=$user --password=$pw --extended-insert=FALSE --skip-dump-date --no-create-db --add-drop-table --single-transaction $ignore_cmd $db > mysqldump.sql # Дамп только структуры таблиц без данных, без даты создания дампа, без создания БД + добавить удаление таблиц mysqldump --user=$user --password=$pw --databases $db --skip-dump-date --no-create-db --add-drop-table --no-data --tables $tables_cmd >> mysqldump.sql
Valsha
29.04.2019 03:49Ну понятно что возможно автор не использует какой то Фреймворк типа yii2, laravel или Django. Но просто автор уж очень сильно уходит на «тёмную сторону», он и сразу пишет что исправления все на live сервере/сайте. То есть все как то уж очень по суровому. Если уж так все сурово сразу то зачем бекапы то тогда :)
speker
29.04.2019 17:46тут не про версионирование структуры бд, а про версионирования содержимого. Если я правильно понимаю в django для этого есть django-reversion
setest1 Автор
29.04.2019 17:45Я прекрасно понимаю, что есть миграции, и знаю что делать когда есть 500 итд, но помимо yii2, laravel или Django итд существует 100500 CMS и самописных монстров, которые развиваются небольшими командами и постепенно перемещаются в пекло из-за гуанокодеров и развития технологий. Правильная настройка конфига позволяет сохранять только структуру без содержимого, тогда рост минимален в таком случае, а что уж с ней делать потом это второй вопрос. Я думаю что если разраб будет пользоваться снимками структуры, то он прекрасно знает как этот вопрос решить.
questor
Практически в каждом ORM фреймворке есть нормальный инструмент для управления миграциями — поэтому собственная поделка на bash-скриптах имеет смысл только ну разве что для тренировки написания скриптов bash. В работе же лучше пользоваться проверенными временем решениями, которыми пользуется большинство разработчиков. Навскидку под PHP — phinx.org laravel.su/docs/5.0/eloquent
setest1 Автор
Да верно, отчасти это была тренировка в баше )