Привет, коллеги! ?

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

Вот ссылки на другие части статьи:

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

  • bash-скрипт

  • GitHub actions

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

Вкратце напомню, что уже изучили, и как мы деплоим вручную:

  1. Есть приватный GitHub-репозиторий с проектом, в который мы пушим изменения с локального репозитория.

  2. Забираем обновленный код из GitHub-репозитория на сервер.

  3. Выполняем команды по обновлению проекта (composer-зависимости, выполняем миграции, пересобираем ассеты, перезапускаем джобы и так далее).

То есть кучу команд необходимо запустить и на локальном рабочем месте, и на сервере. И это, конечно же, неудобно. Здесь достаточно много ручной работы, это наводит уныние. Да и можно всего одну команду упустить, и деплой будет неудачным!

Давайте автоматизировать это дело!

Что у нас есть на старте

Автоматизировать мы будем деплой проекта на Laravel, репозиторий с демо-версией админки MoonShine - https://github.com/moonshine-software/demo-project.

В этой статье мы автоматизируем деплой проекта, который уже был развернут и настроен. Если вы делаете деплой проекта в первый раз, выполните настройку по этим статьям: 
shared-хостинг, VPS.

Вариант 1. bash-скрипт на сервере

Самый простой вариант по автоматизации деплоя. Сделаем обычный bash-скрипт, который будем запускать одной командой на сервере, а он будет делать все за нас. 

Назовём скрипт easy-deploy.sh.

Приступаем к наполнению скрипта командами. Чтобы интерпретатор понял, что это именно bash-скрипт, мы должны написать вот такую конструкцию в начале файла:

#!/bin/bash

Подстелим себе соломку: добавим инструкцию set –e . Если одна из команд завершится с ошибкой, то скрипт прекратит работу. И дальше пишем команды для деплоя (для Composer и миграций желательно использовать флаги --no-interaction  и --force соответственно. Они позволяют выполнять команды без необходимости вмешательства пользователя, что важно для автоматизированного процесса деплоя):

#!/bin/bash
set -e

# Переходим в директорию проекта
cd /var/www/moonshinedemo

# Переводим приложение в режим обслуживания
php artisan down

# Обновляем код из GitHub-репозитория
git pull

# Устанавливаем зависимости Composer
composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader

# Выполняем миграции базы данных
php artisan migrate --force

# Собираем ассеты для production среды
npm run build

# Очищаем все кэши
php artisan optimize:clear

# Кэшируем
php artisan optimize

# Перезапускаем задания в очереди
php artisan queue:restart

# Выводим приложение из режима обслуживания
php artisan up

Сохраняем. Теперь новую версию приложения попробуем забрать при помощи этого скрипта, и он должен выполнить команды, которые мы прописали.

Давайте проверять. Делаем коммит и обновляем проект на сервере. Вот появился у нас скрипт, давайте запустим его:

sh easy-deploy.sh 

Контролируем процесс. 

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

Сейчас процесс деплоя приведен к виду: 

  1. Пушим изменения с локального репозитория в GitHub-репозиторий

  2. Подключаемся к серверу (по SSH, как настроили во второй статье) и запускаем скрипт easy-deploy.sh

Плюсы:

  • Бесплатно. Всё выполняется без использования платных сервисов 

  • Автоматизация. Каждый деплой позволяет сэкономить пару минут (по сравнению с ручным деплоем)

Минусы:

  • Надо подключаться к серверу, чтобы запустить скрипт.

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

  • Отсутствие обратной связи: непонятно как проходит процесс деплоя, необходимо мониторить ход выполнения скрипта на сервере.

По сравнению к деплоем вручную - намного лучше, давайте посмотрим еще один популярный вариант автоматизации.

Вариант 2. GitHub Actions

GitHub Actions — это инструмент для автоматизации рутинных задач в разработке программного обеспечения. Он позволяет настроить автоматическое тестирование, сборку и деплой приложения. GitHub Actions глубоко интегрирован в экосистему инструментов GitHub.

Итак, у GitHub есть Actions, и можно настроить так, чтобы на событие push в GitHub-репозиторий, GitHub будет запускать необходимые команды на сервере. Что надо сделать:

  1. Создать в локальном репозитории рабочий процесс (workflow) GitHub Actions

  2. Добавить информацию для настройки SSH соединения GitHub-сервер - GitHub secrets

  3. Добавить значения из secrets в файл workflow

  4. Запушить workflow в репозиторий на GitHub

  5. Проверяем работу

Велосипед выдумывать не будем, работаем по документации GitHub.

