Итак, в предыдущих статьях (Введение, Командуем, Дратути) мы уже разобрали многие аспекты написания бота: как начать писать бота, как делать плагины-расширения и как работать с непосредственно пользователем и создавать функционал. Однако, до сих пор мы не разобрали, как, куда и с помощью чего можно публиковать и запускать ботов в проде.
О среде исполнения и ОС в целом
В данной статье в первую очередь будут разбираться вопросы публикации из 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_LOGIN
DOCKER_PASSWORD
Тушим, жарим, вот это всё
Образ на докерхабе, теперь бы всё это великолепие как-то запустить. Для этого понадобится устройство с линуксом (VPS/VDS, домашний комп, теоретически старый телефон и желание потерять неделю своей жизни). Приглашаю вас к нам в форум в телеграме для обсуждения всяких хостингов.
Теперь для запуска нам понадобится три вещи:
Установленные
docker
иdocker-compose
(sudo apt install docker docker-compose
наUbuntu
)docker-compose.yml
config.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
скрипте в переменнойserver
runner
в значении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-compose
config.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
) - останавливает работу контейнера (начинает/перезапускает соответственно
Разливаем по тарелкам
Теперь вам остаётся только экспериментировать с тем, что вам предложено в этом туториале, читать кучу макулатуры документации, всё ломать и потом восстанавливать. В общем, искренне желаю вам удачи и не забывать делать бэкапы - они позволят проклюнуться седине позже.