Arquitectura
GitLab (gitlab.com o self-hosted)
▲ OAuth / API │ webhook (push)
│ ▼
Dashboard ─▶ Plano de control (cloudweb-server)
API · scheduler · CA · SQLite
▲ mTLS (los agentes llaman al servidor)
┌────────────┼───────────────┐
Nodo (cloudweb-agent) Nodo … Nodo …
WireGuard · Docker · Caddy · registro de imágenes
└──── malla WireGuard 10.77.0.0/16 ────┘
Plano de control
Un único proceso Go con la API REST (más SSE para logs), el dashboard embebido, el scheduler (mejor ajuste por carga de CPU/memoria), un reconciliador y la CA interna del clúster. El estado vive en SQLite (un archivo, con backup automático antes de migrar). Los secretos (variables de entorno, secreto OAuth, tokens de GitLab) se cifran con AES-256-GCM usando una clave maestra local.
Agentes
Cada nodo ejecuta cloudweb-agent, que vive en su propio repositorio (cloud-web-node) y se versiona y publica por separado; hablan un protocolo versionado y un agente incompatible recibe un 426 con el rango soportado. Se une con un token de un solo uso y recibe un certificado de cliente de la CA (la clave privada nunca sale del nodo). Desde ahí el agente llama al plano de control por mTLS —por eso funciona detrás de NAT—: latidos con su capacidad, órdenes pendientes, reportes de despliegue, rutas y peers de la malla. Las órdenes son persistentes: si el agente se desconecta, las recibe al volver.
Despliegues
- Un push (o el botón de redeploy) crea un despliegue
queued; el scheduler elige nodo y emite la orden. - El agente clona el commit exacto con credenciales efímeras, construye (Dockerfile o buildpacks), publica la imagen en el registro interno y arranca el contenedor.
- Se verifica la salud (respuesta HTTP); recién entonces el ingress cambia el tráfico y la instancia vieja se detiene tras un período de drenaje (blue/green).
- Si algo falla, el despliegue queda
failedy la versión anterior sigue sirviendo.
Estados: queued → building → deploying → running (o failed); el reemplazado pasa a superseded. Si un nodo cae, sus instancias se reprograman en otro nodo con la misma imagen.
Ingress
Los nodos de ingress ejecutan Caddy (contenedor Docker, o un binario con --caddy-bin). El agente genera su configuración desde la tabla de rutas del plano de control y la recarga sin cortes cuando una instancia arranca, se mueve o se detiene. Caddy obtiene los certificados TLS y redirige HTTP a HTTPS.
Registro de imágenes
registry:2 corre en el nodo del plano de control, publicado sólo en la dirección de malla y con TLS emitido por la CA del clúster. Todos los nodos configuran su Docker para confiar en esa CA, de modo que cualquier nodo puede traer una imagen (rollback y reprogramación sin recompilar).
Bases de datos gestionadas
Una base Postgres es un recurso propio (no una app): tiene dueño, estado y un nodo fijo. El agente corre un contenedor por base, endurecido y con límite de memoria, con dos volúmenes con nombre (cwdb-<id> para los datos y cwdb-<id>-backups) y una red Docker interna propia (cwdb-<id>, sin salida a internet ni al resto de redes) a la que solo se conectan el servidor y las apps vinculadas; el puerto no se publica. Las reglas de aislamiento de usuarios no se tocan: la ruta app→base es únicamente esa red.
- Anclaje: el volumen vive en el disco del nodo, así que la base no se reprograma. Si el nodo cae queda
unavailable(nunca se recrea vacía en otro). Las apps vinculadas se programan en ese nodo y tampoco se reprograman lejos de él. - Credenciales: un rol sin privilegios por base, con contraseña generada y cifrada en el plano de control (como las variables de entorno); llega al agente por mTLS y a las apps como
DATABASE_URLyPG*de solo lectura. - Backups lógicos (
pg_dump, formato custom) en el volumen de backups del mismo nodo, programados por el plano de control; restauración todo-o-nada y carga de dumps (SQL plano, gzip, custom, tar) sin tocar los datos si algo falla. - Protocolo: capacidad
managed-databasesy órdenesdb.*aditivas; ver el protocolo agente–servidor. Guía de uso: Bases de datos.
Qué no hace (todavía)
Alta disponibilidad del plano de control, multi-tenant/RBAC, alta disponibilidad y réplicas de las bases de datos (y backups fuera del nodo, acceso desde fuera del clúster y recuperación a un punto en el tiempo), autoscaling, volúmenes persistentes distribuidos y proveedores Git distintos de GitLab (existe la interfaz GitProvider para sumarlos).