Создание рабочего процесса (workflow) GitHub Actions

Создаём свой workflow - создаем папку в каталоге .github/workflows,  в ней файл deploy.yml

Оформим инструкцию! 

Определение события для запуска workflow

on:
  push:
    branches:
      - main

Указываем, что выполняем workflow после события push в ветку main (указываем нужную).

Для выполнения команд на удаленном сервере через SSH мы используем appleboy/ssh-action@master (это GitHub Action, созданный пользователем с именем "appleboy". Позволяет подключиться к удалённому серверу через SSH и

выполнять команды на этом сервере).

Что делает эта Action:

  • Она предоставляет возможность подключиться к удалённому серверу через SSH.

  • После подключения можно выполнять команды или скрипты на этом сервере.

Определение задач (jobs) рабочего процесса

jobs:

  deploy:
    name: Deploy
    runs-on: ubuntu-latest
    steps:
      - name: SSH Deploy
        uses: appleboy/ssh-action@master
        with:
          host: ${{ secrets.SSH_HOST }}
          username: ${{ secrets.SSH_USERNAME }}
          key: ${{ secrets.SSH_PRIVATE_KEY }}
          script: | 
            cd /var/www/moonshinedeploy.ru
            php artisan down
            git pull
            composer install --no-dev --no-interaction --prefer-dist --optimize-autoloader
            php artisan migrate --force
            npm run production
            php artisan optimize:clear
            php artisan optimize
            php artisan queue:restart
            php artisan up

Файл для работы workflow готов. Обратите внимание на ${{ secrets.SSH_HOST }}, ${{ secrets.SSH_USERNAME }} и ${{ secrets.SSH_PRIVATE_KEY }}. Это переменные для настройки подключению к серверу, которые нам нужно будет создать на GitHub.

Настроим secrets GitHub 

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

Для хранения конфиденциальной информации (такой как пароли, ключи API и т.д.) придуманы secrets - это переменные, которые вы можете использовать в вашем репозитории GitHub. Secrets предоставляют безопасный способ хранения данных (GitHub обещает, что всё храниться в зашифрованном виде), которые нужны для настройки GitHub Actions workflows. 

Secrets находятся в настройках репозитория GitHub - "Secrets and Variables", раздел "Actions". 

 

Добавляем информацию для настройки SSH подключения:

SSH_HOST - IP_адрес_вашего_сервера
SSH_USERNAME - имя_пользователя

Переходим к SSH ключам. При настройке SSH-соединения приватный ключ должен храниться на устройстве, с которого вы планируете подключаться к удаленному рабочему месту. А публичный ключ, должен быть скопирован на удаленное рабочее место (к которому мы будем подключаться). Подключаться мы будем с GitHub к серверу. Получается, что мы должны приватный ключ хранить на GitHub, а публичный (.pub) - на сервере.

Сгенерируем на сервере пару ключей для нового SSH-соединения "GitHub-сервер". При генерации придумайте уникальное название, например, "github actions" (чтобы потом проще было найти):

ssh-keygen -t rsa -C "github actions"

- C "github actions": добавляет комментарий к ключу. Это помогает идентифицировать ключ, особенно если у вас их несколько.

Указываем имя для файла с ключами:

Enter file in which to save the key (/home/localadmin/.ssh/id_rsa): /home/localadmin/.ssh/gitHubSSH

Готово!

Копируем значение приватного ключа в секрет SSH_PRIVATE_KEY (начиная от —Begin… до …end ssh private key—). 

Сам файл приватного ключа можно удалить (на всякий случай, чтобы никто не смог подключиться к нашему серверу).

Итак, secrets настроены, файл с workflow у нас готов, нужно отправить его на GitHub.  Создаем новый коммит с изменением, пушим на GitHub. 

Смотрим, появился ли наш workflow в разделе Actions. 

Ждём пока выполнился workflow. Проверяем.

Всё отлично. Но есть недостаток: что происходит в workflow не видим. git push выполнили и дальше ждем, когда проект обновится на сервере. Как решить? Надо либо заходить в экшены репозитория и мониторить работу в режиме реального времени, либо настраивать уведомления на email.

Настраиваем уведомления на почту. Чекбокс стоит, что получаем уведомления о неудачных workflow, если же хотите получать и об успешном выполнении, то снимаем чекбокс.

Плюсы:

  • Интеграция с GitHub. GitHub Actions полностью интегрирован с GitHub, что упрощает настройку и управление рабочими процессами прямо из вашего репозитория.

  • Бесплатно (без ограничений) для открытых репозиториев.

  • Автоматизация. Каждый деплой позволяет сэкономить пару минут (по сравнению с ручным деплоем)

