Despliegues

La llamada regresa antes de que su software esté en la máquina.

Diez puertas de entrada despliegan una versión: deploy_spa, deploy_embed, deploy_pwa, deploy_mpa, deploy_api, deploy_cron, deploy_emitter, deploy_preview, deploy_user_group y deploy_mini_app. Cada una fija exactamente un campo, req.data.deploy_type, y entrega la solicitud a deploy_app. deploy_app no está declarada en cpi_methods, así que no existe una llamada genérica de despliegue: el tipo lo elige el nombre que usted llamó, no un argumento que haya pasado. Lo primero que hace esa función no es aprovisionar. Clona un objeto base, fija app_type con el tipo de despliegue, pone is_deployment en true, adjunta el documento de versión completo como app_release_doc y guarda el resultado en xuda_master, todo antes de pedir el segundo droplet. El nombre público se calcula a partir del id de ese documento en lugar de registrarse: app_access_url es el id seguido de .xuda.app, y en ninguna parte de la ruta de despliegue se hace una llamada a la API de DNS. Un worker de Cloudflare enruta todo lo que está bajo xuda.app hacia una región, y esa región hace de proxy inverso hacia la máquina. Después el trabajo se divide en dos. config.json declara 12 pasos de trabajo para un despliegue de tipo enlace, y los 12 cubren la fase de creación. Cuando el droplet arranca por primera vez y hace curl de vuelta al webhook, el mismo trabajo se reabre con una lista distinta y más larga: 24 nombres leídos de _INSTALL_STEPS, desde connecting to server hasta activating the server. El puente entre las dos fases es una clave de memcached, install_job_ más el id de la app, escrita cuando se crea el droplet con un TTL de 3600 segundos. Si ha expirado para cuando ocurre el primer arranque, la instalación se ejecuta igual, solo que sin barra de progreso.

Diez puertas de entrada, un solo deploy_app
12 pasos de creación, luego 24 pasos de instalación
Un documento antes de ser una máquina
La llamada regresa antes de que su software esté en la máquina.
Compartido o dedicado

Compartido frente a dedicado es una cadena de conexión, y decide las otras tres filas.

La diferencia entre un proyecto en el studio y un despliegue no es una opción de configuración, es a qué CouchDB resuelve la cadena de conexión en common/xuda_node_common.mjs. Un proyecto de studio resuelve a la base de datos de proyectos compartidos de la región. Un despliegue resuelve a su propio datacenter, https en 6984 públicamente o http en 5984 por la dirección privada, usando la contraseña de administrador generada de ese datacenter, y el nombre de su base de datos se calcula, no se elige: db_ más el id del datacenter. Lea las cuatro columnas de abajo en vertical y no en horizontal. Lo que declara la puerta de entrada es lo que usted puede controlar: deploy_spa acepta app_datacenter o create_datacenter, deploy_mini_app no acepta ninguno, y deploy_vps acepta app_name, app_region y app_server_type sin ningún release_doc_id.

Proyecto de studio
Mini app
Despliegue de enlace
VPS
Dónde residen los datosEl CouchDB de proyectos compartidos de la región, resuelto por la cadena de conexión.db_ más el id del datacenter, la misma regla que cualquier otro despliegue.db_ más el id del datacenter, en el CouchDB propio de ese datacenter. Todos los despliegues asociados a él leen y escriben en la misma base de datos.Nada de esto se ejecuta. deploy_vps escribe su propio documento de app con app_type vps y nunca llama a deploy_app.
Máquinas que crea esta llamadaNinguna. Es un proyecto, no un despliegue.Un droplet de despliegue. deploy_mini_app no declara ningún campo de datacenter, así que no puede crear uno.Hasta dos: el droplet del datacenter a partir de datacenter_image_id, y luego el droplet de despliegue a partir de deployment_image_id. Pase data.app_datacenter y se omite el primero.Una VM. No hay campo release_doc_id en la llamada, así que no se le adjunta ninguna compilación.
Firewall que crea la rutaNo hay nada a lo que asociarlo.Ninguno. mini_app comparte un caso del switch con vps y webserver que termina sin crear un firewall.Una regla de entrada: tcp 443 desde 0.0.0.0/0 y ::/0. La salida por icmp, tcp y udp está abierta. El firewall del datacenter abre el 5984 solo a droplets etiquetados con datacenter_for_ más el proyecto.Ninguno, deliberadamente. En la ruta del farm, proxmox_apply_firewall retorna antes con vps: customer-managed firewall.
Mínimo mensualNada en la línea de infraestructura.24 dólares, service_hosting_basic. min_plan free es la restricción de plan, no la factura.97 dólares la primera vez: 24 por el servidor de despliegue más 73 por optimized_hosting_2, además de la membresía Pro de 49 dólares. user_group suma 35, emitter 75, pwa y preview 15.Lo que cueste el slug. deploy_vps no declara min_plan.
12

