Déploiements

L'appel revient avant meme que votre logiciel ne soit sur la machine.

Dix portes d'entrée deploient une version : deploy_spa, deploy_embed, deploy_pwa, deploy_mpa, deploy_api, deploy_cron, deploy_emitter, deploy_preview, deploy_user_group et deploy_mini_app. Chacune définit exactement un champ, req.data.deploy_type, et transmet la requête a deploy_app. deploy_app n'est pas declaree dans cpi_methods : il n'existe donc aucun appel de déploiement générique a faire, le type est choisi par le nom que vous avez appele, pas par un argument que vous auriez passe. La première chose que fait cette fonction n'est pas le provisionnement. Elle clone un objet de base, définit app_type sur le type de déploiement, met is_deployment a true, attaché le document de release complet en tant qu'app_release_doc et enregistre le resultat dans xuda_master, tout cela avant meme qu'un deuxieme droplet ne soit demande. Le nom public est calcule a partir de cet identifiant de document plutot qu'enregistre : app_access_url est l'identifiant suivi de .xuda.app, et aucun appel a une API DNS n'a lieu a aucun moment du chemin de déploiement. Un worker Cloudflare route tout ce qui se trouve sous xuda.app vers une région, et cette région fait un reverse proxy vers la machine. Le travail se divise alors en deux. config.json declare 12 étapes de job pour un déploiement lié, et ces 12 étapes couvrent uniquement la phase de création. Quand le droplet demarre pour la première fois et rappelle le webhook, le meme job est rouvert avec une liste différente et plus longue : 24 noms lus depuis _INSTALL_STEPS, de la connexion au serveur jusqu'a l'activation du serveur. Le pont entre les deux phases est une clé memcached, install_job_ suivie de l'identifiant de l'app, écrite a la création du droplet avec un TTL de 3600 secondes. Si elle a expiré au premier demarrage, l'installation s'exécute quand meme, simplement sans barre de progression.

Dix portes d'entrée, un seul deploy_app
12 étapes de création, puis 24 étapes d'installation
Un document avant d'etre une machine
L'appel revient avant meme que votre logiciel ne soit sur la machine.
Partage ou dedie

Partage contre dedie n'est qu'une chaîne de connexion, et elle décide des trois autres lignes.

La différence entre un projet en studio et un déploiement n'est pas un paramètre, c'est la base CouchDB vers laquelle résout la chaîne de connexion dans common/xuda_node_common.mjs. Un projet en studio résout vers la base des projets partagée de la région. Un déploiement résout vers son propre datacenter, en https sur le port 6984 publiquement ou en http sur le port 5984 via l'adresse privee, avec le mot de passe admin généré de ce datacenter, et le nom de sa base de données est calcule, pas choisi : db_ suivi de l'identifiant du datacenter. Lisez les quatre colonnes ci-dessous verticalement plutot qu'horizontalement. Ce que la porte d'entrée declare est ce que vous pouvez contrôler : deploy_spa accepte app_datacenter ou create_datacenter, deploy_mini_app n'accepte ni l'un ni l'autre, et deploy_vps accepte app_name, app_region et app_server_type sans aucun release_doc_id.

Projet studio
Mini app
Deploiement lié
VPS
Ou se trouvent les donnéesLa base CouchDB des projets partagée de la région, résolue par la chaîne de connexion.db_ suivi de l'identifiant du datacenter, la meme règle que pour tout autre déploiement.db_ suivi de l'identifiant du datacenter, sur le CouchDB propre a ce datacenter. Chaque déploiement qui y est rattache lit et écrit dans cette meme base.Rien de tout cela ne s'exécute. deploy_vps écrit son propre document d'app avec app_type vps et n'appelle jamais deploy_app.
Machines créées par cet appelAucune. C'est un projet, pas un déploiement.Un droplet de déploiement. deploy_mini_app ne declare aucun champ de datacenter, il ne peut donc pas en créer un.Jusqu'a deux : le droplet du datacenter depuis datacenter_image_id, puis le droplet de déploiement depuis deployment_image_id. En passant data.app_datacenter, le premier est saute.Une VM. Il n'existe aucun champ release_doc_id sur cet appel, donc aucun build ne lui est rattache.
Pare-feu créé par ce cheminRien a quoi en attacher un.Aucun. mini_app partage un switch case avec vps et webserver, qui echoue sans créer de pare-feu.Une règle entrante : tcp 443 depuis 0.0.0.0/0 et ::/0. Le trafic sortant icmp, tcp et udp est ouvert. Le pare-feu du datacenter n'ouvre le port 5984 qu'aux droplets tagues datacenter_for_ suivi du projet.Aucun, deliberement. Sur le chemin farm, proxmox_apply_firewall se termine tot avec vps : pare-feu géré par le client.
Plancher mensuelRien sur la ligne infrastructure.24 dollars, service_hosting_basic. min_plan free n'est qu'un verrou de plan, pas la facture.97 dollars la première fois : 24 pour le serveur de déploiement plus 73 pour optimized_hosting_2, en plus des 49 dollars de l'abonnement Pro. user_group ajoute 35, emitter 75, pwa et preview 15.Ce que coute le slug choisi. deploy_vps ne declare aucun min_plan.
12

