31.10.2026 796 материалов

От приложения до кластера: как план на 18 месяцев сжали до трёх сервисов

Разработчик Эйосиас Негаш собирался строить «флагманскую платформу» с Postgres, Redis и service mesh — и передумал. История Ivyk8: от форка Android-приложения Ivy Wallet+ до трёх stateless-сервисов на Kubernetes и пяти записанных решений, которые объясняют, почему базы данных тут нет.

От приложения до кластера: как план на 18 месяцев сжали до трёх сервисов

«Примерно 18 месяцев работы для целой команды» — такая оценка, полученная на этапе проектирования, оказалась полезнее любого кода: она убила в проекте всё лишнее ровно в тот момент, когда это было бесплатно.

Порог входа в персональные проекты сейчас смехотворно низкий. Промпт, полчаса — и у тебя на руках архитектурная схема с Istio, Argo CD и шиной сообщений. Проблема начинается следующей секундой, когда понимаешь, что под эту схему нужно нанять команду. Именно это произошло с проектом Ivyk8 — и разбор того, как из него вырезали половину технологий, стоит прочитать даже тем, кто до Kubernetes не дотянется никогда.

Зачем вообще всё это: деньги, телефон и Google Drive

Точка отсчёта — Android, а не серверная. Ivy Wallet — открытый менеджер личных финансов, который 5 ноября 2024 года его владелец заархивировал. Разработчик Эйосиас Негаш решил пользоваться дальше и сделал форк — Ivy Wallet+ со своим пакетным именем и логотипом.

Нововведений набралось с полдесятка: фото- и аудиовложения к операциям, координаты и название места с миграцией базы Room и кнопкой открытия карт, «баланс на дату» по тапу в истории, перенос фильтра отчётов без горизонтальной прокрутки. И отдельная история — авто-заполнение по SMS: приложение слушает выбранный SIM-слот, вытаскивает из банковских сообщений сумму, баланс, дату и описание по регулярным выражениям для каждого банка и показывает уведомление с готовой операцией. Правила импортируются из JSON; правила написаны для четырёх банков и одного мобильного кошелька.

Важно тут не количество фич, а эффект для данных. Телефон стал захватывать заметно больше информации, а изучать годы операций на шести дюймах — занятие мазохиста. Тем более что Ivy Wallet+ уже пишет резервные копии в Google Drive, и этот файл — весь интерфейс между телефоном и внешним миром.

Отсюда и идея Ivyk8 (Ivy + k8s): десктопный read-only дашборд, который читает бэкап из Google Drive и рисует то, чего экран телефона не нарисует: тренды, средние, прогнозы расходов и поступлений. Задача по меркам индустрии — сугубо бытовая. Но именно поэтому интересно, во что её умудрились раздуть.

План, который назвали бы «флагманским»

Стартовал проект с просьбы к Claude Code собрать «топ-1% флагманский проект». Схема вышла богатой: Kotlin-клиент синхронизации и Go-API, отдельный сервис валют и воркер отчётов, Postgres с read-репликами, Redis в роли и кэша, и очереди, плюс Istio, Argo CD, Argo Rollouts, KEDA, SOPS и полный набор observability.

Дальше — лучший ход во всей этой истории. Попросили ту же модель раскритиковать схему до того, как написана хоть строчка кода. Ответ вышел отрезвляющим: это примерно 18 месяцев работы команды. Звучит как анекдот, но дальше шли конкретные придирки, а они ценнее любой оценки сроков.

Разберём их, потому что это квинтэссенция типичных ошибок начинающего backend-проекта.

  • Redis в роли кэша и очереди одновременно — это противоречие. Кэшу нужна политика allkeys-lru (выбрасывай что угодно под давлением памяти), очереди — noeviction (никогда не теряй задачу). Один инстанс не может быть тем и другим.
  • Read-реплики ломают гарантию read-your-writes. Синхронизирующий клиент загрузил данные, тут же их читает — и получает старую версию с реплики. Отладить такое в одиночку — квест с подвохом.
  • Самописный StatefulSet для Postgres — признак незрелого суждения в Kubernetes. Либо используй оператор, либо не запускай базу вовсе.
  • Нет слоя идентификации. В проекте никто не отвечал на вопрос, кто пользователь.
  • Cosign без проверки подписи при admission — это театр безопасности. Подписанные образы ничего не значат, пока кластер не проверяет эти подписи.

