ps. Не є туторіалом. Ділюсь своїм досвідом
Вступ
Ми часто з другом пишемо телеграм ботів для своїх потреб та інколи брейнштормимо різні ідеї для класного проєкту. Декілька днів тому, я задумався про те, щоб взяти хостинг, оскільки Free Tier на AWS закінчився, а платні тарифи там трохи кусаються. Та і мати трохи досвіду з конфігурацію машини, ось цим всім, також не завадить.
Купив VPS на https://hostiq.ua
Ще дивився цей варіант https://gmhost.ua/uk/hosting-dlja-telegram-botu, але там ціна була вищою за значно менші ресурси.
Вийшло близько 700 грн за такі ресурси:
50 ГБ SSD
4096 MB RAM
CPU: 2 core
OS: AlmaLinux release 8.9 (Midnight Oncilla)
Створення і конфігурації вашої машини займає близько 2х годин.
SSH доступ
Після успішної покупки виділених ресурсів, я отримав адресу машини і пароль для входу по SSH.
В терміналі достатньо прописати:
❯ ssh root@<vps ip>
*ввести відповідний пароль.
Git
Перш за все, я вирішив встановити гітsudo dnf update -y
sudo dnf install git
Docker
sudo dnf --refresh update
sudo dnf upgrade
sudo dnf install yum-utils
sudo yum-config-manager --add-repo
https://download.docker.com/linux/centos/docker-ce.repo
sudo dnf install docker-ce docker-ce-cli
containerd.io
docker-compose-plugin
sudo systemctl start docker
sudo systemctl enable docker
sudo systemctl status docker
Спейс для проєкту
Створив репозиторій з простеньким телеграм ботом https://github.com/overpathz/render-boot-bot
Додав змінну оточення для телеграм токену.
Створив окрему директорію під свої проєкти. Сюди я склонував репу з ботом — git clone ..
Також, ось мій Dockerfile
FROM maven:3.8.5-openjdk-17 as build
COPY . .
RUN mvn clean package -DskipTests
FROM openjdk:17.0.1-jdk-slim
COPY --from=build /target/render-test-bot-0.0.1.jar demo.jar
EXPOSE 8080
ENTRYPOINT ["java", "-jar", "demo.jar"]
Ручний запуск контейнера
У вашого телеграм бота є токен, який ви не можете тримати у відкритому доступі. Тому, один з можливих варіантів тримати його у змінних середовища. Але, як його передати докер контейнеру при запуску?
Як це робиться без докеру в IntelliJ IDEA
В application.properties у вас має бути щось таке
telegram.bot.token=${TELEGRAM_BOT_TOKEN}
В параметрах запуску ставите галочку на змінних середовища і додаєте відповідну пропертю
Під час запуску, воно спробує знайти цю пропертю з різних джерел, одне з них це будуть змінні середовища.
Створення образу і запуск контейнеру
Створення образу: docker build -t <image name> .
docker run -d --name <running container name> -p 8080:8080 <image name>
Але, контейнер це ізольоване середовище. Тому, потрібно йому передати змінну оточення. Якщо вона вже є у вас на машині, можна просто ось так:
docker run -d --name <this container name> -p 8080:8080 -e TELEGRAM_BOT_TOKEN <image name>
Якщо ні, то можна встановити значення при передачі змінних оточення:
docker run -d --name <this container name> -p 8080:8080 -e TELEGRAM_BOT_TOKEN=somesupersecretvalue123 <image name>
Створення імеджу і запуск контейнера (в мене це дуже швидко, оскільки відповідні шари вже присутні)
GitHub Actions
Окей. Непогано. Бота заранили. Але що, якщо ми хочемо трішечки автоматизувати це діло і при кожному пуші(що не є добре) робити деплой на наш сервер?
Робити це можна багатьма способами, але я вирішив скористатись GitHub Actions.
GitHub Actions is a continuous integration and continuous delivery (CI/CD) platform that allows you to automate your build, test, and deployment pipeline. You can create workflows that build and test every pull request to your repository, or deploy merged pull requests to production.
Карявенький, але робочий скрипт, який робить наступні речі:
Налаштовує JDK для збірки за допомогою Maven
Билд проєкту з Maven
Створення Docker-образу на основі нашого Dockerfile в репозиторії
Побудова та пуш Docker-образу
Розгортання на сервері (використовуючи SSH ми виконуємо скрипт на нашій машині віддалено. Ми підтягуємо наш докер образ з нашого репозиторію і запускаємо його)
Щоб це все робити, нам потрібні наші специфічні значення(IP нашого сервера, користувач, логін і пароль від докерхабу), які ми не можемо просто тримати десь в репозиторії. Для цього, створюються “секрети“.
У вашому репозиторії, ви можете зайти в налаштування і створити секретні змінні, які будуть використані у вашому CI/CD скрипті.
DockerHub
Щоб мати змогу пушити ваші образи у ваш репо, вам потрібно зареєструватися на докерхабі.
Створити репозиторій
Створити токен доступу, щоб використовувати його у вашому скрипті
Тепер, після кожного коміту або ПР(ви це можете конфігурувати), у вас буде запускатися джоба, яка буде містити кроки, які ви описували у вашому скрипті
Після деплою, мій контейнер успішно запускається і можна почати користуватися ботом:
Трішки про shutdown хуки
Додатково можна, наприклад, розіслати сповіщення користувачам, що бота буде призупинено, використовуючи shutdown хуки які будуть викликані при завершенні Java процесу. Щось типу такого:
@Component
@RequiredArgsConstructor
@Slf4j
public class ShutdownHookContextListener {
private final UserInMemoryDao usersDao;
private final TgMessageSender messageSender;
@EventListener
public void handleContextRefresh(ContextRefreshedEvent event) {
log.info("Executing handle listener");
Runtime.getRuntime().addShutdownHook(new Thread(() -> {
log.info("Executing hook");
List<Long> users = usersDao.getUsers();
users.forEach(userId -> messageSender.sendTextMessage(userId, "Телеграм бот скоро буде перезапущений! Вибачте за незручності!"));
}));
}
}
При завершенні контейнеру, користувач отримає таке повідомлення:
Але звісно, це краще робити через черги повідомлень, у випадку, якщо у вас є декілька нод і ви по черзі робите деплой, щоб підтримувати availability вашої системи. Таким чином, консюмери(інші ноди, які не перезапускаються), можуть надіслати користувачам це повідомлення, бо shutdown хук може не виконатися якщо різко перервати роботу Java процесу.