«Нужен Kubernetes» часто звучит раньше, чем появляется вторая среда и стабильный CI. В OtherCode мы начинаем с другого вопроса: какой минимальный контур доставки гарантирует воспроизводимую сборку, быстрый откат и понятный on-call — без лишней платформы ради резюме.
Ниже — как студия собирает и выкатывает продукты: Docker как единый артефакт, GitLab CI на собственных docker runners, выбор между Compose, PM2 на VPS и Kubernetes, и паттерн деплоя для othercode.ru и клиентских систем (URAP, Synapse Stream, Typhoon, Galvatec, Diom, Content Factory).
Принцип: один артефакт — много сред
Везде, где возможно, Docker-образ — единственный способ доставить сервис из merge в production. Локально разработчик поднимает тот же стек через Compose; в CI образ собирается и тестируется; на сервере крутится тот же тег.
| Среда | Инструмент | Зачем | |-------|------------|-------| | Laptop | Docker Compose | Паритет с продом, быстрый онбординг | | CI | GitLab docker runner | Сборка, тесты, publish в registry | | Staging / Prod (типичный продукт) | Compose + PM2 (Node) / systemd | Простота, предсказуемая стоимость | | Prod (высокий масштаб / много сервисов) | Kubernetes | Оркестрация, HPA, изоляция команд |
Так мы избегаем классики «у меня работает»: зависимости и OS-слой зафиксированы в образе. Практики тонкой сборки образов — в советах по оптимизации Dockerfile.
GitLab CI и docker runners
Репозитории живут в GitLab. Runners — docker executor: job получает чистый контейнер, собирает проект, гоняет тесты, пушит образ.
Что даёт эта схема
- изоляция сборок (нет «засорённого» агента на bare metal);
- параллельные runners — frontend Next.js, backend API и Python-workers не стоят в одной очереди;
- одинаковый toolchain для URAP (Python), Game API / Synapse (Node + PostGIS-зависимости в образе), Flutter CI для Diom (отдельный job с SDK), ботов Content Factory.
Типичный pipeline:
lint+testbuildDocker imagepushв registry с тегом commit SHA +latestна protected branchdeploy-staging(SSH/API к VPS или облаку)deploy-production— вручную (button) или по тегу релиза
Подробный разбор стадий и кэша — в статье GitLab CI/CD pipeline.
Concurrent runners: зачем платить за параллелизм
Один runner на всё — это очередь из 40 минут на каждый MR, когда параллельно идут Diom (Flutter), сайт на Next.js и ML-smoke для URAP. Мы держим несколько concurrent jobs: короткие проверки не блокируются длинной сборкой образа с системными библиотеками для PostGIS-клиента или нативными зависимостями.
Правило: тяжёлые job (полный e2e, ML eval, Android build) — по правилам или по label, чтобы не жечь минуты на каждый typo-fix в README.
Когда Compose, когда PM2, когда Kubernetes
Это не религиозная война, а таблица решений.
| Критерий | Docker Compose на VPS | PM2 (+ иногда без k8s) | Kubernetes |
|----------|----------------------|-------------------------|------------|
| Число сервисов | 3–15 | Node-приложения, SSR Next | Десятки сервисов, много команд |
| Трафик | Предсказуемый / средний | API и веб othercode.ru | Спайки, нужен HPA |
| Операции | 1–2 инженера знают сервер | Быстрый reload Node | Нужна платформенная экспертиза |
| Сеть / service discovery | Внутренняя docker network | localhost / nginx | Ingress, Service, DNS |
| Стоимость ops | Низкая | Низкая | Высокая (время людей) |
| Откат | Предыдущий image tag | pm2 reload + предыдущий build | Rollback Deployment |
Как выбираем в проектах OtherCode
- othercode.ru (Next.js) — сборка в CI, деплой на VPS RU: процесс под PM2, статика/прокси через nginx, переменные окружения на сервере, zero-ish downtime через reload. Docker используем для вспомогательных сервисов и для паритета сборки.
- Synapse Stream / Game API + PostGIS — сервисы в Compose (API, worker, иногда отдельный geo-job), PostgreSQL/PostGIS либо managed, либо на том же/соседнем хосте с бэкапами. Realtime и геозапросы требуют стабильной БД сильнее, чем «магии» оркестратора.
- URAP AI — Python-workers и API в Docker; GPU/batch — отдельный контур (очередь + мощный хост или Yandex Cloud), online — легче и дешевле.
- Typhoon (STM32/Modbus) и Galvatec — edge/прошивка и шлюзы живут рядом с оборудованием; облачная часть — обычные контейнеры и очереди, не full k8s на каждый контроллер.
- Diom (Flutter) — мобильный клиент; backend деплоится тем же GitLab-пайплайном, что и остальные API.
- Content Factory (Telegram) — бот и workers в Docker Compose; рестарт предсказуемый, масштаб вертикальный до явного потолка.
Kubernetes подключаем, когда: много независимых сервисов с разными релизами, нужен автоскейл по CPU/RPS, несколько команд деплоят в один кластер, или заказчик уже стандартизировал k8s и даёт platform team. Иначе k8s добавляет etcd, Ingress, RBAC и ночные разборы networking — без выигрыша в выручке.
Паттерн деплоя othercode.ru
Упрощённо production-поток сайта и связанных API:
MR → GitLab CI (test + build)
↓
Image / build artifact в registry
↓
Deploy staging (авто)
↓
Smoke / ручная проверка
↓
Deploy production (protected)
↓
PM2 reload / compose up -d
↓
Healthcheck + быстрый rollback tag
Практика:
- Иммутабельные релизы — деплоим конкретный SHA/tag, не «подтянуть latest на сервере и надеяться».
- Секреты не в образе — в env на хосте / в CI variables / в секретнице облака.
- Миграции БД — отдельный шаг до переключения трафика; для PostGIS-схем Synapse особенно осторожно с lock-ами.
- Healthcheck — HTTP
/healthдо снятия старой версии из балансировки (nginx upstream). - Наблюдаемость — логи приложений + метрики хоста; для бизнес-критичных API — алерты по error rate.
Локальная разработка на Compose (сети, volumes, зависимости) разобрана в Docker Compose для разработчика.
Инфраструктурный контур студии
- GitLab — единая точка CI/CD.
- Docker runners — сборка всего стека.
- VPS RU / выделенные серверы — основная посадка продуктов с требованиями по локализации данных.
- Yandex Cloud — когда нужны managed БД, object storage, пиковые GPU или быстрый scale без покупки железа.
- Selectel и аналоги — альтернатива и anti-lock-in к одному провайдеру.
Мы сознательно не завязываем все клиентские прод-контуры на один зарубежный hyperscaler: юридические и сетевые риски для российских продуктов реальны. Гибрид «VPS + российское облако» чаще выигрывает по контролю и предсказуемости счета.
Безопасность и дисциплина релизов
DevOps без security-гигиены — ускорение инцидентов.
| Практика | Как делаем | |----------|------------| | Минимальные образы | Multi-stage, non-root user, мало пакетов | | Сканирование | Зависимости в CI; критичные CVE — блок релиза | | Доступ к prod | SSH keys / bastion, без shared root-паролей | | Аудит деплоев | Кто нажал deploy видно в GitLab | | Backups | БД по расписанию, проверка restore раз в квартал |
Для промышленных контуров (Typhoon/Galvatec) отделяем OT-сегмент от публичного API: Modbus/оборудование не торчит в интернет «для удобства отладки».
Наблюдаемость и инциденты без «кластера ради логов»
Деплой бесполезен, если непонятно, что сломалось. Минимальный набор, который мы держим даже на одном VPS:
- структурированные логи приложений (request id сквозь API → worker);
- health/readiness для nginx upstream и compose healthcheck;
- метрики хоста: CPU, RAM, диск, inode — диск часто убивает prod раньше, чем «не хватило подов»;
- алерты на error rate API и длину очереди Redis (URAP, Content Factory, телеметрия);
- uptime-проверка снаружи для публичных endpoint othercode.ru и клиентских API.
В Kubernetes тот же смысл закрывают ServiceMonitor и Ingress probes — но сами по себе CRD не заменяют договорённость «кто смотрит алерт в 2 ночи». Для студийных продуктов чаще достаточно Prometheus/node exporter или лёгкого стека на VPS плюс уведомление в мессенджер.
Rollback как упражнение, а не теория
Раз в квартал на staging (а для критичных клиентов — по договорённости) прогоняем:
- Деплой заведомо «плохой» версии с падающим health.
- Откат на предыдущий image tag / PM2 release.
- Замер времени до восстановления трафика.
Если откат занимает час ручных правок docker compose и поиска «какой же был SHA» — процесс ещё не готов к Kubernetes и тем более не готов к пику нагрузки Synapse в день события.
Секреты, окружения и конфиги
Три среды — три набора секретов. Мы не копируем .env с production на ноутбук «чтобы воспроизвести баг».
| Тип | Где живёт | Как попадает в процесс |
|-----|-----------|------------------------|
| Build-time | CI variables (masked) | Сборка образа / подпись |
| Runtime app | Env на VPS / secret manager облака | Compose env_file, PM2 ecosystem |
| DB credentials | Отдельно от app secrets | Ротация по расписанию |
Конфиг PostGIS-подключения для Game API, токены Telegram для Content Factory, ключи объектного хранилища для URAP — всё версионируется как наличие переменных в документации, но не как значения в git.
Миграции БД в том же пайплайне
Схема — часть релиза. Для Synapse и прочих PostgreSQL-сервисов:
- миграции лежат в репозитории;
- CI может прогонять migrate на эфемерной БД;
- на production migrate выполняется до переключения трафика на новый API, если изменение обратно совместимо; для ломающих — expand/contract за два релиза.
«Сначала выкатили код, потом вспомнили ALTER» — классический способ получить ночной простой. В связке с Docker это особенно обидно: образ новый, а БД старая.
Онбординг разработчика за день
Хороший DevOps-контур измеряется и скоростью входа:
- Доступ к GitLab и README с
docker compose up. - Локально поднимаются API, Redis, Postgres (с PostGIS-образом, если нужен Synapse).
- Тесты гоняются той же командой, что в CI.
- Staging деплоится кнопкой/пайплайном без SSH-шаманства для типового релиза.
Flutter-сборки Diom и Python-окружение URAP могут требовать отдельных job — но принцип один: воспроизводимость важнее уникальных скриптов на машине тимлида.
Антипаттерны, которые мы режем
- kubectl как первый шаг при одном сервисе и одном разработчике.
- Сборка на production-сервере из
git pullбез CI. - Один runner на все тяжёлые job без concurrency — убитая скорость команды.
- Compose в проде без бэкапов и мониторинга — «как на ноутбуке», только с пользователями.
- PM2 без healthcheck и без версий артефакта — непонятно, что откатывать.
Чеклист перед выбором платформы
- [ ] Есть CI, который собирает immutable artifact
- [ ] Есть staging, близкий к prod
- [ ] Понятен rollback < 15 минут
- [ ] Посчитана стоимость людей на поддержку оркестратора
- [ ] Нагрузка и SLA измеримы (не «нужен scale на всякий случай»)
- [ ] Секреты и доступы разделены по средам
Если после чеклиста хватает Compose + PM2 на VPS — так и делаем. Kubernetes подождёт реального масштаба.
Итог
В OtherCode DevOps — это дисциплина артефактов и доставки: Docker везде, GitLab CI на docker runners с параллелизмом, production чаще на VPS RU с PM2/Compose, Kubernetes — по показаниям, не по моде. Так выкатываются othercode.ru, URAP, Synapse Stream, промышленные и мобильные контуры.
Нужен стабильный пайплайн сборки и деплоя под ваш продукт — обсудим контур.

