Как я развернул фулстек-приложение на "NestJS" с "Angular" в "Supabase" и "Vercel"
Я разработал небольшое фулстек-приложение в качестве примера REST
+ WebSockets
бойлерплейта на NestJS
и Angular
. В приложении используется PostgreSQL
для хранения данных, Redis
для кэширования и Minio
для работы с файлами. Изначально целевой средой для развертывания был Kubernetes
, но для ускорения разработки и тестирования MVP
я решил использовать бесплатные облачные сервисы: Supabase
для инфраструктуры и Vercel
для деплоя бэкенда и фронтенда.
1. Проблемы
- Инфраструктура для разработки: Для локальной разработки необходимо поднимать
PostgreSQL
,Redis
,Minio
и сервер авторизации (Authorizer.dev
). Это занимает время и требует ресурсов. - Сложность деплоя в
Kubernetes
: Настройка сборкиDocker
-образов, процесс билда и деплоя вKubernetes
занимает много времени, особенно еслиDocker
-образы имеют большой размер. - Ограниченный бюджет: Для небольших проектов или тестирования
MVP
нет бюджета на выделенные серверы или полноценную инфраструктуруKubernetes
.
2. Решение
Я решил добавить возможность деплоя приложения не только в Kubernetes
, но и в бесплатные облачные сервисы, такие как Supabase
(для баз данных, хранилища и авторизации) и Vercel
(для деплоя бэкенда и фронтенда). Это позволило ускорить процесс разработки и тестирования, а также снизить затраты на инфраструктуру.
3. Исходное состояние
- Бэкенд:
NestJS
сREST API
иWebSockets
для рассылки событий (например, текущее серверное время). - Фронтенд:
Angular
для взаимодействия с бэкендом черезREST
иWebSockets
. - Инфраструктура:
- Локально запущенные сервисы:
Authorizer.dev
для авторизации,PostgreSQL
для базы данных,Redis
д ля кэширования,Minio
для хранения файлов. - Деплой в
Kubernetes
с использованиемDocker
-образов для бэкенда и фронтенда. PostgreSQL
и миграции запускались черезDocker Compose
.E2E
-тесты также запускались черезDocker Compose
.
- Локально запущенные сервисы:
4. Текущее состояние
- Бэкенд и фронтенд: Работают локально, но инфраструктура полностью перенесена в
Supabase
- Используемые облачные сервисы:
Supabase Auth
: Заменен локальныйAuthorizer.dev
.Supabase Database
: Заменены локальныеPostgreSQL
иRedis
.Supabase Storage
: Заменен локальныйMinio
.
- Деплой: Бэкенд и фронтенд деплоятся на
Vercel
. Из-заserverless
-архитектурыVercel
WebSockets
не работают, поэтому соответствующие тесты отключены. CI/CD
: Сборка и деплой происходят черезGitHub Actions
, включая применение миграций и запус кE2E
-тестов.
5. Этапы реализации
5.1. Переход на Supabase Database
- Локальная
PostgreSQL
заменена наSupabase Database
. - Для миграций использован
pg-flyway
(мини-версияFlyway
безJava
). Я не хотел отказываться от функционалаFlyway
, но при этом не хотел ставитьJava
в момент деплоя приложения. В итоге я написал миниверсиюflyway
—pg-flyway
. - В
Supabase
нельзя создавать несколько баз данных, поэтому миграции запускаются в одной базе с использованием разных таблиц для учета миграций. Для решения этой проблемы при запуске мигратора можно передать название таблицы, где будет сохраняться информация о миграциях. - Один пользователь используется дл я всех баз данных, так как
Supabase
не позволяет создавать новых пользователей с правами на создание баз. Это ограничение потребовало пересмотра логики работы с базами данных.
5.2. Переход на Supabase
вместо Redis
Redis
заменен наKeyv
с поддержкойPostgreSQL
. В рамках текущего проекта нет специфичных дляRedis
задач, поэтому я принял решение подменитьRedis
на некую имплементацию.- В процессе поиска я увидел, что
CacheModule
дляNestJS
переходит на использованиеKeyv
, и я написал свою оберткуnestjs-mod/keyv
, которая поддерживает какRedis
, так иPostgreSQL
. - Это не полная замена, такая замена справедлива только в простых приложениях, где мы кэшируем часть данных.
5.3. Переход на Supabase Storage
Minio
заменен наSupabase Storage
.- Основные изменения касались логики формирования ссылок для загрузки файлов. В отличие от
Minio
, вSupabase
бакеты и политики создаются черезGUI
, что немного усложняет автоматизацию (я только такой способ смог найти). - Из проблем в коде, была проблема в том, что
FilesModule
был жестко связан сMinio
, пришлось связь разорвать и создать конфигурацию для переопределения методов с уровня приложения через интеграционную конфигурацию.
5.4. Переход на Supabase Auth
- Локальный
Authorizer.dev
заменен наSupabase Auth
. - Проблемы начались сразу, так как ранее
AuthModule
базировал свою логику полностью на логиках и коде для работы сAuthorizer
. - Написан новый
NestJS
-модуль для работы сSupabase Auth
, совместимый с предыдущей реализацией. Этот модуль был написан не с нуля, а путем копирования кода существующегоnestjs-mod/authorizer
. - Сейчас этот новый модуль лежит в этом проекте, но в дальнейшем он будет перенесен в
nestjs-mod/nestjs-mod-contrib
. Просто у меня сейчас по работе возникло слишком много проблем с готовыми серверами авторизации, и нужно написать свою кастомную реализацию. Когда она будет написана и протестирована на обратную совместимость сSupabase
иAuthorizer
, тогда и появится реализацияSupabase
в публичномnpm
-пакете.
5.5. Деплой на Vercel
- Эта штука сожрала очень много времени, я не буду описывать все проблемы на пути, но их было очень много. Просто закину ссылку на примеры конфигураций, жалко, что я увидел их только недавно: примеры конфигураций
Vercel
, а это мой конфиг дляvercel.json
. - После того как вы настроите деплой на
Vercel
и у вас естьe2e
-тесты, часть из них будет падать с ошибками, так какVercel
поднимает приложение на каждый запрос, и если приложение не оптимизировано подserverless
, как мое текущее, то тесты будут падать из-за долго отвечающего сайта. Проблемы с долгим бэком я решил, просто увеличив таймаут ожидания в тестах.
5.6. Переменные окружения
- Это не такая уж и проблема, но она есть. Когда мы деплоим на собственный виртуальный сервер, то сервер — это безличная штука, которую можно снести в любой момент, и она не хранит в себе переменные окружения. Они все хранятся у нас в
CI/CD
. - При использовании
Vercel
иSupabase
у нас появляются еще два места, где можно хранить переменные окружения, и нужно как-то так спроектировать деплой и запуск, чтобы учесть различные варианты. Над эту задачку я тоже много времени потратил.
5.7. Регистрация и авторизация в облаках
- Не стану описывать регистрацию в сервисах
Supabase
иVercel
. Просто приложу небольшое видео о том, как создавать приложения наSupabase
и прописать переменные окружения вVercel
.
6. Инструкция по запуску локального кода с внешней инфраструктурой на Supabase
6.1. Инициализация
git clone git@github.com:nestjs-mod/nestjs-mod-fullstack.git
cd nestjs-mod-fullstack
npm i
cp ./example-supabase.env ./.env