В этом уроке у нас две цели: научиться удобному развертыванию кода на удаленных серверах и обеспечить восстановление работы бота после критической ошибки.
Предыдущие уроки
Внимание! Для корректной работы проверяйте, чтобы package.json зависимость golos выглядела так: "golos":"ontofractal/golosjs"
Предисловие
- Обязательно задавайте вопросы в комментариях, если я что-то непонятно объясняю!
- Требуется базовый уровень понимания JavaScript, веб технологий и командной строки.
- У меня минимальный опыт работы с русскоязычной терминологией в программировании, поэтому некоторые названия я буду оставлять на английском языке.
- В этом уроке используется неоптимальный код, паттерны и структура, в приоритете находится простота и читаемость кода.
О деплойменте
До того как начнем, нам необходимо понимание контекста: экосистема и стратегии деплоймента быстро меняются из-за распространения облачных хостингов, контейнеризации, развития распределенных приложений/баз данных и immutable infrastructure. Современный деплоймент -- важная часть цикла разработки и стоит того, чтобы инвестировать в его изучение время.
Деплоймент нашего бота -- достаточно простая штука, но пойдем немного дальше и сделаем процедуру развертывания удобной и легко повторимой. Для этого мы будем использовать контейнеры и docker.
Контейнеры
Самый популярный движок контейнеров -- docker, альтернатива -- rkt. И docker, и rkt были созданы на основе LXC контейнеров. Ключевое отличие в том, что благодаря венчурном финансированию компании docker получилось популяризовать, создать экосистему (один из ключевых факторов успеха опен сорса) и гарантировать долгосрочную поддержку.
Некоторые продукты компании Docker:
- docker engine: движок для создания и запуска контейнеров
- docker swarm: кластеризация контейнеров, нам она не нужна
- docker machine: управление хостами контейнеров, нам оно не нужно
Детальное изучение истории, экосистемы и продуктов docker находится за рамками этого урока, поэтому обязательно ознакомьтесь с сайтов docker.com прежде чем продолжать.
Скринкаст запуска бота на удаленном сервере
Все действия в скринкасте подробно рассматриваются дальше в посте.
Адаптируем JS код бота для Docker
В последней версии мы прописывали список аккаунтов, за голосами которыми мы хотим следовать прямо в коде: const accountVotesToFollow = ['academy']
.
Сейчас мы сделаем так, чтобы список аккаунтов загружался из переменной пространства.
// загружаем список аккаунтов из переменной пространства и превращаем полученную строку в array аккаунтов
const accountVotesToFollow = process.env.GOLOS_ACCOUNT_VOTES_TO_FOLLOW.split(',')
// уведомляем оператора бота о том, голоса каких аккаунтов будет копировать бот
console.log('===================БОТ ЗАПУЩЕН===================')
console.log(`Бот будет повторять голоса следующих аккаунтов: ${accountVotesToFollow.join(', ')}`)
Контейнеры и образы (images)
Необходимо четко разграничить две коцнепции: контейнеры и образы (images). Образы статичны и создаются заранее. В файловой системе образы сохраняются как .tar.gz архивы.
Контейнеры динамичны, внутри них выполняется код. Контейнеры эфемерны, при уничтожении и создании нового контейнера все изменения в предыдущем контейнере исчезают. При запуске контейнеры копируют всю файловую систему образа и запускают заданные программы. Из одного образа может быть запущено любое количество контейнеров .
Начнем с создания образа для нашего бота. На docker hub доступен каталог образов, включая базовые образы, например, образ с последней версией nodejs. Для создания образов используется специальный тип файлов: Dockerfile
.
Посмотрим на структуру простого Dockerfile для нашего бейби бота:
FROM node:latest
ADD . /golos-baby-bot
ENTRYPOINT node /golos-baby-bot/main.js
рассмотрим строчки по порядку:
FROM node:latest
указывает взять за основу последнюю версию базового образ nodejs с docker hub. На момент написания поста это v7.5.ADD . /app/
добавляет все файлы контекста (официальный термин директории в которой находится Dockerfile) в папку app внутри контейнере.ENTRYPOINT node main.js
задает дефолнтую команду при запуске контейнера.
Официальная документация Dockerfile
Теперь нас есть готовый Dockerfile, создадим с помощью него докер образ. Для этого используем следующую команды:
cd /path/to/your_bot_directory
# создаем образ с тэгом username/golos-baby-bot, точка в конце указывает на текущую директорию
docker build -t ontofractal/golos-baby-bot .
Загружаем на удаленный сервер
- на сервере должен быть установлен Docker.
docker save ontofracta/golos-baby-bot:latest -o golos-baby-bot.tar.gz
сохраняем образ в файл в рабочей папкеscp golos-baby-bot.tar.gz root@YOUR_SERVER:/root/
загружаем образ на удаленный сервер, у вас должны быть настроены ssh ключиssh root@YOUR_SERVER
логинимся на удаленный серверcd /root
иls
проверяем на месте ли файл образаdocker load < golos-baby-bot.tar.gz
загружаем образ из файлаdocker run -it -e "GOLOS_ACCOUNT_VOTES_TO_FOLLOW=academy,ontofractal" -e "GOLOS_POSTING_KEY=5..." --restart always ontofractal/golos-baby-bot
Запускаем контейнер
Разберем последнюю команду:
docker run
запускает контейнер-it
сокращение от interactive и tty, аттачит к работающему контейнеру виртуальный терминал-e
сокращение от environment, задает переменную пространства--restart always
задает политику перезапуск контейнера, в нашем случае перезапуск будет происходит всегдаgolos_baby_bot
название образа, который будем использовать для запуска контейнейра
Стандартный образ nodejs на докерхаб занимает слишком много места (~700MB), что создает некоторые неудобства. Для минимизации можно использовать образы alpine.
Итоги
В результате этого урока у нас появился докер образ бейби бота и пошаговая инструкция по деплойменту бейби бота в контейнере. Благодаря политике перезапусков при критической ошибке внутри кода и прерывания работы, контейнер перезагрузится и бот восстановить свою работу.
Ссылки:
Важно
Код выпущен под MIT лицензией. Всю ответственность за использование кода вы принимаете на себя.
@ontofractal, Поздравляю!,
Ваш пост был упомянут в моем хит-параде в следующей категории:
Спасибо, а где посоветуешь удаленный сервер завести?
vultr, digitalocean, hyper.sh (специально для контейнеров, есть freemium опция)
Какого пакета на hyper.sh будет достаточно для стабильной работы?
ммм, думаю, что 256MB вполне хватит
А почему огненная магия?
магия потому, что цитируя Артура Кларка "любая достаточно развитая технология неотличима от магии."
а огненная потому, что джемотикон аккуратный :D
Спасибо за пошаговую инструкцию по деплойменту бейби бота.
:D