Привет! Меня зовут Арсений Помазков. Я — разработчик и создатель одноименного YouTube-канала. Часто в pet-проектах приходится вручную загружать обновления на сервер. Это отнимает много времени и увеличивает вероятность ошибок при изменении кода. Чтобы упростить и ускорить процесс развертывания Telegram-бота, настроим автоматический деплой на сервер с помощью GitHub Actions.

Прежде всего вам понадобится Telegram-бот на любом языке. Я буду использовать пример из предыдущей инструкции о библиотеке Grammy JS. Вы можете создать собственный или использовать с GitHub — все ссылки оставлю в тексте.

Используйте навигацию, если не хотите читать текст полностью:

Подготовка бота
Настройка GitHub-репозитория
Автоматизация деплоя
Заключение

Подготовка бота


Чтобы использовать готовый код с GitHub, нужно убедиться, что на вашем компьютере установлен Git. Открываем командную строку и вводим команду:

git -v

Если видите актуальную версию Git, программа добавлена. В противном случае — скачиваете файл с официального сайта и устанавливаете.

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

git clone https://github.com/arseniypom/bot-automatization.git

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

npm i

Внутри проекта находятся:

  • node_modules — папка с файлами зависимостей;
  • .gitignore — список файлов, которые мы не хотим заливать в Git;
  • index.js — файл с кодом нашего бота;
  • package-lock и package.json — список зависимостей.

В прошлой инструкции я рассказывал, как создать Telegram-бота с помощью Grammy JS, поэтому не буду подробно на нем останавливаться. Кратко пройдемся по основным шагам.

Создаем в проекте файл .env и добавляем в него переменную BOT_API_KEY:

BOT_API_KEY=0123456789:GHF3uhO16fM1Zqn7kyGIiYLuDSfDaNbr8mQ

Переменную можно назвать как угодно. Но поскольку в моем коде уже используется index.js, беру его.

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

Проверим, что все работает:

npm start

Переходим в Telegram по ссылке от @BotFather. Здесь простая механика: бот отвечает на команду /start и /menu, чтобы пользователь мог узнать статус заказа и обратиться в поддержку.


Тестовая версия Telegram-бота.

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



Настройка GitHub-репозитория


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

Создаем новый репозиторий и указываем имя — в нашем случае bot-automatization-final. После — копируем HTTPS-ссылку:

https://github.com/arseniypom/bot-automatization-final.git

Переходим обратно в редактор. Поскольку мы скопировали бота из моего репозитория, у него уже есть связь с удаленным. Это можно проверить, введя команду:

git remote

В ответе видим название origin:


Теперь если введем команду git remote show origin, получим адрес этого репозитория.

git remote show origin


Далее используем команду git remote set-url origin и добавляем скопированную ссылку на только что созданный репозиторий:

git remote set-url origin https://github.com/arseniypom/bot-automatization-final.git

Перепроверяем результат командой git remote show origin. В ответе видим новый адрес:


Заливаем код на новый репозиторий:

git push origin main

Готово! Приступаем к деплою бота.

Деплой бота на сервер


Настройка сервера


Приступим к настройке сервера с помощью Github Actions. Для этого используем облачный сервер Selectel. Далее буду описывать весь процесс на его примере.

Переходим в панель управления и создаем аккаунт, если его нет. В левой секции выбираем Облачная платформа, регион Санкт-Петербург и пул ru-3. Нажимаем Создать сервер.

Указываем имя сервера как в репозитории и вводим нужные характеристики.

  • Пул: ru-3b.
  • Источник: любой дистрибутив Linux — Ubuntu, Debian, CentOS, Fedora и другие. В нашем случае — Ubuntu 64 512 Мб.
  • Конфигурация: Shared. Итоговая конфигурация стоит от 10 ₽/день или около 300 ₽/месяц и подходит для небольших pet-проектов — например, Telegram-ботов и других.

В Shared Line можно арендовать не весь сервер, а его часть — 10, 20 или 50%. Выбираем 10% и наименьшую конфигурацию оперативки. Если получится так, что на сервере нет других арендаторов, все 100% мощности сервера переходят нам без доплат.

  • Диск: базовый SSD на 5 ГБ.
  • Сеть: новая публичная подсеть.

Еще один способ сэкономить на инфраструктуре — взять прерываемый облачный сервер. Он работает не более 24 часов, поэтому отлично подойдет для краткосрочных проектов. Стоимость ресурсов у такого сервера гораздо ниже.


Прерываемый сервер в конфигураторе.

При входе в консоль данные для входа отправляются автоматически, поэтому не настраиваем SSH-ключи и пароль. Нажимаем на кнопку Создать.