Pasos de trabajo declarados, y todos ellos son la fase de creación

24

Pasos de instalación con los que el mismo trabajo se reabre en el primer arranque

2

Servidores que levanta un primer despliegue, datacenter y después app

97 US$

Primer despliegue legal más barato al mes, antes de la membresía

La máquina

Un directorio, llenado enteramente desde fuera.

La instalación son ssh y scp ejecutados desde la región de la plataforma contra root en la dirección de la máquina. copy_source_path apunta a builds/ más el proyecto más el id de compilación, y los archivos se envían a /var/xuda. No hay registro de imágenes, ni subida de artefactos, ni descarga iniciada por la máquina: es una máquina en la que se escribe. Cada fila de abajo tiene dos caras a propósito, lo que la instalación copia y lo que después lo sirve o lo lee, porque en varios casos no son lo mismo en absoluto.

Dos cosas que este dibujo no promete. La instantánea de la compilación no es hermética: varias de esas copias se leen como scp desde la carpeta de compilación o, en su defecto, scp desde la copia viva de la plataforma, de modo que una máquina puede ensamblarse en parte con lo que la región de la plataforma tenga en el momento de la instalación y no enteramente con la compilación congelada. Y cada ssh y scp de la ruta se ejecuta con StrictHostKeyChecking=no y UserKnownHostsFile=/dev/null, porque las direcciones de los invitados del farm se reciclan desde un pool y una clave de host fijada rompería la siguiente VM que reciba esa dirección.
La compilación

Una compilación escribe cuatro cosas, y ninguna de ellas es un archivo comprimido.