Etapes de job declarees, toutes dans la phase de création

24

Etapes d'installation avec lesquelles le meme job rouvre au premier demarrage

2

Serveurs mis en place par un premier déploiement, datacenter puis app

97 $US

Premier déploiement légal le moins cher par mois, hors abonnement

La machine

Un seul repertoire, rempli entièrement depuis l'exterieur.

L'installation, c'est du ssh et du scp qui s'exécutent depuis la région de la plateforme vers root a l'adresse de la machine. copy_source_path pointe vers builds/ suivi du projet et de l'identifiant de build, et les fichiers sont pousses dans /var/xuda. Il n'y a ni registre d'images, ni upload d'artefact, ni pull initie par la machine : c'est une machine a laquelle on écrit. Chaque ligne ci-dessous a volontairement deux faces, ce que l'installation copie et ce qui le sert ou le lit ensuite, car plusieurs d'entre elles ne sont pas du tout la meme chose.

Deux choses que ce schema ne promet pas. Le snapshot du build n'est pas hermetique : plusieurs de ces copies se lisent comme scp depuis le dossier de build, ou sinon scp depuis la copie live de la plateforme, si bien qu'une machine peut etre assemblee en partie a partir de ce que la région de la plateforme détient au moment de l'installation plutot qu'entièrement a partir du build figé. Et chaque ssh et scp du chemin s'exécute avec StrictHostKeyChecking=no et UserKnownHostsFile=/dev/null, car les adresses des invités de la farm sont recyclees depuis un pool et une clé d'hôte fixe casserait la prochaine VM a recevoir cette adresse.
Le build

Un build écrit quatre choses, et aucune n'est une archive.