Минусы:

  • Ограниченное количество минут GitHub Actions для private-репозиториев на бесплатном тарифе

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

  • Отсутствие обратной связи: мониторим ход выполнения workflow или настраиваем уведомления на email

  • Непростая настройка: новичкам придется попотеть, но как мы убедились это выполнимая задача

Выводы

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

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

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

В следующей статье покажу, как автоматизировать деплой Laravel-приложений с использованием Laravel Envoy. 

Ссылки на другие части статьи по деплою:

А какой опыт автоматизации деплоя у вас? Возможно, вы используете другие инструменты или у вас есть свои хитрости в настройке процесса? Поделитесь своими мыслями и опытом в комментариях!

Комментарии (17)


  1. rsmike
    15.10.2024 14:13

    я просто оставлю это здесь

    https://deployer.org/

    есть поддержка всех фреймворков и голого php, есть provisioning из коробки, есть официальный github action, тривиален в настройке, опен сорс

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


    1. censor2005
      15.10.2024 14:13

      А у ларавела есть нативный пакет Envoy, позволяет выполнять команды на удаленном сервере


      1. Cutcode Автор
        15.10.2024 14:13

        Про Envoy еще расскажу, запланировано.


  1. rsmike
    15.10.2024 14:13

    и кстати, забыли еще один краеугольный камень лиги велосипедного деплоя - репозиторий на продакшене, разворачивающий свежий комит в себя с помощью post-receive hook


  1. evgenyk
    15.10.2024 14:13

    Минусы:

    • Надо подключаться к серверу, чтобы запустить скрипт.

    • Отсутствие обратной связи: непонятно как проходит процесс деплоя, необходимо мониторить ход выполнения скрипта на сервере.

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


    1. savostin
      15.10.2024 14:13

      Плюс не отдавать ssh ключ и доступ к проду пусть и честному и секьюрному гитхабу, но все ж


      1. evgenyk
        15.10.2024 14:13

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


    1. Cutcode Автор
      15.10.2024 14:13

      Отличное замечание. Добавлю


  1. EugKor
    15.10.2024 14:13

    Хорошая статья, спасибо. Есть момент, что лучше вместо git pull использовать:

    git fetch --all

    git reset --hard origin/master

    Это позволит избежать конфликтов если вы пересоздали ветку master.


  1. smitt14ua
    15.10.2024 14:13

    Лучше через контейнеры и образы, так можно будет быстро развернуть предыдущую версию без revert-ов в репозитории


    1. Cutcode Автор
      15.10.2024 14:13

      А мы пока не про лучше или хуже а рассматриваем все способы, это уже третья часть) идем от мира динозавров к современным решениям, еще будет как минимум 2-3 статьи


  1. AlexFromHabr
    15.10.2024 14:13

    Коллеги, неужели в русском языке нет адекватных слов чтобы передать смысл слов "гайд" и "деплой"? Это просто ужас какой то во что превратился русский язык у IT-шников. Это совсем некруто использовать эти слова. А как IT-шники произносят http и css - это ужас ужасный.


    1. ideldotpro
      15.10.2024 14:13

      Потому что эти слова компактные и точно описывают предмет или действие. Вот в статье еще нашел исконно русские слова:
      цикл, сервер, автоматизация, скрипт, комильфо, приватный, проект, репозиторий, команда, миграция, локальный, старт, демо, версия, админка, вариант, интерпретатор, конструкция, флаг, процесс, режим, контроль, кэш, сервис, экономия, минута, популярный и т.д.
      А почему к этим словам нет вопросов? Потому что добавили в словарь русского языка? Или просто привыкли?


      1. AlexFromHabr
        15.10.2024 14:13

        Кто в здравом уме, который не знает английского языка (знаю что таких мало в IT) поймет что такое деплой? Он скорее поймет слово развертывание системы или установка приложения/программы. К словам, которые Вы указали, нет русских аналогов. Слово Гайд это руководство, деплой - развертывание или установка.

        В крайнем случае напишите их в английском написании. Не коверкайте русский язык. Так писать - себя не уважать.


    1. Cutcode Автор
      15.10.2024 14:13

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


      1. AlexFromHabr
        15.10.2024 14:13

        Можно написать просто развертывание или установка, ваш вариант тоже подходит.


        1. Vadiok
          15.10.2024 14:13

          Развертывание и установка - это скорее что-то про начальную подготовку к запуску. Деплой же про доставку изменений кода до пользователя.