Последний пункт особенно хорош: критика назвала дыру ещё до постройки, и дыра эта, признано, существует до сих пор. Релизный workflow образы подписывает, а вот кластер их по-прежнему не проверяет. Список дел не закрыт.

Отдельная оговорка: «18 месяцев работы команды» — оценка языковой модели, а не живого архитектора, и относиться к ней стоит как к ориентиру по объёму, а не как к точному сроку. Но направление удара верное: масштаб планирования оказался на порядок больше масштаба задачи.

Резать в два захода

Первое сокращение — промпт на MVP. Из него ушли GitOps, канареечные релизы, observability, KEDA и подпись образов. Оставили Kubernetes и базовый CI со статическим анализом.

Второй, окончательный рез произошёл 1 октября и зафиксирован пятью ADR — короткими файлами, которые фиксируют решение и то, что оно заменило.

  • ADR-0001: три stateless-сервиса на TypeScript — web-dashboard, drive-sync-service (публичный бэкенд дашборда) и analytics-service (внутренний). Без Postgres и без Redis.
  • ADR-0002: сессии живут в зашифрованной cookie, поэтому сервисы не хранят состояние сессий вообще.
  • ADR-0003: доступ к Google Drive ограничен scope’ом drive.readonly — приложение физически не может изменить бэкап, даже если его скомпрометируют.
  • ADR-0004: Kubernetes — единственный путь доставки: k3d локально и в CI, никакого docker-compose.
  • ADR-0005: курсы валют — от Европейского центрального банка, с запасным источником для валют, которых у ЕЦБ нет.

Ключевое — рассуждение под первым пунктом. Аналитика считается в памяти из одного файла, переопределения часового пояса и курса передаются параметрами запроса. Сохранять между запросами нечего — значит, и базе данных здесь нечего делать. При промахе кэша drive-sync-service просто перезагружает бэкап в аналитику. Это не костыль, а свойство: stateless-сервисы можно убивать, реплицировать и катить обновления без ритуальных плясок. Через несколько недель от этой стройности будет конкретная практическая отдача — но об этом в следующих главах серии.

А зачем вообще Kubernetes для одного человека

Честный вопрос, и ответ в репозитории сформулирован одной фразой: проект должен быть построен, защищён, протестирован и доставлен так, как это делали бы с настоящим продуктовым продуктом. Дашборд — для одного пользователя. Точка не в дашборде, а в практике: тесты, которые режут merge, сканирование образов, подписанные релизы, выкатка на реальный кластер.

В этом весь смысл затеи: учебный стенд, выдаваемый за продакшен, не даёт ни одного навыка продакшена. Решение тренироваться на собственном проекте — валидное, если не врать себе о масштабе.

Уроки, которые переживут проект

Итог короткий, но его стоит проговорить вслух.

  • Проси критику до кода. Час того, как тебе говорят, что план — театр, дешевле, чем 18 месяцев открытия этого же факта в бою.
  • Statelessness оплачивается один раз. Отказ от базы данных убрал целые классы работ: миграции, бэкапы, реплики, failover.
  • Записывай решение, пока оно свежее. Именно ADR позволяют через несколько недель объяснить, почему в проекте нет Redis — без пересмотра всей архитектуры с чистого листа.

Есть и четвёртый, который из исходника не вытекает напрямую, но лежит на поверхности. Автоматическая критика работает только там, где её привлекают. Схему могли спокойно реализовывать как есть — и получили бы годами строящуюся инфраструктуру для приложения, читающего один файл из Google Drive.

Что дальше

Дальше в серии — первые настоящие функции дашборда и переезд с локального k3d-кластера на три домашние машины. Переезд, по признанию автора, прошёл далеко не гладко и стал источником самых странных постов серии — там, где инфраструктура ломается, обычно и появляются настоящие инженерные истории.

А главный вывод этой главы простой и немного обидный для индустрии: для дашборда, который показывает вам ваши же траты, хватает трёх сервисов, памяти и одного файла. Всё остальное — театр, за который, если не прислушаться к критике вовремя, кто-то заплатит восемнадцатью месяцами.