Nada en una compilación de Xuda produce un tarball que usted pueda llevarse a otro sitio. build_app ejecuta el verificador de programas, incrementa un entero, escribe documentos en la base de datos del proyecto y deja una carpeta en el drive de la plataforma. Esa carpeta es lo que después lee la instalación por scp: una compilación es un área de preparación en la plataforma, no un artefacto que se le entrega. El verificador que hay delante es orientativo: build_app deja ignore_errors en true por defecto, así que el recuento de errores acaba en el documento de información de la compilación y la publicación continúa igualmente.

  • La versión es un entero, no un hash ni un semver. app_publish_info.app_lastBuild se incrementa en uno en la línea 327 de build_module, y ese número es el build_id que llevan todos los documentos y todas las rutas aguas abajo. El campo version que hay al lado es lo que haya pasado quien llama, 0 por defecto, así que no lleva ningún significado asignado por la plataforma.
  • El proyecto se escribe como documentos: un documento deployed_app por cada documento de studio en la base de datos del proyecto, cada uno con su build_id, más un documento de versión con stat 3. El id de ese documento de versión es lo que nombra data.release_doc_id en una llamada de despliegue, y por eso un despliegue apunta a una fila congelada y no a lo más reciente que haya.
  • La carpeta es builds/<project>/<build>/ en el drive de la plataforma: una copia del drive del studio como studio_assets, más deployment/, common/*.mjs, runtime/xuda-sw.js, dist/runtime, dist/images/devices y dos salidas de Nuxt precompiladas. La invalidación de caché ocurre aquí y no en el momento de servir, y consiste en un renombrado: cada archivo bajo dist/runtime/js lleva .<build_id> antes de su extensión.
  • Lo que una compilación no hace es desplegar. build_app pone update_required en true en cada despliegue activo del proyecto y envía una notificación new_version_available, y ahí se detiene. Compilar no toca ninguna máquina: cada despliegue se actualiza con su propia llamada a update_app_version. La instantánea tampoco es hermética, ya que varias copias de la instalación se leen como scp <build folder> || scp <platform live copy>.
Una compilación, cuatro escrituras
app_lastBuild
+1
incrementado, nunca con hash
Documentos deployed_app
1 por documento de studio
cada uno marcado con build_id
Documento de versión
1, stat 3
su id es su data.release_doc_id
Carpeta en el drive
1
builds/<project>/<build>/, leída después por scp
La ejecución

Una llamada, dos máquinas y cuatro formas de detenerse.

Diez puertas de entrada, una función. deploy_spa, deploy_pwa, deploy_api y siete hermanas fijan cada una req.data.deploy_type en la solicitud y la entregan a deploy_app, que no está declarada en cpi_methods, así que no existe una llamada genérica de despliegue: el tipo lo decide el nombre que usted llama. La ejecución es siempre la misma: rechaza a partir de documentos antes de gastar dinero, crea como mucho dos droplets y entrega el segundo a una fase de instalación que el trabajo de despliegue ya ha dejado de describir.

El trabajo

El trabajo que usted inició declara 12 pasos. La máquina responde con 24 más.

config.json declara job_steps por método, y para un despliegue de enlace esa lista son 12 nombres con un job_timeout de 1800000 ms. Cubre solo la fase de creación: dos servidores, dos firewalls, dos planes de copia de seguridad. La instalación es una segunda fase, posterior, en la máquina, cuando el droplet arranca por primera vez y hace curl de vuelta al webhook. En ese momento el mismo trabajo se reabre contra una lista distinta, los 24 nombres de _INSTALL_STEPS en deploy_module. Ambas se imprimen aquí completas.

config.json cpi_methods.deploy_spa.job_steps -> deploy_module _INSTALL_STEPS
declarados en el momento de la llamada, 12 pasos, job_timeout 1800000
01 initiating process
02 creating datacenter server
03 setting datacenter firewall
04 setting datacenter backup plan
05 connecting to datacenter server
06 installing datacenter resources
07 creating spa server
08 setting spa firewall
09 setting spa backup plan
10 connecting to spa server
11 installing spa resources
12 activating the server
el droplet arranca, hace curl al webhook, se vuelve a leer install_job_<app_id>
el mismo trabajo se reabre contra 24 pasos
01 connecting to server
02 initiating directories
03 installing common resources
04 installing build data
05 copying studio drive
06 copying deployment resources
07 installing webserver resources
08 installing modules
09 installing dependencies
10 installing npm packages
11 installing plugins
12 installing plugins setup
13 installing preview resources
14 installing user group resources
15 copying pwa resources
16 creating ecosystem config file
17 creating ini files
18 creating admin ini files
19 creating nginx files
20 creating websocket service
21 creating self signed certificate
22 starting services
23 installing load balancer
24 activating the server
ambas listas terminan con las mismas tres palabras. Solo en la segunda es la máquina quien las dice.
Una sola clave de memcached une las dos listas: install_job_<app_id>, escrita cuando se crea el droplet con un TTL de 3600 segundos. Si ha expirado para cuando ocurre el primer arranque, la instalación se ejecuta igual, sin ninguna barra de progreso delante.
Cómo hacerlo

Tres movimientos, y el archivo del que sale cada uno.

El despliegue de una versión no es un comando con banderas. Es el nombre de un método, el id de un documento y un trabajo que cambia de forma mientras usted lo observa.

  1. 01

    Elija la puerta de entrada, nombre la versión

    No existe una llamada genérica de despliegue. Usted llama a deploy_spa, deploy_pwa, deploy_api o alguno de los otros siete nombres, y esa elección es el deploy_type: cada uno fija req.data.deploy_type y lo entrega a deploy_app, que cpi_methods no declara. data.release_doc_id es obligatorio: es el id del documento de versión que su última compilación escribió con stat 3. cpi/deploy_module/index.mjs líneas 418 a 443.

  2. 02

    Observe cómo el trabajo cambia de lista a mitad de la ejecución

    El trabajo informa de los 12 pasos de la fase de creación que declara config.json. Cuando el droplet arranca por primera vez hace curl al webhook, el id del trabajo se vuelve a leer de la clave de memcached install_job_<app_id> escrita con un TTL de 3600 segundos, y el mismo trabajo se reabre contra la lista de instalación de 24 nombres. config.json cpi_methods.deploy_spa.job_steps y cpi/deploy_module/index.mjs líneas 4186 a 4241. Una instalación fallida deja la app en app_status_code 2 hasta que usted llame a reinstall_<type>_resources.

  3. 03

    Quédese con la máquina activada

    La instalación escribe /var/xuda/ecosystem.config.js y luego ejecuta pm2 delete all, pm2 start y pm2 startup. spa, embed, pwa, mpa y mini_app ejecutan un webserver en modo cluster con instances max, mientras que cron, emitter y api ejecutan cada uno un proceso en modo fork. El nombre público se calculó a partir del id del documento, nunca se registró: <_id>.xuda.app, enrutado por un worker de Cloudflare hacia una región que hace de proxy inverso hacia la máquina. cpi/deploy_module/index.mjs 6795 a 7040, cpi/router_module/index.mjs 1896 a 1992.

Límites honestos

Ocho cosas que la ruta de despliegue no hace, empezando por la que todo el mundo da por sentada.

  • No hay reversión para el despliegue de un servidor. update_app_version acepta un solo campo, app_id, y resuelve build_id_current a partir de app_publish_info.app_lastBuild, que siempre es la compilación más reciente que existe. Solo los sitios web estáticos pueden retroceder, mediante set_site_live_version. Para un despliegue, volver atrás significa volver a compilar hacia adelante.
  • Una compilación no despliega. build_app pone update_required en true en cada despliegue activo del proyecto y envía una notificación new_version_available, y ahí se detiene. La compilación en sí no envía nada a ninguna máquina. Cada despliegue se actualiza con su propia llamada a update_app_version, de una en una, y un proyecto con seis despliegues activos necesita seis de ellas.
  • La instantánea de la compilación no es hermética. Varias copias de la instalación se leen como scp desde la carpeta de compilación o, si falla, scp desde la copia viva de la plataforma, de modo que un despliegue puede ensamblarse en parte con lo que la región de la plataforma tenga en el momento de la instalación y no enteramente con la compilación congelada.
  • El primer despliegue legal más barato son 97 USD al mes de infraestructura: service_hosting_basic a 24 USD, que son 1 vCPU, 2 GB y 50 GB de disco, para el servidor de despliegue, más optimized_hosting_2 a 73 USD para el datacenter, además de la membresía Pro de 49 USD. min_plan free tampoco significa hosting gratuito. deploy_mini_app sigue requiriendo un slug service_hosting_, el más barato a 24 USD, y no declara ningún campo de datacenter, así que con solo sus campos declarados funciona en el proyecto de cuenta y devuelve el código -2 en cualquier otro sitio.
  • Nueve métodos declaran data.create_datacenter.app_region y app_server_type pero no app_name, que deploy_app exige cuando crea un datacenter en línea. Envíe exactamente los campos declarados y la llamada devuelve el código -5, app_name está vacío. Solo deploy_datacenter declara ese campo.
  • deploy_load_balancer requiere el farm, y sin embargo _render_haproxy_config solo agrupa backends que no estén aprovisionados por Proxmox ni en una dirección 10., 172.16-31. o 192.168. Un conjunto de backends íntegramente del farm produce un solo comentario: no reachable backends yet.
  • Una instalación fallida deja la app en app_status_code 2. install_hosting_resources devuelve el código -1, el webhook marca el trabajo como fallido pero nunca el documento de la app, y nada reintenta más allá de cuatro intentos ssh transitorios. La solución es una llamada manual de reinstalación para ese tipo de despliegue.
  • El certificado de cada máquina es autofirmado: openssl req -x509 durante 99999 días, RSA 2048, con nombre común el id de la app bajo xuda.app. Cada ssh y scp del despliegue se ejecuta con StrictHostKeyChecking=no y UserKnownHostsFile=/dev/null, porque las IP de los invitados del farm se reciclan desde un pool.
Antes de desplegar

Las preguntas que el asistente no responde

Seis cosas extraídas de deploy_module, build_module y config.json, respondidas contra el código publicado y no contra la intención.

Ver

La misma ruta, con botones.

Si prefiere ver el panel antes que leer los nombres de los campos, aquí es donde se eligen el tipo de despliegue, el tipo de servidor y los pasos del trabajo.

Un despliegue es un documento, luego un droplet, luego un scp.

deploy_app escribe el documento en xuda_master antes de pedir una máquina, calcula el nombre público a partir del id de ese documento, deriva el nombre de la base de datos del datacenter, y después empuja la carpeta de compilación desde la región de la plataforma hacia /var/xuda por ssh y la arranca bajo pm2. Nada en esa ruta es un registro, un envío de imágenes ni una descarga desde la máquina. Cuál de los diez tipos de despliegue quiere es una pregunta distinta de cómo funciona cada uno de ellos, y se responde en la página de escenarios. Cuando conozca la forma, inicie uno desde el panel.