Fundaia

Entrar Empezar

Despliegues

Cada intento de poner un servicio a servir es un despliegue numerado, con su commit, su imagen, su registro y su resultado. Esta página explica cómo avanza uno, qué hacer cuando falla y las operaciones que hay sobre ellos.

Las seis etapas

La web y fundaia deploy dibujan el mismo pipeline, calculado en el servidor:

EtapaQué pasa
En colaEspera su turno. Hasta dos despliegues avanzan a la vez en la máquina
Descargando el códigoSe saca el commit (o el código subido) a un árbol de trabajo propio
Construyendo la imagenSe construye con la receta. Una construcción a la vez en toda la máquina
Arrancando el contenedorSe crea con sus variables, su memoria y su puerto
Comprobando que respondeSe pregunta a la ruta de salud hasta que contesta, y se vigila que el contenedor siga vivo
En marchaLas peticiones nuevas ya van al contenedor nuevo. El anterior termina lo que tenía a medias y después se apaga

Un despliegue que reutiliza una imagen (una vuelta atrás, una imagen de contenedor, un componente) se salta las dos primeras y las marca como omitidas. Mientras se construye uno nuevo, el contenedor anterior sigue atendiendo las peticiones.

  → tienda api despliegue #42

  ✔ En cola 120ms
  ✔ Descargando el código 1.4s
  ▸ Construyendo la imagen …
  ○ Arrancando el contenedor
  ○ Comprobando que responde
  ○ En marcha

Comando previo al despliegue (migraciones)

Un servicio puede tener un comando previo: se ejecuta una vez con la imagen nueva, antes de que exista su contenedor, con las mismas variables, la misma red privada y los mismos volúmenes. Es el sitio de las migraciones: npx prisma migrate deploy, bun run db:migrate, python manage.py migrate… Se pone en Ajustes → Arranque, con fundaia settings <proyecto> <servicio> --pre-deploy "…" o con update_service_settings (preDeployCommand).

  • Lo que imprime sale en el registro del despliegue, bajo Arranque, con los secretos tapados.
  • Si termina con un código distinto de 0 (o pasa de quince minutos), el despliegue falla con pre_deploy_failed y la versión anterior sigue sirviendo: no hay un contenedor nuevo a medio migrar.
  • Se ejecuta con sh -c, así que a && b funciona tal cual. No se repite al volver atrás: las migraciones de esa imagen ya corrieron cuando salió por primera vez.
  • Se copia al crear otro entorno, y se exporta en el manifiesto.

El cambio de contenedor

En cuanto el contenedor nuevo pasa la comprobación de salud, toda petición nueva va a él. El anterior no se apaga en ese momento: sigue atendiendo las peticiones que ya tenía empezadas —una descarga, una respuesta en streaming, un WebSocket— hasta que terminan, y sólo entonces se para. El despliegue sale En marcha sin esperar a ese apagado, y el registro del despliegue dice al final cuánto tardó el anterior en vaciarse:

Live
Draining deployment 41 before it stops
Retired deployment 41 (drained in 4s, 0 public / 0 private open at stop)
  • Se espera a lo que llega por su dirección pública y también a lo que le piden los servicios vecinos por la red privada del proyecto.
  • Diez minutos como mucho. Una conexión que no se cierra nunca no deja el contenedor viejo encendido para siempre: a los diez minutos se apaga igualmente, y a los WebSockets que sigan abiertos se les cierra con el código 1012 (el servicio se está reiniciando) para que el cliente vuelva a conectar, ya con el contenedor nuevo.
  • Los servicios con volumen —bases de datos, buckets y cualquiera con un disco montado— no esperan a sus conexiones: dos contenedores escribiendo en el mismo volumen diez minutos es un riesgo mayor que cortar una consulta. Se apagan a los diez segundos, como siempre, y su proceso recibe la señal de parada con tiempo para cerrar ordenadamente.
  • Si la plataforma se reinicia mientras un contenedor viejo se vacía, al volver sigue donde lo dejó, con el mismo límite de diez minutos contado desde el principio.

Cuando un despliegue falla

La etapa en la que se paró casi siempre es la respuesta:

EtapaLo que suele ser
Descargando el códigoUn repositorio privado de otra persona; ver GitHub
Construyendo la imagenFalta una dependencia, o la receta detectada no es la que querías
Arrancando el contenedorEl comando de arranque, o una variable que el proceso lee al nacer
Comprobando que respondeEl puerto o la ruta de salud; o un proceso que escucha en localhost en vez de 0.0.0.0

