Как вручную синхронизировать базу данных с сервера разработки на рабочий сервер

#mysql #synchronization #mariadb

#MySQL #Синхронизация #mariadb

Вопрос:

Сервер / IP-адрес:

  • Сервер разработки: www-dev (172.22.12.42, Debian 10)
  • Сервер администрирования для www-dev: www-admin (172.22.69.25, Debian 10)
  • Рабочий сервер: graysonpeddie.com (172.22.203.247, CentOS 8)

Все мои IP-адреса являются частью сети ZeroTier.

Сценарий и исследование

Допустим, я только что опубликовал статью в своем блоге, используя панель администрирования (www-admin). www-admin подключается к базе данных в www-dev и вставляет новую строку в таблицу после завершения всех проверок в www-dev. Я проверяю, чтобы убедиться, что вижу новую статью в блоге, опубликованную в www-dev. Затем я делаю mysqldump из www-dev, scp файл .sql в graysonpeddie.com , ssh для graysonpeddie.com , и импортировал файл в мою базу данных MySQL.

Вот как выглядит панель администрирования для www-admin:

Панель администрирования, отображающая список статей блога

Панель администрирования, отображающая список категорий

Таким образом, панель администрирования в www-admin взаимодействует с сервером базы данных разработки в www-dev.

Все в порядке и отлично, но с помощью команд mysqldump, scp, ssh и mysql я хочу сделать все это одной командой. Может быть, что-то вроде:

mysqldump -u graysonpeddie_admin -p graysonpeddie_blog | ssh username@graysonpeddie.com "mysql -u graysonpeddie_admin -p graysonpeddie_blog"

Но это слишком много для ввода, и это всего лишь псевдо-пример. И, кроме того, мне пришлось бы пару раз вводить пароли как для сервера разработки, так и для сервера производственной базы данных.

Или, поскольку я настроил свой рабочий брандмауэр на открытие 3306 для 172.22.203.247 (кстати, это частный нулевой IP-адрес), я мог бы сделать что-то вроде этого:

mysqldump -u graysonpeddie_admin -p graysonpeddie_blog | mysql -u graysonpeddie_blog -p -h 172.22.203.247 graysonpeddie_blog

Но проблема в том, что я получаю Enter password: Enter password: , и это не сработает.

