Как я писал telegram бот с админкой на Django. Часть 2
2026-02-26 22:52 Diff

Привет! Это вторая моя статья о новом проекте — telegram bot на python, по продаже товаров. В первой части я описал, с чего начал этот проект и какой был финальный результат. Сегодня я хочу поговорить о CI/CD проекта.

Когда проект достиг стадии MVP (minimum valuable product, минимально жизнеспособный продукт) - очень хотелось вывести его в свет. Для того, чтобы бот постоянно работал, для первых пользователей (тут кто-то был слишком оптимистичен, без рекламы к боту пользователи не придут) и для того, чтобы была возможность выкатывать остальную функциональность маленькими итерациями. Время делать CI/CD.

И снова хотел бы напомнить, что я не профессиональный DevOps, а всего лишь тестировщик. Поэтому текст ниже — всего лишь мой опыт, а не руководство, как делать правильно бота профессионально.

Начнем с CI

Под CI я понимаю запуск тестов, сборку docker image и публикацию артефактов — тех самых images — в репозиторий. Решил не использовать сторонних сервисов, а сделать все на основе GitHub. В целом, как работать с GitHub Actions, можно почитать в официальной документации, тут я попытаюсь описать неочевидные для меня вещи.

Первая неочевидная вещь - как опубликовать docker image в реестр. Я пробовал несколько actions, пытался писать свой скрипт и, в конечном итоге, остановился на официальном Build and push Docker images:

Вторая неочевидная вещь - secrets.PACKAGE_REGISTRY_TOKEN. В интернете разработчики используют secrets.github_token - это стандартный токен, с которым пакет соберется и, даже, опубликуется в вашем реестре. Проблема лишь в том, что после публикации пакета не срабатывается триггер у других actions. В моем случае должен был запуститься следующий workflow для CD. Чтобы триггер сработал, нужно создать новый секрет, в моем случае secrets.PACKAGE_REGISTRY_TOKEN и дать ему права на чтение/запись в реестр.

Также интересно:

Как создать бота в Telegram: большая инструкция

Переходим к CD

В моем случае CD - это доставка артефактов на сервер, миграция базы, запуск приложения. Возможности автоматического отката или бесшовной поставки - нет, да она и не нужна пока. В случает с CI, использовался GitHub-ранер. В бесплатной версии GitHub пользователю предоставляется несколько машино\часов для сборки проектов, чего вполне достаточно для домашнего проекта. Но для CD нужен собственный ранер, который возможно занять на постоянной основе, и на котором будет запущен весь проект.

Добавляем свой runner в GitHub

Для этого проекта использовались сервера Digital Ocean, так что ниже изложена инструкция по добавлению Docker droplet в качестве ранера к существующему проекту:

  1. После создания дроплета Docker 5:19.03.1~3 on 18.04, заходим на него через ssh;
  2. Первое, что нужно сделать - добавить пользователя, так как GitHub Runner не позволяет запустить агент от root;

$ adduser github

  1. Вводим пароль и заполняем информацию о пользователе. Или можно оставить ее пустой;
  2. Добавляем пользователя в группы sudo и docker;

$ adduser github sudo $ sudo usermod -aG docker github $ newgrp docker

  1. Логинимся только что созданным пользователем;

$ sudo su - github

  1. Скачиваем и устанавливаем ранер, как указанно в инструкции Settings -> Actions -> Add runner. Имена ранера и рабочей директории можно оставить со значениями по умолчанию;
  2. Чтобы запустить ранер как сервис, останавливаем текущий скрипт Ctrl+C;
  3. Устанавливаем сервиса ранера;

$ ./svc.sh install

  1. Запускаем ранер как сервис;

$ ./svc.sh start

  1. В workflow yaml файле меняем runs-on: ubuntu-latest на runs-on: self-hosted;

Реализация Deploy Workflow

Идея такая, что должно быть два workflow. Первый - CI, срабатывает на каждый комит в master-ветку. Он собирает артефакты и публикует их в репозиторий. Второй - CD, срабатывает на публикацию пакета в реестр и дальше доставляет этот пакет на специальный агент. Так как это бот-магазин, то CD workflow может быть несколько (по одному на каждый магазин). Это основная причина, почему сборку и доставку разделил на два отдельных процесса.

Ниже приведен пример, как указать в yaml файле тригер на публикацию пакета. И как запускать флоу на личном ранере

Дальше выполняются шаги с docker-compose по обновлению приложения. Шаги следующие: остановить приложение, забрать последнюю версию артефактов, мигрировать базу, запустить новую версию приложения.

На данный момент бот постоянно работает и быстро обновляется после выхода новой версии.

Надеюсь, вам было полезно и познавательно. Тема не очень простая, так что любые вопросы и замечания оставляйте в комментариях под этим постом.

Также, если вам интересно следить за дальнейшим развитием этого проекта, то в telegram канале я публикую маленькие заметки по этой теме.