Si el contenedor muere mientras se comprueba, el despliegue lo dice en el acto («salió con código 1») con sus últimas líneas, en vez de esperar a agotar el plazo.

Los registros completos de cada etapa están en la página del commit y en fundaia logs; ver Registros y métricas.

Operaciones

OperaciónQué haceCLI
DesplegarLee la cabeza de la rama y la despliega con las variables de hoyfundaia deploy tienda api
ReiniciarReutiliza la imagen viva y levanta un contenedor nuevofundaia deploy tienda api --restart
Desplegar sin cachéConstruye cada paso de nuevo, sin las capas guardadasfundaia deploy tienda api --no-cache
RedesplegarVuelve a construir el commit de un despliegue concreto, con las variables de hoyfundaia redeploy tienda api 41
Volver atrásPone otra vez la imagen de un despliegue anteriorfundaia rollback tienda api 41
CancelarDetiene el despliegue en curso; lo que servía sigue sirviendofundaia cancel tienda api
PararDuerme el servicio; la siguiente petición lo despiertafundaia stop tienda api

deploy se queda dibujando el pipeline hasta que acaba y sale con código distinto de cero si falla; --detach vuelve en cuanto lo arranca.

Solo hay un despliegue en curso por servicio: lanzar otro cancela el que estuviera esperando. Si la plataforma se reinicia a mitad de uno, al volver lo encola de nuevo en lugar de darlo por fallido.

Volver atrás

Una vuelta atrás no reabre el despliegue viejo: crea uno nuevo, con su propio número, que reutiliza la imagen de aquel. No reconstruye nada, así que lo que vuelve es exactamente el código de entonces, arrancado con las variables de hoy. Se guardan las dos últimas imágenes de cada servicio, así que siempre se puede volver al menos un paso. En un servicio de imagen se vuelve a la imagen exacta que corría (por su identificador), no a lo que su etiqueta señale hoy, mientras esa imagen siga en la máquina.

Volver atrás sola: el rollback automático

Si lo activas en Ajustes → Arranque (Volver atrás si una versión nueva se cae), con fundaia settings tienda api --auto-rollback true o con update_service_settings (autoRollback), Fundaia vigila los diez primeros minutos de cada versión que sale: si su contenedor se cae en ese tiempo, despliega por su cuenta una vuelta atrás a la última versión que estuvo sana, la misma operación que harías a mano.

  • Una sola vez por despliegue, y nunca en bucle: una vuelta atrás (automática o tuya) que se vuelva a caer no provoca otra. Si la versión anterior ya no tiene imagen en la máquina, no hace nada y el servicio sigue los reintentos de siempre.
  • Mientras la vuelta atrás está en marcha, los reintentos automáticos no levantan la versión que se cayó. Y si cuando se cae ya hay otro despliegue en camino —el arreglo que acabas de empujar—, no vuelve atrás: lo deja llegar.
  • Queda en el historial con el motivo — Fundaia volvió api a la versión 41 porque la 42 se cayó a los 38 s —, se anuncia en la web y en fundaia watch, y los avisos por webhook tienen su propio evento, Vuelta atrás automática (deployment-rolled-back).
  • Está apagado por defecto: una versión que se cae al arrancar por un dato o una variable no se arregla volviendo atrás, y hay servicios que prefieren quedarse caídos a servir código viejo.

Desplegar sin caché

Las construcciones reutilizan las capas de la anterior, y un commit idéntico con las mismas variables reutiliza la imagen entera. Cuando eso esconde un problema —una dependencia que cambió con el mismo lockfile, un apt-get que se quedó viejo— Desplegar sin caché construye cada paso desde cero (podman build --no-cache). Está en el desplegable junto a Desplegar, en fundaia deploy <proyecto> <servicio> --no-cache y en deploy_service con noCache: true.

  • Solo para servicios que la plataforma construye (desde GitHub o con código subido): una imagen de un registro o un componente no tiene caché que saltarse, y se rechaza con un error claro.
  • No se combina con --restart, que precisamente reutiliza la imagen.
  • El despliegue lo lleva marcado: sin caché en el historial, en fundaia history y en su registro.

Cancelar

Cancelar para un despliegue en cola, construyendo o arrancando: detiene la construcción, suelta el turno de la máquina y quita el contenedor nuevo si ya existía. Queda cancelado en el historial, en gris, con la etapa en la que se paró y quién lo canceló. --deployment <n> cancela uno concreto.