Я видел учебные пособия о том, как настроить репликацию master / slave, где сервер разработки будет основным, а производственный сервер будет подчиненным, но все изменения, которые я вношу в свой сервер разработки, будут автоматическими, а не ручными. Я хочу выполнить шаг репликации вручную. Это:

  1. Внесите изменения в базу данных на сервере разработки.
  2. Протестируйте изменения, посетив https[://]www-dev (я поставил [ и ], чтобы не делать www-dev ссылкой).
  3. Если все идет хорошо, внесите изменения в базу данных на рабочем сервере (graysonpeddie.com ).

Я имею в виду, есть ли еще одно слово для «ручного»? Противоположность «автоматическому»? Потому что я выполнил поиск в Google для ручной репликации mysql, и у меня даже была «ручная репликация» в кавычках. Это не помогло, поскольку это привело бы меня к mysql.com для получения руководства по настройке репликации. слово «ручной» имеет более одного определения.

В любом случае, я не возражаю против предложений по программному обеспечению, если оно с открытым исходным кодом и в GNU / GPL. Я посмотрел на Flyway, но я не уверен, что это можно разместить на моем сервере администрирования (www-admin). Однако, если я использую какой-либо способ управления версиями, я хочу сделать это в командной строке, чтобы я мог написать функциональность в своей панели администрирования, которая синхронизирует изменения с моего сервера разработки на рабочий сервер, но только если все идет хорошо на этапе тестирования.

Комментарии:

1. Я думаю, что вы подходите к настройке среды базы данных под неправильным углом! Вы должны написать код, который перемещает структуру базы данных и, возможно, некоторые данные поиска / конфигурации из одного выпуска в другой и сохранить его как часть вашей системы контроля версий кода и применить его как часть отправки нового кода на производственные серверы. Mysqldump слишком груб для этой задачи, поскольку он может экспортировать только существующую структуру, а не то, как вы переходите от одной версии к другой.

2. На самом деле, я думаю, что нашел страницу, которая позволяет мне реализовать синхронизацию базы данных в моей панели администрирования. Я скоро попробую. github.com/IvanPrat/PHPDBSync

3. Я не думаю, что синхронизация — отличная идея, могут быть части базы данных разработчиков, которые не готовы к переносу в производство, но это ваш вызов.

4. Ну, это зависит от того, является ли синхронизация хорошей идеей или нет. Я буду синхронизировать, когда буду хорошо знать, что все готово к синхронизации. В любом случае, у PHPDBSync есть некоторые проблемы, такие как Undefined variable: k_1 on line 371 и Undefined variable: database on line 371 , так что, по крайней мере, я протестировал код из GitHub в моей частной производственной базе данных (172.20.16.34 ), так что я очень рад, что сделал. Я собираюсь поискать другой код в GibHub, который более разработан, чем код, который я нашел в GitHub.

5. Я решил придумать скрипт, который выполняет mysqldump с уже введенными именем пользователя и паролем, который передает его в mysql с тем же именем пользователя и паролем, которые также заполнены. Затем я называю это dbsync.sh и затем введите shell_exec() команду php внутри functions.php а затем вызовите функцию изнутри класса контроллера. Я знаю, что функция shell_exec() и все функции exec() опасны, поэтому я не разрешаю ввод данных пользователем из интерфейса. Копирование всей структуры и данных — идея не для всех, но у меня есть вариант использования для этого, так что это работает.

Ответ №1:

Быстрое и грязное решение

Что у меня есть прямо сейчас, так это написать сценарий оболочки, который содержит имя пользователя и пароль для mysqldump mysql команд и.

Скрипт BASH

/home/grayson/bin/sync-db.sh

 #!/bin/bash
echo "Synchronizing data..."
mysqldump -u username -p'...' -h 172.20.16.32 graysonpeddie_blog | mysql -u username -p'...' -h 172.22.203.247 graysonpeddie_blog
if [ $? -eq 0 ]; then
    echo "OK"
fi
  

Оператор else не требуется, если есть сообщение об ошибке от mysqldump или mysql.

DBSyncController Класс контроллера

/var/www/admin.graysonpeddie.com/controller/dbsynccontroller.php

 <?php

include_once $_SERVER["DOCUMENT_ROOT"]."/includes/controller.inc";

class DBSyncController extends Controller
{
    public function httpget_index()
    {
        $this->View([]);
    }

    public function httpget_sync()
    {
        include_once $_SERVER["DOCUMENT_ROOT"]
            ."/includes/functions.inc";
        $this->View(["DBSync",dbsync_devprod()]);
    }
}
  

httpget_sync Метод отображает страницу результатов.

Функция: от разработки к производству

 <?php
function dbsync_devprod()
{
    return shell_exec('/home/grayson/bin/db-sync.sh');
}
  

Обратите внимание, что exec() ряд функций, таких как shell_exec() , представляет угрозу безопасности, но поскольку моя панель администрирования находится на моем домашнем сервере, а не в Интернете, shell_exec() функция мне подходит, на данный момент.

Долгосрочное решение

Я создал класс BlogModel, чтобы он мог подключаться к локальному или удаленному серверу базы данных. Я создал пару таблиц состояний синхронизации для MySQL. Под «состоянием синхронизации» я подразумевал что-то вроде этого:

/var/www/admin.graysonpeddie.com/model/blogmodel.php

 // Local database only
abstract class SyncState
{
    const CURRENT = 0; // No changes need to be made.
    const NEW     = 1; // A new blog article needs to be copied.
    const UPDATE  = 2; // Update the data in table in the remote database.
    const DELETE  = 3; // Delete the data from the table in remote database.
}
  

И у меня есть пара функций состояния синхронизации в моем BlogModel классе. Все административные хранимые процедуры выглядят одинаково в локальной и удаленной базе данных, за исключением того, что удаленная база данных не содержит таблиц и хранимых процедур для состояний синхронизации.

     // Public functions for Sync states - local database only
    public function SetSyncState_BlogArticles($id,$syncstate)
    {
        $this->SetSyncState($id,$syncstate,"BlogArticles");
    }

    public function SetSyncState_BlogArticlesCategories($id,$syncstate)
    {
        $this->SetSyncState($id,$syncstate,"BlogArticlesCategories");
    }

    public function SetSyncState_BlogArticlesTags($id,$syncstate)
    {
        $this->SetSyncState($id,$syncstate,"BlogArticlesTags");
    }

    private function SetSyncState($id,$syncstate,$table)
    {
        if($this->local)
        {
            $stmt = $this->db->prepare("CALL SetSyncState_".$table."(?, ?)");
            $stmt->bindParam(1, $id, PDO::PARAM_INT);
            $stmt->bindParam(2, $syncstate, PDO::PARAM_INT);
            $stmt->execute();
        } else die("Local database only. Can't set a sync state in the remote database.");
    }
  

Я думал о создании двух классов, которые расширяют класс BlogModel, но я хочу упростить его.

SQL

И пример таблицы, содержащей все состояния для каждой строки.

Запрос

 SELECT ba.BlogArticleID, ba.SyncState AS "BlogArticles",
       bac.SyncState AS "BlogArticlesCategories",
       bat.SyncState AS "BlogArticlesTags"
  FROM SyncState_BlogArticles ba
 INNER JOIN SyncState_BlogArticlesCategories bac ON ba.BlogArticleID = bac.BlogArticleID
 INNER JOIN SyncState_BlogArticlesTags bat ON ba.BlogArticleID = bat.BlogArticleID;
  

Результат

  --------------- -------------- ------------------------ ------------------ 
| BlogArticleID | BlogArticles | BlogArticlesCategories | BlogArticlesTags |
 --------------- -------------- ------------------------ ------------------ 
|             1 |            0 |                      0 |                0 |
|             2 |            0 |                      0 |                0 |
|             5 |            0 |                      0 |                0 |
|             7 |            0 |                      0 |                0 |
|             8 |            0 |                      0 |                0 |
|             9 |            0 |                      0 |                0 |
|            10 |            0 |                      0 |                0 |
 --------------- -------------- ------------------------ ------------------ 
  

BlogArticleID соответствует всему моему блогу на моем веб-сайте (https://graysonpeddie.com ). три столбца после этого содержат состояние в зависимости от того, нужно ли добавлять, обновлять или удалять строку. Если бы я установил состояние BlogArticles равным 1 для BlogArticleID, равного 11, моя панель администрирования вызовет a $local->ShowBlogArticleByID(...) для получения данных из локальной базы данных, а затем скопирует данные в удаленную базу данных путем вызова $remote->WriteBlogArticle(...) . Переменные $local и $remote имеют BlogModel object .

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

Как это работает после завершения?

Как только я напишу статью в блоге, моя панель администратора вызовет SetSyncState_BlogArticles() , SetSyncState_BlogArticlesCategories() , и SetSyncState_BlogArticlesTags() для syncState::NEW , что равно 1.

После этого, чтобы синхронизировать мои изменения с удаленной базой данных, я просто перехожу в раздел «Синхронизировать базу данных» на панели администрирования и нажимаю «Синхронизировать с рабочей базой данных». WriteBlogArticle() вызывается, если для состояния BlogArticles установлено значение 1, и это состояние является «НОВЫМ».

Что, если я удалил статью в блоге? То же самое, но на этот раз статья будет удалена, а строка в graysonpeddie_blogadmin.SyncState_BlogArticles таблице будет автоматически удалена для поддержания согласованности с graysonpeddie_blog.BlogArticles таблицей.

И то же самое для обновления данных в базе данных.

Тем не менее, я буду выполнять «пробный запуск», чтобы убедиться, что я хочу внести изменения, прежде чем я это сделаю, чтобы избежать ошибок на моем рабочем сервере. В этом случае, поскольку я все еще работаю над написанием кода для синхронизации с одной локальной базы данных на удаленную, у меня есть другая настройка виртуальной машины в качестве игровой площадки. Возможно, «промежуточная» виртуальная машина, чтобы убедиться, что все работает, прежде чем я внесу изменения на свой рабочий сервер.

Краткие сведения

В своем посте я подробно рассказал о синхронизации с локального на удаленный сервер базы данных. Пока я полностью не реализовал код для синхронизации с локальной на удаленную базу данных, я все равно буду продолжать использовать грубое решение для выполнения сценария оболочки.

И да, все это требует много работы, но я уже бросил вызов msyelf, когда создал свой собственный движок блога с нуля! Итак, что я сделал для своего веб-сайта (https://graysonpeddie.com ) считается большим проектом. Вот почему я не использую WordPress, Drupal или любые другие готовые решения CMS! Все, что я хочу, это что-то очень легкое, предназначенное только для одного автора, такого как я, очень безопасное с нуля и в полной мере использует парадигму MVC (Model-View-Controller). И знаете что? Это сработало! И все, что мне нужно сделать сейчас, это написать код синхронизации и все!

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