Итак, в предыдущих статьях (Введение, Командуем, Дратути) мы уже разобрали многие аспекты написания бота: как начать писать бота, как делать плагины-расширения и как работать с непосредственно пользователем и создавать функционал. Однако, до сих пор мы не разобрали, как, куда и с помощью чего можно публиковать и запускать ботов в проде.
О среде исполнения и ОС в целом
В данной статье в первую очередь будут разбираться вопросы публикации из Linux окружения, поскольку даже если вы несчастливый обладатель Windows/MacOS, почти всегда непосредственно публикацию и хостинг бота вы будете проводить в Linux окружении: Github Workflows, Gitlab CI, Jenkins и т.д.
Оглавление
Читаем рецепт
Публиковаться мы будем с помощью Docker контейнеров и публикации куда-нибудь, хотя для примера возьмём официальный Docker Hub (на момент написания статьи в нем можно зарегистрироваться и публиковать свои образы). После публикации образа мы будем запускать этот образ где-то, например на VPS с Ubuntu. Также небольшой ликбез по необходимым командам в линуксе:
# Создаем папку sample
mkdir sample
# Переходим в папку sample
cd sample
# Редактируем файл file (если его нет - он создастся при сохранении)
# Перемещение по редактору происходит стрелочками и page up/page down/home/end
# Для выхода и сохранения используем последовательность `Ctrl + x`, `y`
# Для выхода без сохранения используем последовательность `Ctrl + x`, `n`
nano file
# Выходим в предыдущую папку
cd ../
Нарезаем ингредиенты
Итак, предположим, вы имеете вот такой проект. Структура его в целом вряд ли будет важна, поскольку основной задачей будет выделение некоторого модуля, который будет уметь запускать бота. Обычно для этого я создаю отдельный модуль и называю его как-то вроде runner для наглядности. Что особенного в этом модуле:
-
В
build.gradleВ секции
pluginsподключен плагинapplication- это специальный gradle плагин для обозначения модуля как конечного приложенияПрисутствует настройка
application.mainClassName = 'dev.inmo.plagubot.AppKt', обозначающая, что мы будем запускать именно бота
Присутствует Dockerfile, настройка которого самодостаточна для запуска любого собираемого с помощью
applicationплагина приложенияПрисутствует deploy скрипт, запуска которого достаточно для публикации образа
Важные моменты:
FROMдиректива вDockerfileспокойно может быть заменена почти любой альтернативной базовой JDK (например, bellsoft/liberica-openjdk-alpine)deployскрипт как есть работает черезsudo docker, что означает, что вы авторизованы на целевом сервере с помощьюsudo docker login. Это важно, потому что если ваша публикация основана на условномGithub Actions, вам нужно будет убиратьsudoотовсюду в скрипте, поскольку там докер авторизован и работает безsudo(nonsudo_deploy скрипт)serverпеременная вdeployскрипте может быть либо выставлена в реальный адрес докер сервера (см. docker registry), либо это должен быть юзернейм на dockerhub, куда публикуется образappпеременная, также как иversionво всё том жеdeployфактически произвольны и вы можете поставить туда соответствующие вашему бота названия и версиюПри желании, вы можете даже добавить какой-то код в рамках модуля-раннера, но я строго рекомендую располагать в таком модуле только код, конфигурирующий каким-то образом запуск
Local bash
Для публикации из терминала Ubuntu, достаточно запустить deploy:
# Переходим в папку раннера
cd runner
# Деплоим
./deploy
# Всё :)
Github Actions
На своих проектах я использую вот такую настройку Github Action:
.github/workflows/docker-publish.yml
name: Docker
on: [push]
jobs:
publishing:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Log into registry
uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
with:
username: ${{ secrets.DOCKER_LOGIN }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Deploy
run: ./gradlew build && ./nonsudo_deploy
Для проекта-примера можно адаптировать это вот так:
.github/workflows/docker-publish.yml
name: Docker
on: [push]
jobs:
publishing:
runs-on: ubuntu-latest
permissions:
contents: read
packages: write
steps:
- name: Checkout repository
uses: actions/checkout@v2
- name: Log into registry
uses: docker/login-action@28218f9b04b4f3f62068d7b6ce6ca5b26e35336c
with:
username: ${{ secrets.DOCKER_LOGIN }}
password: ${{ secrets.DOCKER_PASSWORD }}
- name: Deploy
run: ./gradlew build && cd runner && ./nonsudo_deploy
Соответственно, чтобы оно заработало, нужно в настройках репозитория установить следующие переменные окружения для экшенов (на данный момент лежат по пути Secrets and variables -> Actions):
DOCKER_LOGINDOCKER_PASSWORD
Тушим, жарим, вот это всё
Образ на докерхабе, теперь бы всё это великолепие как-то запустить. Для этого понадобится устройство с линуксом (VPS/VDS, домашний комп, теоретически старый телефон и желание потерять неделю своей жизни). Приглашаю вас к нам в форум в телеграме для обсуждения всяких хостингов.
Теперь для запуска нам понадобится три вещи:
Установленные
dockerиdocker-compose(sudo apt install docker docker-composeнаUbuntu)docker-compose.ymlconfig.json
И начнем разбирать сразу со второго пункта, потому что с первым всё более-менее понятно.
Чево-то.yml
docker-compose.yml - это файл-конфигурация для docker-compose . Полную спецификацию можно глянуть тут, но для старта мы будем использовать следующий пример:
docker-compose.yml
version: "3.4"
services:
runner:
image: user/runner
container_name: runner
restart: unless-stopped
volumes:
- "./data/:/data/"
- "./config.json:/runner/config.json:ro"
А теперь разберем важные моменты в этом файле:
user- это пользователь/сервер, указанный вdeployскрипте в переменнойserverrunnerв значенииimage(послеuser/) - это название приложения изdeployпеременнойappПри желании, после
user/runnerможно добавить суффикс:версия, гдеверсия- значение переменнойversionизdeployскрипта-
volumes- секция с монтируемыми папками и файлами. Тут слева (до:) - значение из системы, откуда запускаетсяdocker-compose.yml, а справа - где папка/файл будут в контейнере./data/:/data/- монтирование папки данных, в которую можно складывать данные между сессиями. Например, по умолчанию, именно туда попадёт файлlocal.dbс базой данных, если не менять секциюdatabaseв config.json./config.json:/config.json:ro- конфигурация бота. Пример есть в config.json
config.json
Как ни странно, этот файл содержит конфигурацию бота. В нашем случае, для примера вам нужно будет поменять только поле botToken - установить туда токен, полученный от BotFather.
Щепотка соли
Таким образом, на сервере у вас должна получиться некоторая папка (например, runner), в которой есть следующие файлы/папки:
docker-compose.yml- конфигурация для запуска с помощьюdocker-composeconfig.json- конфигурация ботаdata- папка с данными бота
Пробуем на вкус
Теперь всё это великолепие можно запустить одной простой командой:
sudo docker-compose up -d
Когда вам скажут, что контейнер был создан, бот должен начать отвечать на ваши действия.
Небольшой список полезных команд docker-compose
У docker-compose, как и у любого инструмента Linux есть огромная куча параметров. Как и у любого инструмента Linux, у docker-compose я использую ограниченное число команд и параметров просто в силу их достаточности:
sudo docker-compose up -d- запустить контейнер в режиме демона, то есть с автоперезапусками и прочим таким. Если убрать-d, то вы автоматически подключитесь к логам бота, а поctrl + C- останосите контейнер и отключитесь от негоsudo docker-compose pull- стянет последнюю версию используемого образаsudo docker-compose logs -f --tail=100- привяжется к выводу бота с выводом последних 100 строк логов. Поctrl + Cбот не остановится, но от логов вы отключитесьsudo docker-compose down- собственно, остановка и удаление контейнера. Будьте аккуратны с этой командой, поскольку она затрёт все данные, не находящиеся в папках из секции volumessudo docker-compose stop- (наравне сstartиrestart) - останавливает работу контейнера (начинает/перезапускает соответственно
Разливаем по тарелкам
Теперь вам остаётся только экспериментировать с тем, что вам предложено в этом туториале, читать кучу макулатуры документации, всё ломать и потом восстанавливать. В общем, искренне желаю вам удачи и не забывать делать бэкапы - они позволят проклюнуться седине позже.