Rien dans un build Xuda ne produit une archive que vous pourriez emporter ailleurs. build_app exécute le vérificateur du programme, incrémenté un entier, écrit des documents dans la base de données du projet, et dépose un dossier sur le drive de la plateforme. Ce dossier est ce que l'installation lira plus tard via scp : un build est une zone de transit sur la plateforme, pas un artefact qui vous est remis. Le vérificateur qui le précède n'est qu'indicatif : build_app place ignore_errors a true par defaut, si bien que le nombre d'erreurs atterrit dans le document d'informations de build et la release se poursuit quand meme.

  • La version est un entier, ni un hash ni un semver. app_publish_info.app_lastBuild est incrémenté de un a la ligne 327 de build_module, et ce nombre est le build_id que porte chaque document et chaque chemin en aval. Le champ version a cote de lui est ce que l'appelant a passe, 0 par defaut, il ne porte donc aucune signification assignee par la plateforme.
  • Le projet est écrit sous forme de documents : un document deployed_app par document studio dans la base du projet, chacun portant build_id, plus un document de release avec stat 3. L'identifiant de ce document de release est ce que data.release_doc_id designe lors d'un appel de déploiement, c'est pourquoi un déploiement pointe vers une ligne figée plutot que vers la plus récente.
  • Le dossier est builds/<project>/<build>/ sur le drive de la plateforme : une copie du drive studio nommée studio_assets, plus deployment/, common/*.mjs, runtime/xuda-sw.js, dist/runtime, dist/images/devices et deux sorties Nuxt precompilees. Le cache busting a lieu ici plutot qu'au moment de servir, et c'est un renommage : chaque fichier sous dist/runtime/js porte .<build_id> avant son extension.
  • Ce qu'un build ne fait pas, c'est déployer. build_app place update_required a true sur chaque déploiement en direct du projet et envoie une notification new_version_available, puis s'arrete la. Aucune machine n'est touchee par le build. Chaque déploiement est mis a jour par son propre appel update_app_version. Le snapshot n'est pas hermetique non plus, car plusieurs copies d'installation se lisent comme scp <dossier de build> || scp <copie live de la plateforme>.
Un build, quatre écritures
app_lastBuild
+1
incrémenté, jamais haché
documents deployed_app
1 par document studio
chacun estampillé avec build_id
document de release
1, stat 3
son identifiant est votre data.release_doc_id
Dossier sur le drive
1
builds/<project>/<build>/, lu plus tard via scp
L'exécution

Un appel, deux machines, et quatre façons de s'arreter.

Dix portes d'entrée, une seule fonction. deploy_spa, deploy_pwa, deploy_api et sept autres definissent chacune req.data.deploy_type sur la requête et la transmettent a deploy_app, qui n'est pas declaree dans cpi_methods : il n'existe donc aucun appel de déploiement générique, le type est décide par le nom que vous appelez. L'exécution est la meme a chaque fois : elle refuse sur des documents avant de dépenser de l'argent, créé au plus deux droplets, et confie le second a une phase d'installation que le job de déploiement a deja cesse de decrire.

Le job

Le job que vous avez lance declare 12 étapes. La machine répond avec 24 de plus.

config.json declare des job_steps par méthode, et pour un déploiement lié, cette liste compte 12 noms avec un job_timeout de 1 800 000 ms. Elle ne couvre que la phase de création : deux serveurs, deux pare-feux, deux plans de sauvegarde. L'installation est une seconde phase, plus tard, sur la machine, quand le droplet demarre pour la première fois et rappelle le webhook. A ce moment, le meme job est rouvert avec une liste différente, les 24 noms de _INSTALL_STEPS dans deploy_module. Les deux sont reproduites ici intégralement.

config.json cpi_methods.deploy_spa.job_steps -> deploy_module _INSTALL_STEPS
declaree au moment de l'appel, 12 étapes, job_timeout 1 800 000
01 demarrage du processus
02 création du serveur datacenter
03 configuration du pare-feu datacenter
04 configuration du plan de sauvegarde datacenter
05 connexion au serveur datacenter
06 installation des ressources datacenter
07 création du serveur spa
08 configuration du pare-feu spa
09 configuration du plan de sauvegarde spa
10 connexion au serveur spa
11 installation des ressources spa
12 activation du serveur
le droplet demarre, rappelle le webhook, install_job_<app_id> est relue
le meme job est rouvert avec 24 étapes
01 connexion au serveur
02 initialisation des repertoires
03 installation des ressources communes
04 installation des données de build
05 copie du drive studio
06 copie des ressources de déploiement
07 installation des ressources webserver
08 installation des modules
09 installation des dependances
10 installation des paquets npm
11 installation des plugins
12 configuration des plugins
13 installation des ressources preview
14 installation des ressources user group
15 copie des ressources pwa
16 création du fichier de configuration ecosystem
17 création des fichiers ini
18 création des fichiers ini admin
19 création des fichiers nginx
20 création du service websocket
21 création du certificat auto-signé
22 demarrage des services
23 installation du load balancer
24 activation du serveur
les deux listes se terminent sur les trois memes mots. Seule la seconde est prononcee par la machine.
Une clé memcached relie les deux listes : install_job_<app_id>, écrite a la création du droplet avec un TTL de 3600 secondes. Si elle a expiré au premier demarrage, l'installation s'exécute quand meme, simplement sans barre de progression devant elle.
Passer a l'action

Trois étapes, et le fichier d'ou vient chacune.

Un déploiement de release n'est pas une commande avec des options. C'est un nom de méthode, un identifiant de document, et un job qui change de forme sous vos yeux.

  1. 01

    Choisissez la porte d'entrée, nommez la release

    Il n'existe pas d'appel de déploiement générique. Vous appelez deploy_spa, deploy_pwa, deploy_api ou l'un des sept autres noms, et ce choix constitue le deploy_type : chacun définit req.data.deploy_type et le transmet a deploy_app, que cpi_methods ne declare pas. data.release_doc_id est obligatoire : c'est l'identifiant du document de release écrit par votre dernier build avec stat 3. cpi/deploy_module/index.mjs lignes 418 a 443.

  2. 02

    Observez le job changer de liste en cours de route

    Le job affiche les 12 étapes de la phase de création declarees par config.json. Quand le droplet demarre pour la première fois, il rappelle le webhook, l'identifiant du job est relu depuis la clé memcached install_job_<app_id> écrite avec un TTL de 3600 secondes, et le meme job rouvre avec la liste d'installation de 24 noms. config.json cpi_methods.deploy_spa.job_steps et cpi/deploy_module/index.mjs lignes 4186 a 4241. Une installation en echec laisse l'app en app_status_code 2 jusqu'a ce que vous appeliez reinstall_<type>_resources.

  3. 03

    Recuperez la machine activee

    L'installation écrit /var/xuda/ecosystem.config.js, puis exécute pm2 delete all, pm2 start et pm2 startup. spa, embed, pwa, mpa et mini_app exécutent un seul webserver en mode cluster avec instances max, tandis que cron, emitter et api exécutent chacun un processus en mode fork. Le nom public a été calcule a partir de l'identifiant du document, jamais enregistre : <_id>.xuda.app, route par un worker Cloudflare vers une région qui fait un reverse proxy vers la machine. cpi/deploy_module/index.mjs 6795 a 7040, cpi/router_module/index.mjs 1896 a 1992.

Limites honnetes

Huit choses que le chemin de déploiement ne fait pas, a commencer par celle que tout le monde suppose.

  • Il n'existe pas de rollback pour un déploiement serveur. update_app_version prend un seul champ, app_id, et résout build_id_current a partir de app_publish_info.app_lastBuild, qui est toujours le build le plus récent. Seuls les sites web statiques peuvent revenir en arriere, via set_site_live_version. Pour un déploiement, revenir en arriere signifie rebuilder en avant.
  • Un build ne déploie pas. build_app place update_required a true sur chaque déploiement en direct du projet et envoie une notification new_version_available, puis s'arrete. Rien n'est pousse vers une machine par le build lui-meme. Chaque déploiement est mis a jour par son propre appel update_app_version, un a la fois, et un projet avec six déploiements en direct en nécessite six.
  • Le snapshot du build n'est pas hermetique. Plusieurs copies d'installation se lisent comme scp depuis le dossier de build, ou en cas d'echec, scp depuis la copie live de la plateforme, si bien qu'un déploiement peut etre assemble en partie a partir de ce que la région de la plateforme détient au moment de l'installation plutot qu'entièrement a partir du build figé.
  • Le premier déploiement légal le moins cher coute 97 dollars par mois d'infrastructure : service_hosting_basic a 24 dollars, soit 1 vCPU, 2 Go et 50 Go de disque, pour le serveur de déploiement, plus optimized_hosting_2 a 73 dollars pour le datacenter, en plus des 49 dollars de l'abonnement Pro. min_plan free ne signifie pas non plus hébergement gratuit. deploy_mini_app requiert quand meme un slug service_hosting_, 24 dollars au minimum, et ne declare aucun champ de datacenter : avec uniquement ses champs declares, il fonctionne sur le projet de compte et renvoie le code -2 partout ailleurs.
  • Neuf méthodes declarent data.create_datacenter.app_region et app_server_type mais pas app_name, que deploy_app exige quand il créé un datacenter a la volee. Envoyez exactement les champs declares et l'appel revient avec le code -5, app_name est vide. Seul deploy_datacenter declare ce champ.
  • deploy_load_balancer requiert la farm, pourtant _render_haproxy_config ne regroupe que les backends qui ne sont ni provisionnes par Proxmox ni sur une adresse 10., 172.16-31. ou 192.168. Un ensemble de backends entièrement farm rend un seul commentaire : aucun backend accessible pour le moment.
  • Une installation en echec laisse l'app en app_status_code 2. install_hosting_resources renvoie le code -1, le webhook marque le job en echec mais jamais le document de l'app, et rien ne reessaie au-dela de quatre tentatives ssh transitoires. La correction est un appel manuel de reinstallation pour ce type de déploiement.
  • Le certificat sur chaque machine est auto-signé : openssl req -x509 pour 99999 jours, RSA 2048, nom commun l'identifiant de l'app sous xuda.app. Chaque ssh et scp de déploiement s'exécute avec StrictHostKeyChecking=no et UserKnownHostsFile=/dev/null, car les IP des invités de la farm sont recyclees depuis un pool.
Avant de déployer

Les questions auxquelles l'assistant ne répond pas

Six questions lues directement dans deploy_module, build_module et config.json, avec des réponses fondees sur le code livré plutot que sur l'intention.

Regarder

Le meme chemin, avec des boutons.

Si vous preferez voir le tableau de bord plutot que lire les noms de champs, c'est ici que se choisissent le type de déploiement, le type de serveur et les étapes du job.

Un déploiement, c'est un document, puis un droplet, puis un scp.

deploy_app écrit le document dans xuda_master avant de demander une machine, calcule le nom public a partir de cet identifiant de document, dérive le nom de la base de données a partir du datacenter, puis pousse le dossier de build depuis la région de la plateforme vers /var/xuda via ssh et le demarre sous pm2. Rien dans ce chemin n'est un registre, un push d'image ou un pull depuis la machine. Choisir lequel des dix types de déploiement vous convient est une question différente de leur fonctionnement a tous, et elle trouve sa réponse sur la page des scenarios. Une fois la forme connue, demarrez-en un depuis le tableau de bord.