Скрестил Gogs, Drone и MinIO внутри k8s

Завязка

Я тут писал небольшую статейку (само собой, в org-mode), для удобства хранил её, само собой, в git'е, и решил сделать сборку в pdf для читателя на своём домашнем Drone CI.

Инфраструктура

Мой Drone CI размещён на моём домашнем Kubernetes-«кластере», состоящем из сервера, который хостит, собственно Drone, Gogs, Grafana, и ещё всякое по-мелочи. Собрал я его просто для изучения этого самого k8s, и всё ещё поддерживаю, постепенно наращивая функциональность, но больше для изучения современных технологий и всякой кластеризации.

Drone CI у меня сконфигурирован на использование k8s в качестве runner'а, и оно неплохо работало до того момента, как мне потребовалось хранить артефакты. Оказалось, что Drone не умеет хранить артефакты, и Gogs тоже не умеет. Не то, чтобы меня это сильно удивило, в конце концов, я примерно по этому признаку их и выбирал — в них нет ничего лишнего.

Беглое гугление показало, что лучше всего Drone хранит всякое в S3. Ну что ж,сказано — сделано.

Домашний S3

Немножко погуглив, я обнаружил, что самый простой способ организовать дома S3 — это поставить MinIO. Почитал, какие образы они предоставляют, написал пяток ямлов, kubectl apply -f ., и оно даже сходу почти заработало.

Из интересного: во-первых у них немножко другой API, они не используют хостнеймы для бакетов, а дают к ним доступ через URL, а во-вторых они разнесли работу на два порта, и часть клиентов поддерживает работу через дополнительный элемент в пути, а часть — нет. В итоге проще всего оказалось организовать доступ по двум портам изнутри кластера, доступ снаружи приподзакрыть, а для раздачи файлов сделать новый сервис.

Сервер раздачи

Соответственно, чтобы раздавать файлик без открытия доступа к хранилищу из внешнего контура, пришлось организовать сервер для раздачи файлов. Сначала я погуглил на тему раздачи просто через nginx, но потом я решил, что это неспортивно, и просто реверс-проксирование с кэшем, это не очень прикольно. Да и выставлять хранилище наружу без каких-либо ограничений мне не очень хотелось,в итоге я решил попробовать написать сервис для раздачи.

Сервис на Rust

Поскольку последнее время я осваиваю Rust, то решил посмотреть, как там обстоят дела с написанием веб-сервисов. Рассмотрев несколько возможных библиотек, я выбрал Axum, как довольно популярный, и вроде понятный с точки зрения документации.

В итоге за полтора часа экспериментов получился сервис на 150 строк на rust,который одной ногой умеет ходить в MinIO через rusoto_s3, а другой — отдавать файлы по http через Axum. Получилось в целом неплохо, не разобрался только с юнит-тестированием: замокать весь мир оказалось непросто, и даже с помощью ChatGPT мне пока не удалось наладить тестирование, надо будет отдельно почитать, можно ли как-то малой кровью тестировать такие вот клиенты, без того,чтобы создавать тестовое окружение для S3 и вообще городить огород.

Выводы

В общем, традиционно потратил несколько часов на автоматизацию задачи, которая руками решалась за десять минут, и попутно:

  • Разжился новым сервисом в домашнем k8s, в котором теперь буду хранить всякое
  • Потренировался писать cloud-first веб-сервисы на расте
  • Наладил хранение артефактов для Drone CI

Ну и задачку решил, поэтому доволен.