Деплой проекта на сервер из Github

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

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

А потом я наткнулся на ранее неизвестные мне возможности Git — его хуки.

Читаем документацию и видим, что
Хук post-merge запускается после успешного выполнения команды merge. Его можно использовать для восстановления данных в рабочей директории, которые Git не может отслеживать, такие как права доступа. Так же этот хук может проверять наличие внешних по отношению к Git файлов, которые вы захотите скопировать при внесении изменений.
А это значит, что мы можем запускать любые произвольные скрипты при успешном скачивании изменений из Git. Так что нам нужно сделать 6 простых шагов:

1. Генерируем SSH ключ для Github
ssh-keygen -t rsa -b 4096 -C "your_email@example.com"
сохраняем его в какую-нибудь временную директорию с именем id_rsa. Не затрите случайно свой основной ключ в системе!

Я сохраняю в директорию Downloads.

2. Добавляем публичную часть ключа в репозиторий своего проекта
Нам нужно вставить содержимое id_rsa.pub в настройки Deploy Keys проекта на Github:
cat ~/Downloads/id_rsa.pub


Allow write access не отмечаем! нам же не нужно, чтобы при взломе хостинга была возможность что-нибудь натворить с репозиторием проекта, правда?

3. Устанавливаем приватную часть ключа юзеру хостинга
Нужно скопировать содержимое cat ~/Downloads/id_rsa на своём компе и вставить в nano ~/.ssh/id_rsa на хостинге. Если на хостинге уже есть какой-то основной ключ у юзера — не затрите его! Лучше поищите как сохранять несколько ключей и использовать их раздельно для разных подключений.

Еще нужно указать строгие права на свой ключ: chmod 600 ~/.ssh/id_rsa

4. Скачиваем этот репозиторий в рабочую директорию сервера
Ну тут просто git clone git@github.com:username/project.git — смотрите точнее у себя на Github. Главное, чтобы доступ был именно по SSH — мы же для него ключ и установили.

Лично у меня каждый проект на сервере под своим юзером и в своей рабочей директории, поэтому я и скачиваю его в корень этой директории. Если Git будет ругаться, что файлы уже существуют, то нужно сделать pull во временную директорию, а потом перенести всё оттуда в корень, включая скрытую .git.

Вот так это выглядит в итоге:


Смысл в том, чтобы дальше вы могли делать git pull из корня проекта, и это бы обновляло все ваши файлы в нём из репозитория.
В принципе, подобная возможность скачивания обновлений уже решает некоторые проблемы, например когда из-за неустойчивого соединения при выгрузке из PhpStorm, весь сайт падает от того, что половина файлов новая, а другая еще нет.

5. Но мы идём дальше и создаём наш хук post-merge:
nano ~/.git/hooks/post-merge
Где пишем что-то вроде
#!/bin/bash

/usr/bin/composer install --working-dir ~/core --no-dev
php ~/core/vendor/bin/phinx migrate -c ~/core/phinx.php
cd ~/frontend && ./node_modules/.bin/yarn install
cd ~/frontend && ./node_modules/.bin/yarn build
cd ~/frontend && ./node_modules/.bin/yarn restart
Ну или какие у вас там скрипты? Вот их и пишите.

Теперь при успешном git pull, когда есть какие-то изменения, будут запускаться эти команды.

6. Осталось только добавить проверку в cron
crontab -e
И пишем
MAILTO=your_email@example.com

*/30 *     * * *    git pull
И тогда каждые 30 минут будет проверяться ваш репозиторий.

Вам нужно только пушить ваш протестированый код в основную ветку на Github, откуда его загрузит рабочий сервер, а хук post-merge запустит ваши скрипты. Отчеты об успешной работе или об ошибках (если таковые будут) прилетят на почту, указанную в MAILTO — их пришлёт сам cron.

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

Лично мне такая простая настройка проектов очень сильно облегчает жизнь уже полгода. Никаких недостатков за это время я не нашёл, так что делюсь этим способом с вами.
Василий Наумкин
01 октября 2020, 11:54
modx.pro
6
844
+19

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

