0 added
0 removed
Original
2026-01-01
Modified
2026-02-26
1
<p>Привет! Это вторая моя статья о новом проекте - telegram bot на python, по продаже товаров. В<a>первой части</a>я описал, с чего начал этот проект и какой был финальный результат. Сегодня я хочу поговорить о CI/CD проекта.</p>
1
<p>Привет! Это вторая моя статья о новом проекте - telegram bot на python, по продаже товаров. В<a>первой части</a>я описал, с чего начал этот проект и какой был финальный результат. Сегодня я хочу поговорить о CI/CD проекта.</p>
2
<p>Когда проект достиг стадии MVP (minimum valuable product, минимально жизнеспособный продукт) - очень хотелось вывести его в свет. Для того, чтобы бот постоянно работал, для первых пользователей (тут кто-то был слишком оптимистичен, без рекламы к боту пользователи не придут) и для того, чтобы была возможность выкатывать остальную функциональность маленькими итерациями. Время делать CI/CD.</p>
2
<p>Когда проект достиг стадии MVP (minimum valuable product, минимально жизнеспособный продукт) - очень хотелось вывести его в свет. Для того, чтобы бот постоянно работал, для первых пользователей (тут кто-то был слишком оптимистичен, без рекламы к боту пользователи не придут) и для того, чтобы была возможность выкатывать остальную функциональность маленькими итерациями. Время делать CI/CD.</p>
3
<p>И снова хотел бы напомнить, что я не профессиональный DevOps, а всего лишь тестировщик. Поэтому текст ниже - всего лишь мой опыт, а не руководство, как делать правильно бота профессионально.</p>
3
<p>И снова хотел бы напомнить, что я не профессиональный DevOps, а всего лишь тестировщик. Поэтому текст ниже - всего лишь мой опыт, а не руководство, как делать правильно бота профессионально.</p>
4
<h3>Начнем с CI</h3>
4
<h3>Начнем с CI</h3>
5
<p>Под CI я понимаю запуск тестов, сборку docker image и публикацию артефактов - тех самых images - в репозиторий. Решил не использовать сторонних сервисов, а сделать все на основе GitHub. В целом, как работать с GitHub Actions, можно почитать в<a>официальной документации</a>, тут я попытаюсь описать неочевидные для меня вещи.</p>
5
<p>Под CI я понимаю запуск тестов, сборку docker image и публикацию артефактов - тех самых images - в репозиторий. Решил не использовать сторонних сервисов, а сделать все на основе GitHub. В целом, как работать с GitHub Actions, можно почитать в<a>официальной документации</a>, тут я попытаюсь описать неочевидные для меня вещи.</p>
6
<p>Первая неочевидная вещь - как опубликовать docker image в реестр. Я пробовал несколько actions, пытался писать свой скрипт и, в конечном итоге, остановился на официальном<a>Build and push Docker images</a>:</p>
6
<p>Первая неочевидная вещь - как опубликовать docker image в реестр. Я пробовал несколько actions, пытался писать свой скрипт и, в конечном итоге, остановился на официальном<a>Build and push Docker images</a>:</p>
7
<p>Вторая неочевидная вещь - secrets.PACKAGE_REGISTRY_TOKEN. В интернете разработчики используют secrets.github_token - это стандартный токен, с которым пакет соберется и, даже, опубликуется в вашем реестре. Проблема лишь в том, что после публикации пакета не срабатывается триггер у других actions. В моем случае должен был запуститься следующий workflow для CD. Чтобы триггер сработал, нужно создать новый секрет, в моем случае secrets.PACKAGE_REGISTRY_TOKEN и дать ему права на чтение/запись в реестр.</p>
7
<p>Вторая неочевидная вещь - secrets.PACKAGE_REGISTRY_TOKEN. В интернете разработчики используют secrets.github_token - это стандартный токен, с которым пакет соберется и, даже, опубликуется в вашем реестре. Проблема лишь в том, что после публикации пакета не срабатывается триггер у других actions. В моем случае должен был запуститься следующий workflow для CD. Чтобы триггер сработал, нужно создать новый секрет, в моем случае secrets.PACKAGE_REGISTRY_TOKEN и дать ему права на чтение/запись в реестр.</p>
8
<blockquote><h3>Также интересно:</h3>
8
<blockquote><h3>Также интересно:</h3>
9
<p><a>Как создать бота в Telegram</a>: большая инструкция</p>
9
<p><a>Как создать бота в Telegram</a>: большая инструкция</p>
10
</blockquote><h3>Переходим к CD</h3>
10
</blockquote><h3>Переходим к CD</h3>
11
<p>В моем случае CD - это доставка артефактов на сервер, миграция базы, запуск приложения. Возможности автоматического отката или бесшовной поставки - нет, да она и не нужна пока. В случает с CI, использовался GitHub-ранер. В бесплатной версии GitHub пользователю предоставляется несколько машино\часов для сборки проектов, чего вполне достаточно для домашнего проекта. Но для CD нужен собственный ранер, который возможно занять на постоянной основе, и на котором будет запущен весь проект.</p>
11
<p>В моем случае CD - это доставка артефактов на сервер, миграция базы, запуск приложения. Возможности автоматического отката или бесшовной поставки - нет, да она и не нужна пока. В случает с CI, использовался GitHub-ранер. В бесплатной версии GitHub пользователю предоставляется несколько машино\часов для сборки проектов, чего вполне достаточно для домашнего проекта. Но для CD нужен собственный ранер, который возможно занять на постоянной основе, и на котором будет запущен весь проект.</p>
12
<h3>Добавляем свой runner в GitHub</h3>
12
<h3>Добавляем свой runner в GitHub</h3>
13
<p>Для этого проекта использовались сервера<a>Digital Ocean</a>, так что ниже изложена инструкция по добавлению Docker droplet в качестве ранера к существующему проекту:</p>
13
<p>Для этого проекта использовались сервера<a>Digital Ocean</a>, так что ниже изложена инструкция по добавлению Docker droplet в качестве ранера к существующему проекту:</p>
14
<ol><li>После создания дроплета Docker 5:19.03.1~3 on 18.04, заходим на него через ssh;</li>
14
<ol><li>После создания дроплета Docker 5:19.03.1~3 on 18.04, заходим на него через ssh;</li>
15
<li>Первое, что нужно сделать - добавить пользователя, так как GitHub Runner не позволяет запустить агент от root;</li>
15
<li>Первое, что нужно сделать - добавить пользователя, так как GitHub Runner не позволяет запустить агент от root;</li>
16
</ol><p>$ adduser github</p>
16
</ol><p>$ adduser github</p>
17
<ol><li>Вводим пароль и заполняем информацию о пользователе. Или можно оставить ее пустой;</li>
17
<ol><li>Вводим пароль и заполняем информацию о пользователе. Или можно оставить ее пустой;</li>
18
<li>Добавляем пользователя в группы<a>sudo</a>и<a>docker</a>;</li>
18
<li>Добавляем пользователя в группы<a>sudo</a>и<a>docker</a>;</li>
19
</ol><p>$ adduser github sudo $ sudo usermod -aG docker github $ newgrp docker</p>
19
</ol><p>$ adduser github sudo $ sudo usermod -aG docker github $ newgrp docker</p>
20
<ol><li>Логинимся только что созданным пользователем;</li>
20
<ol><li>Логинимся только что созданным пользователем;</li>
21
</ol><p>$ sudo su - github</p>
21
</ol><p>$ sudo su - github</p>
22
<ol><li>Скачиваем и устанавливаем ранер, как указанно в инструкции<em>Settings -> Actions -> Add runner</em>. Имена ранера и рабочей директории можно оставить со значениями по умолчанию;</li>
22
<ol><li>Скачиваем и устанавливаем ранер, как указанно в инструкции<em>Settings -> Actions -> Add runner</em>. Имена ранера и рабочей директории можно оставить со значениями по умолчанию;</li>
23
<li>Чтобы запустить ранер как сервис, останавливаем текущий скрипт Ctrl+C;</li>
23
<li>Чтобы запустить ранер как сервис, останавливаем текущий скрипт Ctrl+C;</li>
24
<li>Устанавливаем сервиса ранера;</li>
24
<li>Устанавливаем сервиса ранера;</li>
25
</ol><p>$ ./svc.sh install</p>
25
</ol><p>$ ./svc.sh install</p>
26
<ol><li>Запускаем ранер как сервис;</li>
26
<ol><li>Запускаем ранер как сервис;</li>
27
</ol><p>$ ./svc.sh start</p>
27
</ol><p>$ ./svc.sh start</p>
28
<ol><li>В workflow yaml файле меняем runs-on: ubuntu-latest на runs-on: self-hosted;</li>
28
<ol><li>В workflow yaml файле меняем runs-on: ubuntu-latest на runs-on: self-hosted;</li>
29
</ol><h3>Реализация Deploy Workflow</h3>
29
</ol><h3>Реализация Deploy Workflow</h3>
30
<p>Идея такая, что должно быть два workflow. Первый - CI, срабатывает на каждый комит в master-ветку. Он собирает артефакты и публикует их в репозиторий. Второй - CD, срабатывает на публикацию пакета в реестр и дальше доставляет этот пакет на специальный агент. Так как это бот-магазин, то CD workflow может быть несколько (по одному на каждый магазин). Это основная причина, почему сборку и доставку разделил на два отдельных процесса.</p>
30
<p>Идея такая, что должно быть два workflow. Первый - CI, срабатывает на каждый комит в master-ветку. Он собирает артефакты и публикует их в репозиторий. Второй - CD, срабатывает на публикацию пакета в реестр и дальше доставляет этот пакет на специальный агент. Так как это бот-магазин, то CD workflow может быть несколько (по одному на каждый магазин). Это основная причина, почему сборку и доставку разделил на два отдельных процесса.</p>
31
<p>Ниже приведен пример, как указать в yaml файле тригер на публикацию пакета. И как запускать флоу на личном ранере</p>
31
<p>Ниже приведен пример, как указать в yaml файле тригер на публикацию пакета. И как запускать флоу на личном ранере</p>
32
<p>Дальше выполняются шаги с docker-compose по обновлению приложения. Шаги следующие: остановить приложение, забрать последнюю версию артефактов, мигрировать базу, запустить новую версию приложения.</p>
32
<p>Дальше выполняются шаги с docker-compose по обновлению приложения. Шаги следующие: остановить приложение, забрать последнюю версию артефактов, мигрировать базу, запустить новую версию приложения.</p>
33
<p>На данный момент бот постоянно работает и быстро обновляется после выхода новой версии.</p>
33
<p>На данный момент бот постоянно работает и быстро обновляется после выхода новой версии.</p>
34
<p>Надеюсь, вам было полезно и познавательно. Тема не очень простая, так что любые вопросы и замечания оставляйте в комментариях под этим постом.</p>
34
<p>Надеюсь, вам было полезно и познавательно. Тема не очень простая, так что любые вопросы и замечания оставляйте в комментариях под этим постом.</p>
35
<p>Также, если вам интересно следить за дальнейшим развитием этого проекта, то в<a>telegram канале</a>я публикую маленькие заметки по этой теме.</p>
35
<p>Также, если вам интересно следить за дальнейшим развитием этого проекта, то в<a>telegram канале</a>я публикую маленькие заметки по этой теме.</p>