На странице нам открывается список всех серверов и их статус. Ждем, пока запуститься сервер. Как только статус переведется в Active, переходим к новому серверу. В открывшейся панели видим несколько вкладок и настройки, с помощью которых можно отключить или заморозить сервер. Дополнительно есть кнопка перезагрузки и другие опции.

Подключение к серверу


Ниже выбираем Консоль, вводим логин root и пароль. Настроить сервер можно прямо в консоли панели управления или через терминал компьютера по SSH. Будем использовать второй вариант.

Чтобы подключиться к компьютеру, нужно получить данные сервера. Пароль уже видели во вкладке Консоль, а IP — во вкладке Порты.


Сперва копируем IP-адрес. В терминале на Mac или командной строке на Windows вводим команду в формате ssh <имя пользователя>@<IP-адрес>. В нашем случае — ssh root@185.10.187.10.

После терминал отправляет вопрос: «Хотите ли вы продолжить подключение?» Изначально SSH-клиент не может проверить подлинность сервера, так как его ключ еще не сохранен на вашем компьютере. Пишем «yes», и при следующих попытках входа вопрос не появится.


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


Снизу видим имя пользователя (root) и название сервера. Теперь можно настроить сервер для деплоя!

Деплой бота


Обновляем список пакетов в системе с помощью команды и устанавливаем нужные пакеты: git для работы с гитом, node.js и npm для запуска нашего приложения:

sudo apt install git nodejs npm

В ответе видим вопрос:

After this operation, 92.1 MB of additional disk space will be used.
Do you want to continue? [Y/n] 

Отвечаем Y и нажимаем Enter. Убеждаемся, что все корректно работает:

node -v 
npm -v

В результате видим рядом с каждой командой ее версию:


Система указывает 12 версию ноды, хотя актуальная на момент подготовки статьи – 20. Все потому, что версии этих пакетов по умолчанию старые. Нужно поставить пакет n и с его помощью самостоятельно установить стабильную версию.

sudo npm install -g n
sudo n stable

Повторно проверяем версию node с помощью node -v. Если все еще показывается старая версия, перезагружаем сервер. Это можно сделать кнопкой в правом верхнем углу или командой reboot прямо в консоли.


Раздел «Консоль» в настройках сервера.

Если выбрали перезагрузку через консоль, соединение будет разорвано. Нужно подождать пару минут, чтобы снова подключиться к серверу.

После ожидания вводим данные для входа и перепроверяем версии. Теперь они актуальные:


Загружаем менеджер процессов pm2, с помощью которого будем запускать бота. Устанавливаем его глобально — на это указывает флаг -g:

npm i pm2 -g

Далее клонируем репозиторий с ботом на сервер в формате git clone <ссылка на GitHub-репозиторий>:

git clone https://github.com/arseniypom/bot-automatization-final.git

После клонирование на сервере появляется папка с названием репозитория —заходим в нее:

cd bot-automatization-final

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

Устанавливаем зависимости:
npm i

Создаем файл .env и открываем с помощью редактора nano:

nano .env

После открытия редактора добавляем в него содержимое .env из проекта на компьютере:


Используем сочетанием клавиш Ctrl+O, затем Enter и Ctrl+X, чтобы сохранить прежнее имя файла и выйти из редактора.

Запускаем бота с помощью pm2. Не забудьте перед этим убедиться, что остановили его локально, иначе возникнут конфликты.

pm2 start index.js --name tg-bot

В консоли видим сообщение об успешном запуске:


Автоматизация деплоя


Для настройки деплоя используем GitHub Actions — встроенную в GitHub систему автоматизации, которая позволяет создавать и запускать рабочие процессы (workflow) для сборки, тестирования, деплоя и других задач. Запускаются они автоматически в ответ на события в репозитории — например, при пуше кода или создании pull request.

Возвращаемся в GitHub-репозиторий и переходим на вкладку Actions. На странице предложены уже готовые workflow — нам нужно создать собственный. Нажимаем на set up a workflow yourself.


В открывшийся редактор вставляем код:

name: Node.js CD # Название workflow (процесса автоматизации)

on:
  push:
    branches: [ main ] # Триггер: запускать workflow при пуше в ветку main