Misha Bulic
01 октября 2020, 12:18
0
а можно ли как то вместе с этим и базу синхронизировать?
    Василий Наумкин
    01 октября 2020, 12:24
    0
    Миграции и так синхронизируются — они в файлах, и хранятся в Git.

    А содержимое БД версионировать это странная какая-то идея, она же на десятки гигабайт может быть.
      Павел Бигель
      01 октября 2020, 12:31
      +1
      Ты просто никаким образом не пометил что это не для MODX, поэтому люди будут задавать такие вопросы :)
      А вообще да в xpdo миграций нет, поэтому нужно сэтапить CI интеграции используя транспортные пакеты.
        Василий Наумкин
        01 октября 2020, 15:50
        0
        Ты просто никаким образом не пометил что это не для MODX
        А какая разница? Если MODX, то что, нужно всю БД в Git хранить?

        Давно придуманы и Gitify, и файловые элементы.

        А вообще да в xpdo миграций нет
        А причём здесь xPDO? У меня миграциями Phinx занимается, ему не важно какие команды выполнять, хоть mysqli_execute пиши. Это же просто набор PHP скриптов, которые накатываются и откатываются в определённом порядке.

        Заметка вообще про хуки Git, без привязки к системам.
          Александр Мельник
          01 октября 2020, 21:31
          0
          Подскажите, я полистал документацию по phinx. Я правильно понял что это не просто инструмент для создания таблиц на основании php миграций, а это полностью ORM? Вижу тут и работу с данными, и выборки и условия. То есть отдельно ORM вы в проекте уже не пользуетесь типа Eloquent или Doctrine?
            Василий Наумкин
            02 октября 2020, 06:44
            0
            Я правильно понял что
            Нет, это консольная утилита для запуска миграций.

            Просто она из CakePHP, поэтому и в документации примеры по работе внутри этой системы. Но и без неё Phinx отлично самостоятельно запускает миграции.

            То есть отдельно ORM вы в проекте уже не пользуетесь типа Eloquent или Doctrine?
            Именно Eloquent я везде и использую.
    Андрей Степаненко
    02 октября 2020, 10:33
    0
    К этой схеме работы можно еще добавить плагин в phpStrom называется phinG. То есть в ручную запустить на удаленном сервере этот баш.
    Мануал по нему somethingabout.ru/post/phing-deploy-proekta-na-prodakshen-v-1-klik
      Василий Наумкин
      02 октября 2020, 10:43
      0
      Зачем какие-то плагины к IDE, если SSH и так умеет запускать команды на удалённом сервере?
      ssh email@example.com ls -lsh
      Это выведет тебе файлы в директории юзера, под которым ты авторизуешься.

      Точно так же можно делать и git pull, но делать вручную мне это лень, так что я повесил задачу на cron.

      Плюс, если ты работаешь в команде, то в master могут пушать несколько человек, и при моей схеме им всем вообще не нужно давать доступа к серверу, и тем более не нужно ничего для этого у себя настраивать.
        Андрей Степаненко
        02 октября 2020, 10:49
        0
        Дак я про альтернативу и не говорю. Это как раз для ленивых чтобы на сервер не заходить постоянно: prnt.sc/urq1ve
        .
        Можно любую команду удаленно выполнить.
      Александр Мельник
      02 октября 2020, 12:36
      0
      Основной посыл Василия понятен. Поскольку он при разработке пользуется всякими системами сборки типа вебпака, миграциями баз данных, то он автоматизирует процесс запуска этих моментов, написав некий bash скрипт, который выполняется как хук для git, а сам git запускается по крону. Хороший вариант и как информация — интересно.
      Мне показалось слишком запутанным манипуляции с ssh ключами. Но я наверное не знаю что такое deploy ключи, всегда пользовался просто ssh ключем который можно указать в настройках аккаунта, а не отдельного репозитория.
      Василий (а может и не только Василий), а поделитесь ка пожалуйста такой информацией если найдете минуту. Знаю вы активно используете webpack. Вчера у меня было время и я ради интереса решил ознакомится с инструментом этим. Разумеется поверхностно. И мне показалось что это хороший инструмент для верстки, для статичных сайтов или же для проектов на чистом js. И мое самое большое недоумение — это как этим пользоваться на php фреймворках. Как бы так описать, что вызвало это недоумение. Вебпак так или иначе собирает скрипты, стили в файлы и в имени файла есть некий хеш, чтобы избежать кеширования в браузере пользователя. Эти файлы должны как-то подключаться в шаблон. Так вот на всех примерах и видео которые я просмотрел, все это происходило так — был отдельно файл index.html в котором создавался html код. а потом вебпак при сборке этот файл обрабатывал, добавлял к нему подключение файлов c учетом хеша в имени. Но в php фреймворках у нас нет готового заранее html. Я вот использую например twig шаблонизатор и все что есть — это его файлы. Как это решаете вы? Как в ваши html шаблоны подключаются файлы, генерируемые вебпаком? И второе недоумение вызвал devServer вебпака. Удобная штука, хранит бандлы в оперативной памяти и все такое, но это ведь сервер на js? на node js вернее и он никак не сможет запустить php и отобразить страницу в браузере?
        Алексей Соин
        02 октября 2020, 14:33
        +1
        так вебпак и не будет работать с php, если рассматривать связку вебпака с php бекендом, то это какраз получится spa приложение, где фронт отдельно, бэк отдельно, на фронте через вебпак собираются js, css, html делаются запросы к php и получается продукт. Вебпак может быть использован при сборке бекенда, но только если бекенд написан на nodejs.
          Александр Мельник
          02 октября 2020, 14:48
          0
          ну я просто в вебпаке совсем профан, но да — почувствовал вчера, что он совсем не годиться для обычного php фреймворка. Не какихто новомодных spa и прочих, а там где html формируется на сервере.
          Спасибо, вы подтвердили мое мнение.
            Николай Савин
            02 октября 2020, 15:40
            +1
            Это ошибочное поспешное мнение.
            Во первых webpack не обязательно создает хешированные имена файлов, а вполне себе способен перезаписывать один и тот же файл — достаточно при конфигурации имя указать.
            Да собственно и все. Во-вторых писать не зачем.
            Собираете фронт у себя на компьютере, выгружаете на сервер. Точно так же, как если бы работал с GULP сборщиком например.
              Александр Мельник
              02 октября 2020, 16:15
              0
              наверное вы правы, да.
              Вроде бы и можно использовать, а вроде как из пушки по воробьям стрелять.
              По крайней мере выгоды перед галпом никакой, а в изучении сложнее.
              Да и например в фреймворке Yii2 там есть свой механизм перемещения статичных файлов (изображений, стилей, js — ок) в публичную директорию и мне кажется это будет конфликтовать.
              Но это так — совершенно не на чем не основанные выводы, никогда не использовал ни webpack ни gulp, да и что-то подсказывает что не буду.
              Вчера смотрел видео по webpack (хорошее и качественное) и ловил себя на мысли, что я не понимаю и не принимаю новых тенденций. В предыстории говориться, что в незапамятные времена скрипты в проект подключали просто ужасно через script src = и это так ужасно. Что человечество изобрело вебпак. И после этого начинается — установим nodejs, установим вебпак. А в это время в терминале где отображается ход установки — загружено 24658 файлов в node_modules. Установим кучу плагинов, создадим безумный конфигурационный файл, будем каждый раз запускать пересборку всего проекта, когда добавили строчку в код. И по итогу одна строка console.log('hello world') в нашем скрипте превращяется в 100 строк (без шуток) кода в сгенерированном вебпаком файле, в котором код запускается через eval и… у всех это вызывает радость и восторг.
              Наверное я просто не пишу настолько сложного кода, чтобы данный инструмент начал приносить удовольствие, а не раздражение.
                Николай Савин
                02 октября 2020, 16:26
                +1
                Ну если на JS только hello world писать — то конечно это бессмысленое занятие.
                А если в проекте половина на JS написана — это уже другой разговор.
                А попробуйте разделять код проекта на логические модули, каждый из которых находится в отдельном файле.
                А попробуйте еще библиотеки и инструменты для работы подключать из npm например.

                Чтобы еще раз не отвечать зачем вообще все эти node_modules если можно любую нужную библиотеку локально скачать — сразу отвечу. Чтобы через полгода одной командой npm update обновить сразу все используемые библиотеки и зависимости.
                Вы же наверное следите чтобы версия MODX свежей была на тех проектах, за которые отвечаете.
                Так и за другими составными частями следить нужно. А использовать NPM это самый простой способ.

                И еще позволю себе совет — вместо того чтобы в каждой ветке новые длиннющие рассуждения писать — было бы полезно тратить этот час в день на самообразование. Но это лишь мое мнение, которое я просто оставлю здесь. Спасибо. Пойду займусь самообразованием ))
                  Александр Мельник
                  02 октября 2020, 16:39
                  0
                  правы как всегда.
                  вместо того чтобы в каждой ветке новые длиннющие рассуждения писать
                  я просто знаю одно такое свое качество — если я пишу очень кратко, то меня совсем не понимают. Поэтому всегда стараюсь подавать мысль развернуто. Но даже это не всегда приводит к желаемому результату.
                  было бы полезно тратить этот час в день на самообразование.
                  Верно, но как бы странно это не звучало — я на работе и просто не могу себе позволить на час два полностью увлечься чем-то и вникнуть. Каждые 10 минут приходят задачи по десяткам проектам и сосредоточиться на изучении нового почти нереально. Но закончив работу я стараюсь найти время и разузнать что-то новое. Но нового так много, мне кажется в мире вообще каждую минуту создают новый фреймворк над фреймворком и через еще 30 секунд уже кто-то успевает написать 23 плагина к этому фреймворку))
                  Василий Наумкин
                  02 октября 2020, 19:23
                  +3
                  Наверное я просто не пишу настолько сложного кода, чтобы данный инструмент начал приносить удовольствие, а не раздражение.
                  Именно так.

                  Лет 7-8 назад я лично всем в интернете рассказывал, что мне хватает Notepad++, и что я не вижу никакого смысла в IDE вообще. Работал из под Windows, редактируя файлы прямо на рабочем сервере.

                  И про Git что-то подобное говорил, и про MODX Revolution в сравнении с Evolution (можно до сих пор найти на Хабре), что он прям мега-избыточный, и мне совсем не нравится.

                  Всё меняется с ростом профессионального уровня. Нужно просто понять и принять, что все эти гипер-сложные (как тебе кажется сейчас) штуки разрабатывают не странные люди с манией величия, а такие же парни как ты — просто чуть выше по уровню прокачки.

                  Они решают те проблемы, с которыми столкнулись. Просто ты еще лично до этих проблем не дорос.

                  А когда дорастёшь — скажешь им большое спасибо.
            Василий Наумкин
            02 октября 2020, 19:11
            +1
            Мне показалось слишком запутанным манипуляции с ssh ключами. Но я наверное не знаю что такое deploy ключи, всегда пользовался просто ssh ключем который можно указать в настройках аккаунта, а не отдельного репозитория.
            Это ровно та же фигня, но только для юзера сервера, который будет работать с одним единственным репозиторием. Просто, чтобы не выдавать ему свой личный ключ, с которым он сможет получить доступ во все твои репозитории. По умолчанию этот ключ вообще только на чтение работает. То есть, это просто вопрос безопасности.

            Василий (а может и не только Василий), а поделитесь ка пожалуйста такой информацией если найдете минуту.
            Уже давно поделился .

            Сейчас я работаю с Nuxt.js, и где-то там внутри используется Webpack, но Nuxt занимается всей этой заморочкой сам. Так что про Webpack я уже давно не думаю.
          Руслан Сафин
          03 октября 2020, 08:50
          +2
          Интересный вариант деплоя.
          Есть еще альтернатива, которую я использую… По пушу в гитлаб, запускается сборка проекта и билд докер контейнера (натравить можно на любую ветку), на сервере стоит один докер и обновляет сам контейнеры на новую версию… Удобный подход, особенно если необходимо деплоить несколько веток одного проекта на разные сервера (например прод, тестовый, демо)

          Еще большой плюс, если настроена правильно сборка контейнера, на сервер не попадают исходники
            Иван Климчук
            04 октября 2020, 23:09
            +3
            Как рабочее решение — хорошо, потому что работает. Следующим шагом вижу погружение в омут CI/CD, чтобы избежать крона с запросами раз в 30 минут, а деплоить по запросу через тот же GitHub Actions, после проверки сборки и тестов, например. Суть примерно та же, только чуть удобнее.
              Руслан Сафин
              05 октября 2020, 15:07
              +1
              Вот мне пришлось по работе разобраться с CI/CD, у нас 3 домена (демо, тест, прод) + микросервисная архитектура на go (7сервисов) + nodejs + angular =)))
                Василий Наумкин
                06 октября 2020, 05:33
                0
                Суть примерно та же, только чуть удобнее
                Скрипты сложнее, плюс всё равно нужно генерировать SSH ключ и устанавливать его на сервер и Github. Только направление работы другое — не сервер будет скачивать изменения, а Github будет присылать их через SSH.

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