Syncman — развертывание и синхронизация проектов на удаленном сервере

    Syncman
    Прежде, чем начать свой рассказ, задам один маленький вопрос: Как вы разворачиваете свои проекты сервере?
    Если вами управляется один маленький сайтик на бесплатном виртуальном хостинге, то проблемы синхронизации у вас не возникают — подключился по ftp, скопировал файлы и все. А если нужно контролировать развертывание нескольких сотен проектов (от маленьких сайтов визиток до нагруженных приложений), над которыми трудится не один десяток людей? Если позволяет квалификация, то можно использовать rsync, unison и др. Особо отчаянные могут просто обновлять рабочую копию проекта (svn, git и тд.) из репозитория. А что будут делать десятки художников, которым срочно нужно поправить вот ту маленькую картинку? Ведь для многих из них консоль — волшебный темный дремучий лес.
    Под катом описание одного решения, позволяющего сильно упростить процесс развертывания приложений.

    Страна должна знать своих героев

    Проект Syncman уже имеет довольно большую историю, но, как мне кажется, свою актуальность до сих по не потерял. Спасибо pachanga, korchasa, romankitaev,wIliam, dbrain и др., кого не смог найти на Хабре. Все это действующие и бывшие сотрудники компании БИТ Creative. Благодаря им этот проект появился и до сих пор живет. Работая с ними, я многому научился.

    Виновник торжества

    Сегодня под прицелом замечательный opensource проект Syncman.
    Syncman ставит себе главной целью облегчить синхронизацю удаленных проектов так, чтобы даже люди далекие от программирование (например, художники, дизайнеры, менеджеры и др.) могли самостоятельно синхронизировать проекты с удаленными серверами.
    Syncman имеет отличные Web и консольный интерфесы. Ниже приведены скриншоты Web-интерфейса Syncman.
    Ничего лишнего. Список проектов, разбитый по группам. Для каждого проекта, кнопочки синхронизировать, посмотреть изменения, откатить изменения. При выборе определенного проекта, можно посмотреть его текущие настройки. Если проект синхронизирован, то он выделен зеленым цветом. Если были новые коммиты, которых нет на удаленном сервере, то цвет — красный.
    После настройки проекта его синхронизация сводится к следующей последовательности действий:
    1. Изменил проект
    2. Сделал коммит в репозиторий
    3. Нажал в Web-интерфейсе Syncman кнопочку «Синхронизировать проект»

    Со временем к этому сильно привыкаешь, например, я синхронизирую примерно так:
      .....
      svn commit -m "my changes"
      syncman project_to_sync
    

    Все проект синхронизирован.

    Что делает Syncman во время синхронизации?

    Синхронизация проходит в 4 основных этапа:
    1. Проект выбирается или обновляется из репозитория во временную папку на сервере Syncman, где-то в локальной сети.
    2. Выполняется команда presync_cmd, задаваемая в настройках проекта. На этой стадии подготавливается макет для развертывания. К примеру, presync_cmd может удалить файлы, которым на удаленном сервере делать нечего: например, можно удалит временные каталоги, ненужные дизайны, файлы модульных тестов.
    3. Развертывание проекта. Обычно, это делается с использованием rsync по SSH, но не обязательно. Например можно использовать FTP (если невозможно организовать доступ для rsync).
    4. На последнем этапе выполняется команда postsync_cmd, задаваемая в настройках проекта. Обычно эта команда выполняется по SSH, но это совершенно не обязательно. Задача этой команды, убрать файлы, устаревшие после развертывания (например, в Limb кэшируются некоторые пути, шаблоны и др.), кроме, того могут применяться миграции для базы данных.


    Основные характеристики

    Я использую данное решение очень давно. Функционала было достаточно, и после переезда Syncman на github совершенно не следил за изменениями. Собственно эти изменения и подтолкнули меня написать данный пост. Итак Syncman:
    • Проект с открытым кодом;
    • Написан на php;
    • Основан на фреймворке Limb3;
    • Легко настраивается;
    • Гибок в настройках. Чаще хватает стандартных настроек (о них ниже), но через конфигурационный файл проекта можно переопределить практически все комманды, чтобы удовлетворить самого требовательного пользователя;
    • Код Syncman гибок. Все таки это сын проекта Limb3! Собственно о расширении функционала чуть ниже;
    • Из коробки работает с репозиториями svn и git;
    • Из коробки поддерживает синхронизацию по SSH с использованием rsync и по FTP;
    • Прост в использовании. Для выполнения синхронизации не нужно обладать специфичными знаниями.

    Как настроить Syncman?

    Разберем все по пунктам:
    1. Забрать файлы из репозитория
      cd /path/to/hosts
      git clone https://github.com/limb-php-framework/limb-app-syncman.git syncman
      git submodule init
      git submodule update
    

    2. Добавляем новый виртуальный хост
    Например, например если вы используете apache, то конфиг может быть таким:
    Стандартный конфиг
    <VirtualHost 192.168.0.xxx:80>
      ServerName syncman
      DocumentRoot /home/user/syncman/www
      
      <Directory />
        Options FollowSymLinks
        AllowOverride All
      </Directory>
      
      
      <Directory /home/user/syncman/www>
        Options Indexes FollowSymLinks MultiViews
        AllowOverride All
        Order allow,deny
        allow from all
      </Directory>
        
      ErrorLog /tmp/apache_syncman_error.log
      LogLevel warn
      CustomLog /tmp/apache_syncman_access.log combined
    </VirtualHost>
    


    Если web-интерфейс использовать не планируется, то этот пункт можно пропустить.

    3. Настройка проектов
    3.1. Краткий пример
    Если следовать описанию выше, то загруженные файлы должны находиться в папке /path/to/hosts/syncman. Тогда все проекты должны храниться в каталоге /path/to/hosts/syncman/projects.
    Для каждого проекта создается отдельная папка. Имя этой папки — название проекта. В папке проекта лежит один единственный файл settings.conf.php с настройками проекта.
    Пример конфигурационного файла1
    $conf = array(
       //Настройки доступа к удаленному серверу, и папка проекта на нем
      'server' => array(
        'host' => 'myhost.com',
        'user' => 'syncman',
        'password' => 'qwerty',
        'remote_dir' => '/var/www/myhost.com',
      ),
      
      //Настройки репозитория, в данном случае git
      'repository' => array(
        //-- allowed types: git, svn
        'type' => 'git',
        'path' => 'myrepos/myhost.com/',
        'branch' => 'project_branch',
      ),
      
      //Как синхронизировать
      //-- allowed types: rsync, ftp
      'type_sync' => 'ftp',
       
      //Подготовка, данная команда выполнится на сервере Syncman
      'presync_cmd' => 'php %local_dir%/cli/pre_sync.php',
      //данная команда выполнится на удаленном сервере после того, как файлы будут синхронизированы
      'postsync_cmd' => 'ssh -i %key% %user%@%host% \'php %remote_dir%/cli/post_sync.php\'',
      
      //история для ftp не работает
      'history' => false,
      //Группировка проектов
      'category' => 'MyCategory',
    );
    


    Пример конфигурационного файла2
    $conf = array(
       //Настройки сервера, синхронизация через SSH
      'server' => array(
        'host' => 'myhost.com',
        'user' => 'syncman',
        'port' => 22,
        'key' => '/home/syncman/.ssh/id_dsa',
        'remote_dir' => '/var/www/myhost.com',
      ),
       
      //Настройки репозитория, в данном случае Subversion
      'repository' => array(
        //-- allowed types: git, svn
        'type' => 'svn',
        'path' => 'myrepos/myhost.com/trunk',
      ),
      
      //Синхронизируем rsync поверх SSH
      //-- allowed types: rsync, ftp
      'type_sync' => 'rsync',
      
      //см. первый пример
      'presync_cmd' => 'php %local_dir%/cli/pre_sync.php',
      'postsync_cmd' => 'ssh -i %key% %user%@%host% \'php %remote_dir%/cli/post_sync.php\'',
      
      //история синхронизации включена
      'history' => true,
      //Группировка проектов
      'category' => 'MyCategory',
       //переопределяем некоторые стандартные настройки.
       //!!!можно использовать, если четко представляете что они делают
      'ssh_get_date' => "date +%F_%R",
      'ssh_mkdir' => "mkdir -p \$dir",
      'ssh_ln_edit' => "rm -f \$ln_path; ln -s \$new_dir \$ln_path;",
      'ssh_cp' => "cp -pRT \$dir_of/ \$dir_in/", // для первого раза можно добавить в конце &> /dev/null
      'ssh_ls' => "ls -F --classify -1 \$dir",
      'ssh_preg_dir' => "/(.)+\//",
      'ssh_readlink' => "readlink -v \$link",
    );
    



    3.2. Пример подробный. Пошаговая инструкция
    Если после прочтения примера 3.1. Все равно не понятно как настроить проект, то...
    подробная инструкция
    Разберем второй пример более подробно:
    1. Заходим на сервер Syncman по SSH (Предполагаем, что Syncman расположен не на вашем компьютере);
    2. Перейдите в каталог Syncman, если каталог projects не создан, то создаем его;
    3. Переходим в каталог projects, и создаем папку проекта myhost.com;
    4. Переходим в папку myhost.com и при помощи вашего любимого текстового редактора создаем файл settings.conf.php (содержание как в примере 2);
    5. Предполагаем, что синхронизация будет выполняться по SSH (как показывает опыт, это самый частоиспользуемый вариант).
    6. Если требуется, создаем пару ключей для SSH при помощи ssh-keygen. Публичный ключ копируем на удаленный сервер проекта myhost.com, авторизуем его. Путь к секретной части прописываем в секции key.
    7. При написании конфига можно менять любые настройки. Более того, если при задании настройки указать %name%, то вместо данного шаблона будет подставлено соответствующее значение (см., например, задание команды postsync_cmd).
    8. Далее создаем скрипт cli/pre_sync.php в репозитории вашего проекта.
      Типичный пример pre_sync.php для Limb приложений
      echo "Pre syncing...\n";
      
      //Каталоги для удаления
      $remove_dirs = array($all_shared = dirname(__FILE__) . "/../www/shared");
      $remove_dirs[] = dirname(__FILE__) . "/../_docs";
      
      //удаление каталогов
      foreach($remove_dirs as $dir)
        `rm -rf $dir`;
      
      //создание каталогов и перемещение файлов
      mkdir($all_shared);
      foreach(glob(dirname(__FILE__) . "/../lib/limb/*/shared") as $pkg_shared)
      {
        echo "Moving $pkg_shared..\n";
        $pkg = basename(dirname($pkg_shared));
        rename($pkg_shared, "$all_shared/$pkg");
      }
      echo "done.\n";
      

    9. Далее создаем скрипт cli/post_sync.php в репозитории вашего проекта.
      Типичный пример post_sync.php для Limb приложений
      $dir = dirname(__FILE__);
      
      echo "Post syncing...\n";
      include('migrate.php');//миграция базы
      
      `rm -rf $dir/../var/compiled`;
      `rm -rf $dir/../var/locale`;
      `rm -rf $dir/../var/locators`;
      `rm -f $dir/../var/db_info*`;
      echo "done.\n";
      

    10. Оба последних файла должны быть добавлены в репозиторий и синхронизироваться вместе с проектом.
    11. Все проект настроен.


    Естественно, пункты 1-2 выполняются лишь один раз. Пункт 3 выполняется 1 раз для каждого проекта.
    4. Развертывание и синхронизация
    С использованием web-интерфейса
    Для синхронизации проекта требуется открыть веб-адрес, по которому расположен Syncman, в любом браузере. Если все было сделано правильно, вы должны увидеть ваш myhost.com проект в списке проектов.
    Projects
    Нажмите на кнопку «Синзронизировать». Должно открыться новое окно, в котором будет показан журнал синхронизации.
    Sync
    Если требуется посмотреть изменения нажмите на кнопку «показать изменения». Должно открыться новое окно, в котором будет показан журнал синхронизации.
    Diff
    Из консоли
    Выше был упомянут консольный интерфейс. Все скрипты для выполнения синхронизации из консоли, лежат в папке bin проекта Syncman.
    Скрипт sync.php старая версия скрипта для синхронизации. Пример использования:
      sync.php <project>[,<project>,<project>...]
      или
      php sync.php <project>[,<project>,<project>...]
    

    Кроме того, есть новый вариант данного скрипта — syncman.php — обладающий более широкими возможностями. Работа основана на пакете taskman.
    Расширение поведения Syncman

    В Syncman все крутится вокруг класса Project, поэтому для понимания работы приложения стоит разобраться с этим классом. На первый взгляд может показаться, что там все сложно. Но это только кажется. Project наследуется от класса фреймворка Limb — lmbOblect. Именно с lmbOblect и надо начинать изучать Project, тогда сложностей не возникнет.
    Для добавления поддержки новых систем контроля версий, требуется написать класс для поддержки соответствующей системы контроля версий по аналогии с классами SvnRepository и GitRepository. Их можно найти в каталоге src/model/. После того как ваш класс будет готов требуется внести изменения в класс RepositoryFactory (лежит в каталоге src/factory).
    Для добавления поддержки новых типов транспорта при синхронизации, требуется написать соответствующий класс по аналогии с классами RSyncProjectSync и FtpProjectSync. Их можно найти в каталоге src/model/. После того как ваш класс будет готов требуется внести изменения в класс ProjectSyncFactory (лежит в каталоге src/factory).

    Заключение

    Для меня Web-программирование лишь хобби, и совершенно не хочется тратить время на ручную синхронизацию моих сайтов. В этом мне помогает Syncman. И поверьте его использование сэкономило мне не один десяток часов моего личного бесценного времени.
    Данное приложение родилось в компании БИТ Creative. С его помощью они синхронизируют сотни проектов. Представьте себе сколько времени экономят они.
    Надеюсь, я заинтересовал своего читателя. И тем самым вызвал в нем интерес к Syncman и Limb.

    Ссылки

    Поделиться публикацией

    Похожие публикации

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

      +1
      Последние коммиты в проекте были 2 года назад. Не означает ли это что проект заброшен?
        0
        Тут логика такая. Если вас все устраивает — отлично, пользуйтесь. Нужно исправить ошибки или добавить функциональности — милости просим, новизна приветствуется. Просто текущая функциональность вполне устраивает пользователей проекта.
        +3
        какие только костыли не вспоминают, лишь бы configuration management не изучать.
          0
          При чем здесь Configuration management? Syncman не решает его задачи. Его цель — уже подготовленный (возможно, с использосанием CM) программный продукт отправить на сервер.
            0
            именно, потому что configuration management должен решать задачи деплоя.
              0
              CM — это методология, и она никак не поможет выгрузить данные на сервер. Для этого потребуется некий инструмент.
          0
          Это все здорово, но:
          — как делать откат?
          — что видят юзеры сайта в момент синхронизации? (половина файлов старая, половина новая)
            0
            В настройках проекта можно указать, опцию history=true. Я ей никогда не пользовался.
            Но работает вроде бы как-то так:
            Сервер натравливается на символьную ссылку. Эта ссылка указывает на текущую версию проекта.
            Для каждой синхронизации создается папка, обозначенная датой. Из текущей копии все переписывается в эту папку. Затем символьная ссылка заменяется ссылкой на эту новую папку. И синхронизация выполняется уже в новой папке. При необходимости отката — жмете кнопку «откатить изменения», и ссылка опять указывает на старую папку. Работает, к сожалению только для файлов.

            Как правило, все происходит быстро (rsync копирует только изменившиеся файлы) и ничего показывать не надо. Но чисто технически в presync_cmd можно установить для nginx редирект на статическую страницу, а в postsync_cmd — соответственно, его убрать.
            –1
            Хотелось бы увидеть сравнение с Jenkins.

            Только полноправные пользователи могут оставлять комментарии. Войдите, пожалуйста.

            Самое читаемое