jobs:
  build:
    runs-on: ubuntu-latest # Определение окружения: используется последняя версия Ubuntu


    steps:
    - name: Deploy using ssh # Название шага: Деплой с использованием SSH
      uses: appleboy/ssh-action@master # Использование готового действия для SSH-подключения
      with:
        host: ${{ secrets.HOST }} # Хост (сервер) для подключения, берется из секретов Github
        username: ${{ secrets.USERNAME }} # Имя пользователя для SSH, берется из секретов Github
        key: ${{ secrets.PRIVATE_KEY }} # Приватный ключ для SSH, берется из секретов Github
        port: 22 # Порт для SSH-подключения (по умолчанию 22)
        script: |
          cd ~/bot-automatization-final # Переход в директорию с проектом на сервере
          git pull origin main # Вытягивание последних изменений из ветки main
          git status # Проверка состояния git-репозитория
          npm install --only=prod # Установка только продакшн-зависимостей
          pm2 restart tg-bot # Перезапуск процесса tg-bot с помощью PM2


Нажимаем на кнопку Commit changes… в правом верхнем углу. Повторяем действие в открывшемся окне.


В результате появится новый файл в репозитории с новым workflow ./github/workflows/main.yml.

Переходим в консоль, чтобы сгенерировать SSH-ключ на сервере:

ssh-keygen -t rsa -b 4096 -m PEM -C "github-actions-bot-automatization”

В ответ на вопрос о названии файла нажимаем Enter и оставляем название по умолчанию:

Enter file in which to save the key (/root/.ssh/id_rsa):

Повторяем действие на вопрос о секретной фразе и ее повторе – оставляем пустыми. Нажимаем Enter.

Enter passphrase (empty for no passphrase):
Enter same passphrase again:

Получаем сообщение о создании ключа:


В итоге система автоматически сгенерировала два ключа: публичный и приватный. Они находятся в папке ~/.ssh.

Чтобы вывести публичный ключ в консоль, вводим команду:

cat ~/.ssh/id_rsa.pub

Ключ нужно скопировать и добавить в файл с authorized_keys:

nano  ~/.ssh/authorized_keys

Добавляем публичный SSH-ключ и сохраняем сочетанием клавиш Ctrl+O, Enter и Ctrl+X.

Теперь уберем приватный SSH-ключ, чтобы добавить его в переменные окружения на GitHub:

cat ~/.ssh/id_rsa

Копируем значение вместе с фразами в начале и конце:

-----BEGIN RSA PRIVATE KEY-----
MIIJKAIBAAKCAgEA1KcpcbZPKPyR8KGSo3qPJJ3IeTmkQxC1gohVyhl3R9h/KetB
CiczYsP0xnlM3ZMztfZYSqMNJy9811TDtT1s6I5sb1UJ9nz52T2qQPDBcSyUVwR5
...
wvT6Hy+I/5b4L89IkWcpSQcYg+SyBxMMVLliHDARfXmw5+jbFaG01854tOkvjD81
vJthoKSIwKgrAojmgiOF53/H+mHMUk4ckwRMsSJJuqEESBtxDzh7vmK0dWU=
-----END RSA PRIVATE KEY-----


Далее добавляем в GitHub. Для этого заходим в SettingsSecretsActions и нажимаем New repository secret.


Для ранее созданного workflow нужно три секретных ключа: PRIVATE_KEY, HOST и USERNAME. В блок Имя вписываем первую переменную PRIVATE_KEY, а в значение — приватный SSH-ключ. Нажимаем Add secret.


Также создаем оставшиеся переменные. В HOST помещаем IP-адрес сервера, а в USERNAME — root. Будьте внимательны, опечатки могут нарушить работу workflow.


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

Важно: перед тем, как использовать локальный репозиторий, необходимо подтянуть обновления из удаленного. Именно в нем создали новый файл с workflow — main.yml.

Обновляем репозиторий с помощью команды:

git pull origin main

Переходим к тестированию. Дописываем пару слов в приветственное сообщение:


Далее заливаем обновления на GitHub. Готово!


Заключение



Теперь если зайти во вкладку Actions на GitHub, мы увидим запуски workflow.


Система выполнила первый workflow сразу после создания файла main.yml. На момент создания мы «не добили» нужные секреты, поэтому они находятся в статусе Failed.

Второй запуск успешный. Произошел тогда, когда мы запушили изменения в ветку main из локального репозитория. Также workflow сработает, если добавим merge в главную ветку. На этом процесс автоматизации завершен!

Автор: Арсений Помазков, создатель YouTube-канала.

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


  1. Apokalepsis
    25.10.2024 17:21

    А если взять serverless то можно очень сильно сократить все шаги.


    1. flancer
      25.10.2024 17:21

      сколько стоит serverless?


  1. ko22012
    25.10.2024 17:21

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

    Лично я на простых проектах предпочитаю ssh соединения, а не создание docker образов, ибо жирно и быстро память забивает. И пару минут стоит это дело.

    А еще есть возможность использовать публичные actions, для проверок pull request годится.

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

    А после слияния в основную ветку, автоматическое развертывание на стенд разработки.