Un despliegue que ya está en marcha no se cancela: para volver a la versión anterior está Volver atrás.

Todos los despliegues, en una pantalla

Despliegues, en la barra lateral (o g d en el teclado), junta los de todos los proyectos que ves: arriba lo que está en cola, construyendo o arrancando; debajo lo que terminó en las últimas 24 horas, bien, mal o cancelado. Cada fila dice el proyecto, el servicio y el entorno, el motivo (un commit, a mano, una vuelta atrás…), quién lo lanzó, el commit, las seis etapas en una barra y cuánto lleva o cuánto tardó. Se actualiza sola con cada cambio, sin recargar.

  • En curso, Fallidos y Todo filtran la lista; Fallidos incluye un despliegue que salió bien y cuyo contenedor cayó después.
  • Cancelar detiene uno en curso desde la misma fila; lo que servía antes sigue sirviendo.
  • Pulsar el servicio abre su pestaña de despliegues, en su entorno.
fundaia deployments            # en curso y últimas 24 horas, de todos tus proyectos
fundaia deployments --active   # solo lo que se está desplegando ahora
fundaia deployments --failed   # solo lo que falló o se cayó

Para un agente es list_recent_deployments (scope: active, recent, failed o all), y por HTTP, GET /api/infra/deployments?scope=active&limit=50. Nadie ve los despliegues de un proyecto al que no llega.

Varios servicios a la vez

Desplegar, reiniciar, dormir o despertar todos los servicios de un entorno, o los que elijas, en una sola orden:

  • En la web, el menú Acciones de la barra del proyecto: Desplegar todo, Reiniciar todo, Dormir todo, Despertar todo, con una confirmación que dice cuántos servicios toca. Para unos pocos, Mayús + clic en el lienzo los va eligiendo y aparece una barra con las mismas acciones; Esc o un clic en el fondo la quita.
  • fundaia bulk deploy tienda (todos), fundaia bulk sleep tienda web worker (esos), con --env para otro entorno.
  • bulk_action por MCP, o POST /api/infra/projects/:id/bulk con { "action": "deploy", "services": ["web"], "environment": "staging" }.

Se despliega y se despierta primero lo que otros usan (la base de datos antes que la API que la lee) y se duerme al revés. Cada servicio pasa por las mismas comprobaciones que un despliegue suelto, y el que no puede —sin suscripción, ya dormido, sin código todavía— vuelve con su motivo sin parar a los demás. Un nombre que no existe, en cambio, para la orden entera antes de tocar nada. Cada servicio deja su propia fila en el historial, como si lo hubieras hecho a mano.

Deploy hooks: desplegar desde fuera

Un deploy hook es una URL secreta: un POST a ella despliega el servicio, sin cuenta ni token. Es lo que se pega en un job de CI, en el webhook de publicación de un CMS o en un cron de otra máquina.

fundaia hooks add tienda web "GitHub Actions"   # imprime la URL, una sola vez
curl -X POST https://infrastructure.fundaia.com/api/infra/hooks/fdh_…
fundaia hooks list tienda web                   # nombre, pista del token y última llamada
fundaia hooks rm tienda web "GitHub Actions"    # su URL deja de funcionar

En la web están en Ajustes → Deploy hooks, con botón de copiar y el curl de ejemplo.

  • La URL es la credencial: se enseña una sola vez al crearla (en la web, fundaia hooks add o la respuesta 201 de la API) y se guarda solo su huella. Si se filtra, revócala y crea otra. Por MCP se pueden listar y revocar, pero no crear: una herramienta nunca enseña un secreto.
  • Responde 202 con el despliegue que empezó. Si llamas varias veces mientras uno de ese hook sigue en cola, se reutiliza ese en vez de encolar otro; si ya se está construyendo, el nuevo lo sustituye, como un push.
  • Una URL desconocida o revocada responde un 404 idéntico, sin pistas de cuál de las dos era.
  • Pasa por las mismas comprobaciones que un despliegue a mano (suscripción, almacenamiento), y en el historial aparece como Fundaia desplegó web con el deploy hook GitHub Actions.

El historial y la página de un commit

La pestaña Despliegues de un servicio es su lista de commits, agrupada por día. Cada fila lleva una marca —verde el que sirve ahora, violeta el que se construye, roja el que falló, un reloj el que espera aprobación— y las comprobaciones de sus workflows (✓ 5 / 8).

