Деплой без стресса: автоматизируем процесс для Telegram-ботов

bgwgrukmaamnkwca9d9chtckqim.png


Привет! Меня зовут Арсений Помазков. Я — разработчик и создатель одноименного 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, чтобы пользователь мог узнать статус заказа и обратиться в поддержку.

c2cfe4b927d924c78ac792f91e3abf95.png


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

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

dieiksvcuar3umm3kjj24s37br8.png

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


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

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

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


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

git remote


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

fd4514f9c251d417891ee4fd453df7df.png


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

git remote show origin


14100a9a25c796668db332335cb0352c.png


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

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


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

f80ca5701be0d5e492943b4eb95eff4e.png


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

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 часов, поэтому отлично подойдет для краткосрочных проектов. Стоимость ресурсов у такого сервера гораздо ниже.

05e19fc2b57be4dd47d4e9a4b3dc9b49.png


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

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

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

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


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

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

68f216689cedc04e9b7cbcdb6d892bef.png


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

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

2ed4b6b7d09d5ca730c8b554f4f1a332.png


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

cda396d889d198d6929058adfe197726.png


Снизу видим имя пользователя (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


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

9a229f0a12f753c999b5dca696792037.png


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

sudo npm install -g n
sudo n stable


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

2629eb44b33db475aa9bd62312fb8926.png


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

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

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

8d9c62192c994e2f40006981e7bc3da6.png


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

npm i pm2 -g


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

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


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

cd bot-automatization-final


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

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

npm i


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

nano .env


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

0d57701800b13b881a338b123a70743f.png


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

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

pm2 start index.js --name tg-bot


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

3e56dc7232276e1230beb92e9bcce03a.png


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


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

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

c1604d92e916092712b4f999c40b4689.png


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

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… в правом верхнем углу. Повторяем действие в открывшемся окне.

59f56c5f740118755738ba3434fc2d23.png


В результате появится новый файл в репозитории с новым 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:


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

481087e3faf3317e79da663716f2ac4d.png


В итоге система автоматически сгенерировала два ключа: публичный и приватный. Они находятся в папке ~/.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.

8fea3995511f36d11b5870487c1c0699.png


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

8dbf4eb584b81c00640b2162628445bb.png


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

457fd890af6da59db15aa0ea07d0db46.png


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

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

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

git pull origin main


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

bd866a8649447a0ec7c11e0dc462e404.png


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

d86d8a6b361c0e004de6bc9a6e7785c0.png


Заключение


63ceb1c547b4a5af3a5f090bdfa249f5.png


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

04b9d14a306a13f22247de944f206d28.png


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

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

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

© Habrahabr.ru