Gontzal Bilbao

Gontzal Bilbao

  • Email Email
  • Ubicación País Vasco, ES

Despliegue Cloud en GCP - SaaS multi-tenant contenerizado en Cloud Run


Este proyecto recoge cómo llevé a producción una plataforma SaaS B2B multi-tenant sobre Google Cloud Platform. No me bastaba con "que funcione en cloud": quería una arquitectura serverless, observable y reproducible. Contenedores en Cloud Run, datos en Cloud SQL por socket privado, caché y colas en Memorystore, los secretos centralizados y un despliegue que cabe en un solo comando.

Google Cloud Cloud Run Cloud SQL Memorystore Cloud Storage Vertex AI Secret Manager Artifact Registry Docker Firebase Hosting

Contexto y objetivo

Una aplicación SaaS real tiene tres frentes vivos a la vez: un panel web, una API de negocio y procesos en segundo plano (envíos, recordatorios, programaciones). Llevar eso a producción con un coste ajustado y sin un equipo de plataforma dedicado te obliga a apoyarte en servicios gestionados y a automatizar el ciclo de build y despliegue.

Lo que buscaba era desplegar la plataforma con escalado a cero en reposo, conexiones de datos privadas (nada de bases expuestas a internet), las variables sensibles fuera del código y un flujo de despliegue repetible para API, Web y landing.

Arquitectura y servicios

Separé las responsabilidades por servicio gestionado y dejé todo el tráfico de datos dentro de la VPC privada:

  • Artifact Registry — repositorio Docker privado para las imágenes de API y Web.
  • Cloud Run — dos servicios (API NestJS en :4000 y Web Next.js en :3000), públicos, con auth propia por JWT y escalado 0 → N.
  • Cloud SQL (PostgreSQL 16) — base de datos sin exposición directa a internet; Cloud Run se conecta por Unix socket mediante el Cloud SQL Auth Proxy integrado.
  • Memorystore (Redis 7) — caché y backend de colas, accesible solo desde la VPC y con TLS obligatorio.
  • Cloud Storage — almacenamiento de objetos (avatares, adjuntos, recursos) servido con signed URLs temporales en lugar de exponer el bucket.
  • Vertex AI (Gemini) — capa de IA generativa de la plataforma, autenticada por la service account del servicio sin gestionar claves.
  • Secret Manager — connection strings, secretos JWT y claves de terceros, inyectados como variables de entorno en el deploy.
  • Firebase Hosting — landing estática servida por CDN, separada del panel SaaS.

Contenerización

Tanto la API como la Web usan Dockerfiles multi-stage sobre node:22-slim para tener imágenes pequeñas y un arranque rápido. El build se ejecuta desde la raíz del monorepo y se versiona por git SHA además de latest, así cualquier revisión en Cloud Run es trazable a un commit concreto.

  • La API (~164 MB) incluye Prisma y ejecuta prisma migrate deploy en el entrypoint antes de arrancar.
  • La Web (~92 MB) usa el modo standalone de Next.js 15; las variables NEXT_PUBLIC_* se hornean en tiempo de build.

Multi-tenancy y trabajos asíncronos

El enrutado multi-tenant funciona por subdominio ({tenant}.dominio): un proxy reescribe el Host y la Web resuelve el tenant a partir de él. Cada modelo y endpoint lleva tenantId para garantizar el aislamiento.

Los procesos en segundo plano corren con BullMQ dentro del proceso de la API, usando Memorystore como backend. Así me ahorro un servicio extra mientras el volumen lo permite, y dejo la puerta abierta a sacar un worker dedicado a Cloud Run cuando haga falta escalar.

Decisiones técnicas clave

  • Escalado a cero (--min-instances=0): sin tráfico no hay coste de cómputo; el cold start (~2-3s) es asumible en este caso.
  • Direct VPC egress (private-ranges-only): Cloud Run alcanza Memorystore por IP privada sin enrutar todo el tráfico por la VPC ni añadir un connector serverless.
  • Datos por socket, no por IP: --add-cloudsql-instances monta el Cloud SQL Auth Proxy como socket Unix; el acceso a datos pasa siempre por un túnel autenticado, sin exposición directa a internet.
  • Secretos versionados: cada secreto se referencia como NOMBRE=SECRETO:latest; rotar un valor es publicar una nueva versión, sin tocar el código.
  • Migraciones en el arranque: el contenedor aplica las migraciones Prisma al desplegar; para releases críticos se pueden ejecutar como Cloud Run Job previo.

Flujo de despliegue

El ciclo de publicación es el mismo para los tres frentes y se lanza desde la raíz del monorepo:

  • Build de la imagen Docker multi-stage, etiquetada por git SHA y latest.
  • Push a Artifact Registry (repositorio privado por región).
  • Deploy en Cloud Run con un solo comando, que monta los secretos, el socket de Cloud SQL y la salida a la VPC.
  • Migraciones Prisma aplicadas por el propio contenedor en el arranque; la landing se publica aparte en Firebase Hosting.

Resultado e impacto

  • Plataforma en producción con dominios propios y TLS gestionado automáticamente.
  • Coste en reposo casi nulo gracias al escalado a cero, apoyado en créditos de GCP durante el desarrollo.
  • Despliegue de cada servicio (API / Web / landing) reproducible y trazable a un commit.
  • Datos y caché sin exposición directa a internet, secretos centralizados y observabilidad de requests en el panel de operaciones.

¿Tienes que llevar una aplicación a producción en cloud?

Diseñar el despliegue, la contenerización y la observabilidad para que escale sin sorpresas de coste es justo el tipo de problema que me gusta resolver.

Comentar un caso similar Ver más proyectos