Pulsar una fila abre la página del commit, que reúne todo lo suyo:

  • El veredicto y la única acción que le toca: cancelar, reintentar, volver a esta versión, aprobar o descartar.
  • Despliegue: las seis etapas y lo que imprimió cada una, abierto en la que falló. Si el commit se desplegó varias veces, cada intento con sus propios pasos.
  • Cambios: los ficheros y sus diffs, leídos de GitHub. Un fichero binario no tiene diff, y de un commit con más de 300 ficheros GitHub solo enumera los 300 primeros.
  • Incidencias, si las hubo: los errores que escribió el contenedor mientras servía ese commit; ver Incidencias.
fundaia history tienda api                   # los despliegues, del más nuevo al más viejo
fundaia history tienda api --commit c229d52  # solo los de ese commit
fundaia commit tienda api                    # los cambios de lo último desplegado
fundaia commit tienda api c229d52 --stat     # solo la lista de ficheros

La dirección de la página lleva el commit (/p/…/s/…/commits/<sha>), y es también a la que apunta el check que la plataforma deja junto al commit en GitHub.

Congelar despliegues

Un viernes por la tarde, un Black Friday o una migración delicada: congelar deja el proyecto, o un solo entorno, quieto. Se congela desde ahora (hasta una fecha, durante un rato o hasta que alguien lo levante) o cada semana en una ventana de hora local, escrita como un horario de encendido:

fundaia freeze now tienda --reason "Black Friday" --until "2026-11-30 08:00"
fundaia freeze window tienda "V 18:00 - L 08:00" --reason "Fin de semana"
fundaia --env production freeze now tienda --reason "Migración" --until 2h --env-only
fundaia freeze status tienda          # si está congelado, hasta cuándo, la próxima ventana y lo retenido
fundaia freeze lift tienda frz_…      # la termina ya, o quita la ventana

En la web, en Editar proyecto → Entornos → Congelar despliegues; con MCP, freeze_deploys, get_freeze y lift_freeze. Mientras dura, el lienzo lo dice arriba, con lo que espera.

Lo automático se retiene y sale al terminar; lo manual se rechaza salvo que lo fuerces.

  • Se retiene: un push o una etiqueta nueva, una imagen nueva del registro (también fundaia pull), un deploy hook (responde 202 con held: true), un despliegue programado y una promoción automática. Queda uno por servicio —el último—, en el historial como Fundaia retuvo por la congelación el despliegue de web, y sale solo en cuanto nada lo congela (al llegar la hora o al levantarla), a nombre de quien lo pidió: el push construye lo último de la rama.
  • Se rechaza: desplegar o reconstruir a mano, en lote, promover y aprobar un commit externo responden 423 con el código **deploy_frozen** y el motivo. --force (CLI), force: true (MCP y API) o Hacerlo igualmente en la web lo hacen ahora, y el historial apunta se saltó la congelación para desplegar web con tu nombre.
  • Nunca se congela: volver atrás (es la salida de una mala versión), reiniciar con la misma imagen, el cambio de variables y la recuperación de un servicio caído.

Las ventanas se leen en la zona que digas (--timezone, Europe/Madrid si no) y siguen el cambio de hora; varias se separan con ;, y L-V 22:00-06:00 vale igual que en los horarios.

Acciones programadas

Reiniciar, desplegar, dormir o despertar un servicio más tarde: una vez (--at "2026-10-20 22:00", o --at 2h) o repitiéndose con un cron en UTC, como mucho cada quince minutos. No son las tareas programadas, que ejecutan un comando dentro del contenedor: estas pasan por el mismo camino que hacerlo a mano —las comprobaciones de la suscripción, el historial (Fundaia desplegó web por una acción programada) y los avisos—.

fundaia schedule add tienda web restart --cron "0 4 * * *"
fundaia schedule add tienda web deploy --at "2026-10-20 22:00"
fundaia schedule add tienda web sleep --cron "0 21 * * 1-5"
fundaia schedule list tienda web      # cuándo va la próxima y cómo fue la última
fundaia schedule rm tienda web sac_…

En la web están en la pestaña Tareas del servicio; con MCP, schedule_action, list_scheduled_actions y remove_scheduled_action.

  • Un despliegue programado en un entorno congelado se retiene hasta que termine; reiniciar, dormir y despertar no se congelan.
  • Si la plataforma estaba parada a la hora, la acción se apunta como perdida en vez de hacerse tarde; una de una vez no se repite.
  • En un entorno protegido, programarla pide su nombre, porque es un despliegue diferido.