Экватор рассказа про техническое оживление Python Дайджест проекта. Ранее рассказал как перейти с Python 3.4 на Python 3.11 и автоматически актуализировать весь код. В этой части расскажу про организацию CI для Open Source проекта на основе Github Actions — как гонять тесты, проверять код, зависимости, разворачивать приложение и делать бэкапы на внешнее хранилище.
Содержание цикла статей
- 1 часть: Как обновиться с Python 3.4 до Python 3.11, если pip уже сломан
- 2 часть: Как актуализировать всю кодовую базу с помощью pre-commit
-
3 часть: Как сделать CI для OpenSource проекта с Github Actions
— вы здесь — - 4 часть: Как ускорить Django проект до (почти) максимума
Состояние после форматирования кода
- Приложение запускается как локально, так и на сервере, тесты проходят.
- Код можно запускать на Python 3.11, а зависимости актуальны и добавлены через
poetry
. - Есть сервер на Ubuntu 14.04, бэкапы, сертификаты и прочее — обновляются руками.
- Выкатка изменений в приложение происходит руками через git pull & restart commands.
Задача (часть 3) — убрать необходимость заходить на сервер для типовых операций
В Python Дайджест есть три операции, которые хотелось бы сразу автоматизировать:
- Прогон тестов и проверка кода через pre-commit (вторая часть) — tests.yaml
- Деплой приложения на сервер — ci.yaml
- Бэкап базы данных и загрузка на внешний диск — backup.yaml
План работ
- Выбрать CI для автоматизации рутины
- Подготовить новый сервер
- Настроить CI для деплоя и бэкапа приложения
Как выбрал Github Actions в качестве CI
Лет 5 назад, Travis CI был "CI по умолчанию для Open Source проектов", с помощью него запускали тесты, делали сборки, даже работали с серверами по SSH. Было удобно и бесплатно.
Сейчас "CI по умолчанию для OpenSource на Github" — это Github Actions. Это средство автоматизации, которое позволяет к событиям взаимодействия с репозиторием привязать выполнение почти любых действий. Про него на хабре несколько раз писали — раз, два, три.
Github Actions крут тем, что сами Actions — это плагины (часто скрипты или Docker образ), которые пишут все кому не лень и выкладывают на Github Marketplace.
Работает это так:
- Когда меняем что-то в репозитории — push, pull request, по кнопке, по расписанию и т.д. — возникает событие;
- Github Actions ловит это событие и запускает агента;
- агент поднимает контейнер с указанной версией операционной системы;
- дальше внутри контейнера можете делать что пожелаете.
А Github Action плагины — это готовые действия, которыми вы можете стянуть код из репозитория, преобразовать его, куда-то сохранить и прочее. Плагинов много.
Какие Github Actions выбрал
Для моих задач хватило таких плагинов. Они покрывают действия от скачивания кода репозитория до сборки образа в Docker Hub и подключения к внешнему серверу по SSH.
- actions/checkout — стянуть код репозитория
-
snok/install-poetry — установить
poetry
- actions/cache — чтобы переиспользовать virtualenv окружение
-
pre-commit/action — запустить все
pre-commit
проверки - actions/setup-python — установить необходимую версию python
- codecov/codecov-action — залить результаты прогона тестов в codecov
- rlespinasse/github-slug-action — для удобства использования gituhb переменными
- docker/metadata-action — подготовить переменные для сборки образа
- docker/setup-qemu-action — окружение для сборки Dockerfile
- docker/setup-buildx-action — чем будем собирать Dockerfile
- docker/login-action — авторизоваться в DockerHub для хранения образа
- docker/build-push-action — собрать и залить Docker образ
- appleboy/scp-action — для загрузки файлов на сервер
- appleboy/ssh-action — для исполнения команд на сервере
Важное примечание. Эти Github Actions популярны, ими пользуются тысячи участников сообщества. Однако их разрабатывает открытое сообщество, что не гарантирует стабильность, корректность и совместимость новых и старых версий. Изучайте состав, скрипты и Docker образы на предмет ошибок и очевидных уязвимостей перед использованием.
Как подготовил сервер
Старый сервер был на устаревшей Ubuntu 14.04, для которой не удалось найти живых репозиториев с пакетами и обновиться выше. Также сама система была сильно замусорена. Поэтому решил, что проще создать новый сервер и настроить.
Мне не хотелось получить мусорный сервер спустя очередные 5 лет, поэтому решил запускать приложение с помощью docker compose (docker_compose.prod.yml), собирая Docker (Dockerfile) образ приложения.
Но для начала настроил сервер с актуальной Ubuntu.
Python Дайджест хостится на FirstVDS уже давно, без неожиданных проблем, поэтому и новый сервер проще запустить там. У FirstVDS есть подробная документация на большинство случаев жизни, описаны даже самые первые шаги с хостингом.
Купил сервер с 2 потоками CPU, 4 Gb RAM и 60 Gb SSD. За глаза и за уши такого количества ресурсов хватает для проекта.
После получения сервера нужно было:
- Создать юзера для приложения.
- Убрать SSH авторизацию через пароль на ключ.
- Установить необходимый софт
apt-get update && apt-get install -y vim htop nginx-full postgresql postgresql-contrib rclone redis locales cron
- Опционально. Установить zsh и oh-my-zsh.
- Создать в PostgreSQL базу данных и настроить для использования из Docker контейнера.
- Установить certbot для получения SSL, скопировать конфили let's encrypt со старого сервера с помощью scp.
- Разрешить исполнение таблицы crontab настроенной у юзера. Чтобы из ограниченного пользователя запускать регулярные задачи.
- Настроить rclone для переноса файлов на внешний диск, в моем случае Яндекс Диск, а затем перенести настройки на сервер. Это потребуется для бэкапов.
- Установить Docker и docker compose.
- Создать аккаунт на Docker Hub и создать там проект, чтобы заливать образы.
- Дорабатываем nginx.conf — добавляем чтение nginx конфига приложения из отдельного места (include секция).
Сервер готов для следующих шагов.
Как настроил переменные окружения
Хорошо писать программы с учетом 12 factors, получаем более удобное, понятное в поддержке приложение. Один практический аспект из 12 факторов — это отказаться от hardcoded настроек в пользу настройки через окружение. В исполняемом окружении прописываем переменные (доступ до БД, секреты и прочее), а приложение считывает их на старте с помощью библиотеки python-dotenv.
Github Secrets позволяют сохранить переменные окружения, а затем обратиться к ним при работе CI. Причем, на каждую ветку можно сделать отдельные наборы переменных. Вот я и создал набор production и указал переменные для доступа по SSH, а также для работы приложения.
Готово, теперь можем запускать.
Как получил результат
Сделал тестовый коммит и процессинг начался:
- Проверился код с помощью
pre-commit
, прошли тесты. - Собрался и залился Docker образ в Docker Hub.
- Скопировались настройки на сервер через SCP.
- Запустились миграции, подготовилась статика и запустилось приложение.
- nginx принимает новый конфиг и сервис готов к приему трафика по домену.
Дальше в настройки DNS домена была настроена A запись с парой домен-ip адрес сервера.
Вот и все, теперь Github Actions будет автоматически раз в сутки делать бэкап базы на Яндекс.Диск, при Pull Request будут проходить тесты и проверки кода, а по коммиту в основную ветку — разворачиваться приложение на сервере.
Выводы
- Сочетание Docker compose + CI на виртуальном сервере все также хорошо работает для проектов, после базовой настройки сервера не требуется за ним следить.
- Github Actions имеет много плагинов (часть очень слабые), которые решают типовые задачи по эксплуатации проекта. Однако иногда проще «руками» зайти по SSH и сделать необходимое, вместо изучения внутренностей actions.
- Теперь вносить изменения в Python Дайджест стало приятным, без боязни сломать зависимости или код.
НЛО прилетело и оставило здесь промокод для читателей нашего блога:
— 15% на все тарифы VDS (кроме тарифа Прогрев) — HABRFIRSTVDS.