Les déploiements des composants de l'application
L’application comporte plusieurs composants (application Web, serveurs / Cloud functions, utilitaires …), chacun a son processus spécifique de déploiement.
Déploiement l’application Web
L’objectif est d’obtenir une page Web, index.html
et les ressources associées, dans un folder à distribuer:
- soit sur un CDN, par exemple github pages: c’est l’option retenue et décrite ci-après.
- soit dans un serveur Web hébergé,
- soit dans le serveur SRV décrit ci-après quand il héberge les services OP+PUBSUB.
Configuration
Les paramètres de configuration sont à ajuster dans le fichier src/config.mjs
. Plusieurs déploiements peuvent avoir exactement la même configuration, typiquement celle par défaut.
Après build on obtient un folder presque prêt à distribuer:
- l’application Web doit disposer des URLs des services OP et PUBSUB.
- celles-ci, qui localisent les services correspondants sur Internet, et donc la base de données et le storage, sont données dans le fichier
public/services.json
. - un
README.md
est également à fournir.
Voir plus de détails sur ces deux fichiers dans le document L’application Web, section “Configuration de runtime”.
L’URL du serveur (pas spécialement fun) est masquée ici et l’utilisateur ne connaît que l’URL de son application donnée par son provider de l’application comme:
https://asocialapps.github.io/XX?demo
Build et test de la build:
yarn quasar build -m pwa
# OU
npm run build:pwa
# https://github.com/http-party/http-server
# Installation: npm install -g http-server
npx http-server dist/pwa -p 8080 --cors -S --cert ../asocial-srv/keys/fullchain.pem --key ../asocial-srv/keys/privkey.pem
# Plus simplement
npx http-server dist/pwa -p 8080 --cors
Le résultat est dans dist/pwa
(environ 40 fichiers pour 5Mo):
- y mettre le fichier
services.json
avec le contenu ci-dessus etREADME.md
.
L’application buildée et configurée peut être distribuée depuis dist/pwa
sur le CDN de son choix, par exemple ci-après dans github pages
.
browser-list pas à jour
Au cours du build un message apparaît souvent en raison de l’obsolescence de la browser-list.
On la met à jour par la commande:
npx update-browserslist-db@latest
Distribution par github pages
Un repository github.com
peut aussi gérer un site Web de distribution.
- créer un dépôt
github.com
pour la distribution: par exemple iciasocialapps
(https://github.com/asocialapps
). - créer un repository par distribution à effectuer: par exemple ici
XX
.
Sur le poste qui génère la distribution,
- créer un folder
asocialapps-XX
et y copier les fichiers récupérés du build (dans./dist/pwa
). - y ajouter le fichier
services.json
. - y ajouter un fichier
README.md
qui permet à n’importe qui de reconstituer l’application Web distribuée depuis les sources: - le dépôt des sources est cité ainsi que la tag qui pointe exactement la révision utilisée.
- la section
patchs
résume ce qui a été modifié dans ces sources avant build.
Effectuer un commit + publish
de XX
vers le dépôt de distribution.
La première fois il faut indiquer dans github.com
que ce repository doit être diffusé sur github.io
:
- ouvrir le repository, et sa page de
settings
. - sélectionner la section
Pages
(à gauche) et fixer les paramètres donnant la branche à distribuer (master
par défaut).
C’est tout.
Lors de la distribution d’une nouvelle version ultérieure, la configuration de Pages n’a pas à être refaite: le seul fait d’effectuer un commit + publish
suffira à régénérer le site qui sera accessible par l’URL:
https://asocialapps.github.io/XX
(C’est bien .io
pas .com
).
Tests externes depuis localhost
par ngrok
ngrok
permet de créer un tunnel entre localhost et Internet en rendant accessible un serveur HTTP (écoutant le port 8443 par exemple) s’exécutant sur le poste de développement comme s’il était accessible publiquement sur Internet.
Dans sa version gratuite, ngrok
demande une inscription et permet d’obtenir un authtoken.
Sur son compte dans ngrok
on demande aussi une URL dédiée: celle-ci est générée par ngrok
et n’est pas au choix. Par exemple:
exactly-humble-cod.ngrok-free.app
Il faut enregistrer, une fois, son token sur le poste:
ngrok config add-authtoken MONTOKEN
>> Authtoken saved to configuration file: /home/daniel/snap/ngrok/179/.config/ngrok/ngrok.yml
Le token est conservé localement, la localisation s’affiche dans le terminal.
Pour ouvrir un tunnel, il faut ouvrir un terminal et lancer:
ngrok http --domain=exactly-humble-cod.ngrok-free.app 8443
En retour il apparaît l’URL https://… d’accès.
Pour fermer le tunnel, interrompre la session en cours dans ce terminal.
Le tunnel établi par Ngrok permet d’utiliser cette URL depuis n’importe où, en particulier depuis un mobile, pour joindre le serveur s’exécutant sur le localhost
du poste de développement.
Déploiements des services OP et PUBSUB
Obfuscation des données sensibles
Certificats du serveur
Si le serveur n’est pas géré par un provider externe (Google, AWS, Azure …), il est à démarrer comme une simple application node
à qui il faut fournir les certificats https fullchain.pem
et privkey.pem
.
- ces données NE DOIVENT PAS être exposées dans
git
. Elles sont stockées dans le folder./keys
qui DOIT figurer en.gitignore
. - le build des services NE CONTIENT PAS ce folder car les certificats doivent être renouvelés assez souvent et indépendamment du build d’une nouvelle version des services.
- c’est sur le host de production directement que le folder
./keys
est installé, avec en général un script de renouvellement automatique des certificats.
Tokens divers
Ces tokens sont des autorisations d’usage d’API, des authentifications diverses. Ils sont inscrits comme des entrées majeures dans le fichier ./keys.json
. Les entrées actuelles sont:
app_keys
: les clés de cryptage des sites, le mot de passe de l’administrateur technique (en fait son PBKFD) et les clésvapid
de notification web push.service_account
: l’authentification d’un compte Google.s3_config
: l’authentification du fournisseur d’accès au storage S3.
Ce fichier NE DOIT PAS être exposé dans git, il figure dans .gitignore
(d’ailleurs dans le cas contraire github par exemple envoie des alertes).
Mais ces données doivent être intégrées dans la build des services:
- il n’est pas souhaitable que cette build les fasse apparaître en clair. L’hébergeur qui installe les services n’a pas à les voir passer explicitement dans les fichiers de build.
Le fichier ./keys.json
est obfusqué par la commande:
node src/gensecret.mjs
qui en génère le fichier ./src/secret.mjs
:
- le fichier
./keys.json
est parsé, l’objet Javascript résultant est sérialisé et crypté (par un couple clé / salt généré dans le code) et encodé en base64. - le résultat est écrit dans
./src/secret.mjs
A l’initialisation des services, l’import de ce fichier expose l’encodage en base64 généré. Ce texte est converti en binaire, décrypté et l’objet correspondant disponible dans la configuration interne.
Le fichier
./src/secret.mjs
N’EST PAS communiqué àgit
. Il est a régénérer à chaque fois quekeys.json
change (et à la première installation).
Certes la lecture des sources permet de comprendre comment l’obfuscation a été réalisée. Mais le hacking en est compliqué pour l’hébergeur des services qui doit écrire du code pour l’extraire et avoir lu le code de la build pour en saisir le procédé et les clés.
Typologie des déploiements possibles
Selon les configurations choisies, on peut effectuer des build et déployer les services OP et PUBSUB selon plusieurs options. Ci-après la liste des options documentées, et celles a priori non pertinentes avec la raison associée.
Déploiements pour un site NON géré par un provider externe
Un serveur NON géré est un serveur dont on assure soi-même la configuration et la surveillance d’exploitation. Typiquement:
- un site de production sur une ou des VMs hébergés chez un fournisseur standard.
- un serveur de test personnel pour une exploitation de démonstration ou de test, en ayant un nom de domaine spécifique.
Sur un site non géré, il faut installer:
- éventuellement un
nginx
(ou équivalent) capable d’effectuer un load balancing entre plusieurs instances de serveur HTTP assurant un service OP afin d’accroître la puissance disponible. - éventuellement une base de données,
Sqlite
(ouPostgresql
), locale, et en gérer la sécurité / backup / restore. Mais il est aussi possible d’utiliser un service d’hébergementFirestore
(ou par extension DynamoDB -Amazon-, ou CosmoDB -Microsoft Azure-) où un service d’hébergement externePostgresql
.
Les déploiements documentés sont les suivants:
- Serveur OP: serveur assurant le seul service OP.
- Serveur PUBSUB: serveur assurant le seul service PUBSUB.
- Serveur SRV: serveur assurant les deux services OP+PUBSUB.
Déploiement pour un site GAE géré
Google App Engine (GAE) est une solution pour déployer un serveur assurant les mêmes fonctionnalités qu’un site NON géré avec les remarques suivantes.
GAE est une ferme de serveurs: une ou plusieurs instances peuvent s’exécuter en parallèle, le nombre pouvant est borné à UNE instance. Au bout d’un certain temps sans réception de requête, l’instance est arrêtée et sera relancée à l’arrivée d’une nouvelle requête:
- c’est exactement le même comportement qu’un Cloud Function, si ce n’est que la durée de vie en l’absence de requête est plus long (une heure au lieu de 5 minutes pour fixer les idées).
Déployer le service OP seul sur GAE n’a pas d’intérêt a priori: plutôt utiliser un Cloud Function.
Déployer le service PUSUB seul sur GAE n’a pas d’intérêt a priori: plutôt utiliser un Cloud Function.
Déployer les deux services OP+PUBSUB sur GAE à un intérêt de simplification d’administration:
- la comparaison des coûts avec un mix de Cloud Functions n’a pas été faite.
- il faut borner le nombre d’instances à UNE, PUBSUB ne peut pas être multi-instances: en conséquence c’est une option de faible puissance.
- le mot faible est flou: le débit potentiel peut cependant être suffisant dans les cas d’usage par des organisations de taille modeste ou moyenne.
- dans les cas de faible trafic, le coût tombe en dessous du minimum facturable, l’hébergement devenant gratuit.
GAE pourrait assurer la distribution de l’application Web (et du site documentaire statique) mais ce n’est pas une bonne idée:
- ça obligerait à refaire un déploiement de l’ensemble même quand seule l’application Web a changé en provoquant une interruption certes faible de disponibilité.
- ça présente aux utilisateurs une URL d’accès (celle de l’application Web) assez abscons et où Google apparaît.
Il reste préférable d’assurer séparément la distribution de l’application par github pages
(ou autre). Ceci permet aussi de changer le déploiement des services OP et PUBSUB pour des solutions différentes meilleures en termes de coûts / performances de manière transparente pour les utilisateurs, ce qui est souhaitable.
Déploiement par des Cloud Functions (CF)
Le service OP peut être déployé par CF, sans contrainte sur le nombre d’instances en parallèle.
Le service PUBSUB peut être déployé par CF, avec contrainte d’UNE instance au plus.
Il n’est documenté ici que l’usage de Google Cloud Functions: les deux autres options chez AWS et Azure sont à tester et documenter, même si en théorie les adaptations de code à effectuer semblent marginales.
Choix de la base de données
Autogestion de la base de données
C’est possible pour les providers SQLite
et PostgreSQL
.
C’est une gestion lourde et humainement contraignante pour une organisation.
Service hébergé de la base de données
Firestore
Service géré par Google. Si le débit est faible on peut tomber sous le seuil de facturation.
En pratique ceci impose naturellement à opter pour Google Storage pour le storage des fichiers.
PostgreSQL
Il y a plusieurs offres sur le marché avec un coût d’entrée minimal d’une vingtaine d’euros mensuels: certes le débit va être important, mais c’est une solution à réserver si le coût de Firestore devient prohibitif.
DynamoDB (AWS) et CosmoDB (Azure)
Ces classes providers n’ont pas été écrites:
- sur le papier il n’y a pas de contradictions avec les contraintes à respecter pour l’interface provider.
- les autres providers ont environ 500 lignes de code: le temps à passer en compréhension / test des API, puis en création des comptes Amazon ou Azure, puis en tests, est plus important que l’effort d’écriture à proprement parlé du code.
Choix du storage
Autogestion
Réservé à un site de test avec le provider file system.
Google Storage
A choisir si les options GAE et CF chez Google sont prises.
Amazon S3
S3 est un interface, le provider a été testé avec minio
.
- S3 est bien entendu disponible chez AWS.
- d’autres fournisseurs existent sur le marché, la comparaison des coûts n’a pas été faite.
- gérer soi-même S3 avec
minio
n’est pas vraiment réaliste en production.
Le Storage de Azure serait à écrire: environ 500 lignes de code.
Fichiers de configuration
Fichier keys.json
Ce fichier contient des autorisations et tokens spécifiques de l’administrateur du site:
- il est exclu de git afin de ne pas exposer ces données au public,
- sa sécurité est gérée par l’administrateur technique par ses propres moyens.
L’outil
node src/gensecret.mjs
génère un fichier obfusquésrc/secret.mjs
.
Il comporte les constantes suivantes:
app_keys
: voir ci-après.service_account
: pour les déploiements sur Google Cloud Platform. Procédure décrite en annexe.-
s3_config
: le token d’authentification au service S3 choisi. Procédure décrite en annexe.{ "vapid_private_key": "...", "vapid_public_key": "...", "app_keys" : { "admin": ["..."], "sites": { "A": { "k": "...", "db": [true, true, true], "st": [true, true, true] }, "B": { "k": "...", "db": [false, false, false], "st": [false, false, false] } } }, "service_account" : { ... }, "s3_config" : { ... }, "alertes" : { "_url": "http://.../script.php", "_pwd": "...", "_sendgrid_api_keyX": "...", "_from": "daniel@sportes.fr" } }
vapid_private_key
et vapid_public_key
Ce couple de clés permet au service PUBSUB de pousser des notifications vers l’application Web qui DOIT avoir dans sa configuration la vapid_public_key
.
- génération par l’outil vapid:
node src/tools.mjs vapid
- la clé publique est transmise dans la configuration de / des applications ayant accès à ce serveur / services.
app_keys
admin
: donne la ou les hash des phrases secrètes de l’administrateur technique.
- lancer l’application Web (n’importe laquelle)
- ouvrir le panneau d’outils: barre du bas, icône engrenage,
- onglet Tester une phrase secrète
- saisir une phrase secrète par exemple
les framboises sont bleues cette année
, -
copier le texte qui apparaît dans
SHA256 du PBKFD de la phrase complète
.ZgHxc7BeHgR7z5HLpidsMd4XmSJmfCCulgu7cfwB9V8=
Ceci donne une clé à mettre dans les propriétés de app_keys
:
Le login s’effectuera ainsi:
Organisation: `admin`
Phrase secrète: `les framboises sont bleues cette année`
sites
: cette rubrique permet d’enregistrer la clé et les options de cryptage des sites:
- habituellement un administrateur n’est concerné que par son site, de code
A
typiquement. - toutefois s’il doit réaliser des exports de base de données pour d’autres sites, il doit disposer de la clé de cryptage du site cible, d’où dans ce cas l’existence d’un site
B
.
L’attribut k
est obtenu comme la propriété admin:
- les propriétés data des tables / documents sont toujours cryptées par cette clé.
L’attribut db
donne trois booléens indiquant si la base crypte aussi,
- [0] : le code de l’organisation préfixant les
id
et propriétéshk
; - [1] : les ids principales des documents;
- [2] : les ids secondaires des documents.
L’attribut st
donne trois booléens indiquant si le storage crypte,
- [0] : le code de l’organisation;
- [1] : les ids des avatars / groupes;
- [2] : les ids des fichiers.
service_account
Jeton d’accès au Google account Dans le cas de déploiement sur Google (GAE / Firestore / Google Cloud Storage).
s3_config
Jeton d’accès au storage d’interface S3.
alertes
Certaines alertes graves peuvent donner lieu à envoi d’un email à une adresse (typiquement celle de l’administrateur technique) afin qu’il soit notifié au plus vite de la nécessité de consulter le log du serveur.
Les propriétés sont celles d’un serveur externe d’envoi de mail mis en place par l’administrateur technique:
- le couple
_url _pwd
est relatif à un serveur Web,- dont l’url est donnée ici,
- et dont un mot de passe est donné ici.
- Voir en annexe l’API que doit implémenter un tel serveur.
- le couple
_sendgrid_api_key _from
sont deux propriétés pour solliciter le service sendGrid (Twilio). Usage expérimental en évaluation. Dans le cas d’usage d’autres services du marché, leur configuration serait données ici.
Folder keys
Ce folder contient le certificat du domaine de l’application tels que générés par Lets Encrypt
(https://letsencrypt.org/) par exemple:
fullchain.pem
privkey.pem
Ce folder,
- est exclu de git pour ne pas exposer les clés du domaine au public,
- est externe au build afin que sur le site on puisse renouveler ces clés (obsolètes régulièrement) sans refaire un déploiement.
Ce folder ne sert qu’aux déploiements serveur NON géré et est inutile en cas de déploiement GAE et CF (dont les certificats sont gérés par le fournisseur).
Fichier src/config.mjs
- Il est inclus dans git.
- Chaque déploiement a le sien.
- Il comporte,
- une partie fonctionnelle qui peut avoir une valeur commune pour tous les déploiements du site.
- une partie technique spécifique de chaque déploiement et détaillée ci-après.
Il comporte des lignes donnant les configurations des providers de DB et de Storage:
- pouvant être cités dans la section
run
, -
pouvant être cité sur les lignes de commande:
node src/tools.mjs ...
// Configuration nommées des providers db et storage s3_a: { bucket: 'asocial' }, fs_a: { rootpath: './fsstoragea' }, fs_b: { rootpath: './fsstorageb' }, gc_a: { bucket: 'asocial-test1.appspot.com' }, sqlite_a: { path: './sqlite/testa.db3' }, sqlite_b: { path: './sqlite/testb.db3' }, firestore_a: { },
Configuration des providers
Chaque nom de configuration comporte: le nom du provider
, _
, lettre d'identification
. Les noms sont:
- Base données:
sqlite
: accès à une base de données SQLite. Options:{ path: '...' }
Path du fichier.db3
de la base données.
firestore
: accès à Google Firestore. Options:{ }
- Storage:
fs
: accès à un folder du File-System local. Options:{ rootpath: '...' }
Path de la racine.
gc
: accès au Google Cloud Storage. Options:{ bucket: '...' }
identifiant du bucket réservé à cet usage.
s3
: accès à un Storage Amazon S3. Options:{ bucket: '...' }
identifiant du bucket réservé à cet usage.
La section env: {…}
Certains paramètres (typiquement ceux de _l’emulator de Google Cloud Platform) doivent figurer en variables d’environnement. On les déclare dans la section env. Cas identifiés:
STORAGE_EMULATOR_HOST
: pour EMULATOR de Google Storage-
FIRESTORE_EMULATOR_HOST
: pour EMULATOR de Google Firestoreenv: { STORAGE_EMULATOR_HOST: 'http://127.0.0.1:9199', // 'http://' est REQUIS FIRESTORE_EMULATOR_HOST: 'localhost:8085' // Remplace le port par défaut 8080 }
Toutes les entrées de cette section seront converties en variable d’environnement.
Déploiements Serveur
Les déploiements possibles sont:
- déploiement d’un service OP.
- déploiement d’un service PUBSUB.
- déploiement SRV, incluant OP et PUBSUB.
Chaque déploiement demande:
- d’ajuster la configuration pour chaque cas à déployer,
- d’effectuer un build,
- de distribuer le résultat du build sur le site de production.
Déploiements Serveur d’un service OP (sans PUBSUB)
Fichier src/keys.json
- les clés
vapid...
sont inutiles (mais ne nuisent pas).
service_account
- uniquement si le provider de base de données est Firestore.
s3_config
- uniquement si le provider de Storage est S3.
alertes
- uniquement si les alertes graves sont poussées sur le mail de l’administrateur technique.
Folder keys
Le certificat du domaine est requis pour les serveurs NON gérés.
Fichier src/config.mjs
export const config = {
// Paramètres fonctionnels
allocComptable: [8, 2, 8],
allocPrimitive: [256, 256, 256],
heuregc: [3, 30], // Heure du jour des tâches GC
retrytache: 60, // Nombre de minutes avant le retry d'une tâche
// Configuration du déploiement
env: { },
fs_a: { rootpath: './fsstoragea' },
gc_a: { bucket: 'asocial-test1.appspot.com' */ },
sqlite_a: { path: './sqlite/test.db3' },
firestore_a: { },
pathlogs: './logs',
pathkeys: './keys',
run: {
site: 'A',
origins: new Set(['http://localhost:8080']),
nom: 'test asocial-sql', // pour le ping
pubsubURL: 'https://test.sportes.fr/pubsub/',
mode: 'https',
port: 8443,
storage_provider: 'gc_a',
db_provider: 'sqlite_a',
projectId: 'asocial-test1',
rooturl: 'http://test.sportes.fr:8443'
}
}
Commentaires
gc_a:
configuration du provider Google Cloud Storage. Par commodité on peut en décrire plusieurs (gc_a gc_b etc.)sqlite_a:
configuration du provider DB SQLite. Par Par commodité on peut en décrire plusieurs (sqlite_a sqlite_b etc.)firestore_a:
configuration du provider DB Firestore. Par Par commodité on peut en décrire plusieurs (firestore_a firestore_b etc.)run.site: 'A'
indique l’entrée deapp_keys.sites
qui détient la clé de cryptage du site.run.origins:
Set desorigin
des sites de CDN délivrant l’application Web. Si vide ou que la directive est absente, pas de contrôle sur l’origine.run.nom:
sert uniquement à l’affichage lors d’une requête ping.run.mode:
‘https’ (par exception en test ‘http’).run.port:
numéro de port d’écoute.pubsubURL
: URL où le service OP va trouver le service PUBSUB,run.storage_provider:
identifiant du provider de Storage (référencé au-dessus).run.db_provider:
identifiant du provider de DB (référencé au-dessus).run.projectId:
ID du project Google si l’un des providers storage / db est un service de Google.run.rooturl:
en général absent. URL externe d’appel du serveur qui ne sert qu’à un provider de storage qui doit utiliser le serveur pour délivrer une URL get / put file. Cas storageFS et storageGC en mode emulator.
Build par webpack
Fichier webpack.config.mjs
:
import path from 'path'
export default {
entry: './src/server.js',
target: 'node',
mode: 'production',
output: {
filename: 'op.js',
path: path.resolve('dist/op')
}
}
Le résultat du _build par webpack ira dans le folder dist/op
et son .js principal y sera op.js
Gestion de package.json
et build
En développement il y a une ligne:
"type": "module",
Pour effectuer un build il faut renommer cette directive “typeX” (ou la supprimer).
Commande dans un terminal (à la racine du projet):
npx webpack
- durée de 30s à 1 minute: être patient, rien ne s’affiche avant la fin.
Il faut renommer la directive ““typeX” en “type” sinon le développement ne marche plus.
Dans le folder dist/op
insérer un fichier package.json
ne contenant que {}
:
echo "{}" > dist/op/package.json
Si on veut exécuter immédiatement le résultat du build directement dans le folder dist/op
, node
va chercher un package.json
, y compris au niveau de folder supérieur et va trouver le package.json
du projet qui a une directive "type"module"
ce qui met l’exécution en erreur car op.js
utilise un require
.
La présence du package.json
fake permet d’éviter ce problème.
Exécution de test dans dist/op
- si le provider de storage était par exemple
sqlite_a: { path: './sqlite/testa.db3' },
vérifier qu’il y a bien une basedist/op/sqlite/testa.db3
. - si le provider de storage était par exemple
fs_a: { rootpath: './fsstoragea' },
dansconfig.mjs
, vérifier qu’il existe bien un folderdist/op/fsstorage
.
Exécution:
cd dist/op
node op.js
Attention:
op.js
est le vrai exécutable et écrit vraiment dans la vraie base et le vrai storage.
Déploiements Serveur d’un service PUBSUB (sans OP)
Fichier src/keys.mjs
app_keys
- les clés
vapid...
SONT REQUISES.
service_account
- inutile (mais ne nuit pas).
s3_config
- inutile (mais ne nuit pas).
Folder keys
Le certificat du domaine est requis.
Fichier src/config.mjs
export const config = {
// Paramètres fonctionnels inutiles mais ne nuisent pas
// Configuration du déploiement
env: { },
pathlogs: './logs',
pathkeys: './keys',
run: {
site: 'A',
nom: 'test asocial-pubsub', // pour le ping
mode: 'https',
port: 8444
}
}
Commentaires
run.site: 'A'
indique l’entrée deapp_keys.sites
qui détient la clé de cryptage du siterun.origins:
Set des origin des sites de CDN délivrant l’application Web et des sites OP. Si vide ou que la directive est absente, pas de contrôle sur l’origin.run.nom:
sert uniquement à l’affichage lors d’une requête ping.run.mode:
‘https’ (par exception en test ‘http’).run.port:
numéro de port d’écoute. Attention à ne pas donner le même numéro de port que celui du service OP si c’est un serveur sur le même host.
Build par webpack
Fichier webpack.config.mjs
:
import path from 'path'
export default {
entry: './src/pubsub.js',
target: 'node',
mode: 'production',
output: {
filename: 'pubsub.js',
path: path.resolve('dist/pubsub')
}
}
Le résultat du _build par webpack ira dans le folder dist/pubsub
et son .js principal y sera pubsub.js
Gestion de package.json
et build
En développement il y a une ligne:
"type": "module",
Pour effectuer un build il faut renommer cette directive “typeX” (ou la supprimer).
Commande dans un terminal (à la racine du projet):
npx webpack
- durée de 30s à 1 minute: être patient, rien ne s’“affiche avant la fin.
Il faut renommer la directive ““typeX” en “type” sinon le développement ne marche plus.
Dans le folder dist/pubsub
insérer un fichier package.json ne contenant que {}
:
echo "{}" > dist/pubsub/package.json
Si on veut exécuter immédiatement le résultat du build directement dans le folder dist/pusub
, node
va chercher un package.json
, y compris au niveau de folder supérieur et va trouver le package.json
du projet qui a une directive "type"module"
ce qui met l’exécution en erreur car pubsub.js
utilise un require
.
La présence du package.json
fake permet d’éviter ce problème.
Exécution de test dans dist/pubsub
Exécution:
cd dist/pubsub
node pusub.js
Attention:
pubsub.js
est le vrai exécutable et pousse de vraies notifications.
Déploiements Serveur d’un service OP+PUBSUB
Fichier src/keys.mjs
app_keys
- les clés
vapid...
sont REQUISES.
service_account
- uniquement si le provider de base de données est firestore.
s3_config
- uniquement si le provider de Storage est S3.
Folder keys
Le certificat du domaine est requis.
Fichier src/config.mjs
export const config = {
// Paramètres fonctionnels
allocComptable: [8, 2, 8],
allocPrimitive: [256, 256, 256],
heuregc: [3, 30], // Heure du jour des tâches GC
retrytache: 60, // Nombre de minutes avant le retry d'une tâche
// Configuration du déploiement
env: { },
fs_a: { rootpath: './fsstorage' },
gc_a: { bucket: 'asocial-test1.appspot.com' */ },
sqlite_a: { path: './sqlite/testa.db3' },
firestore_a: { },
pathlogs: './logs',
pathkeys: './keys',
run: {
site: 'A',
origins: new Set(['http://localhost:8080']),
nom: 'test asocial-sql', // pour le ping
pubsubURL: null,
mode: 'https',
port: 8443,
storage_provider: 'gc_a',
db_provider: 'sqlite_a',
projectId: 'asocial-test1',
rooturl: 'http://test.sportes.fr:8443'
}
}
Commentaires
gc_a:
configuration du provider Google Cloud Storage. Par commodité on peut en décrire plusieurs (gc_a gc_b etc.)sqlite_a:
configuration du provider DB SQLite. Par Par commodité on peut en décrire plusieurs (sqlite_a sqlite_b etc.)firestore_a:
configuration du provider DB Firestore. Par Par commodité on peut en décrire plusieurs (firestore_a firestore_b etc.)run.site: 'A'
indique l’entrée de app_keys.sites qui détient la clé de cryptage du siterun.origins:
Set des origin des sites de CDN délivrant l’application Web. Si vide ou que la directive est absente, pas de contrôle sur l’origin.run.nom:
sert uniquement à l’affichage lors d’une requête ping.pubsubURL
: null, le serveur assure localement ce service aussi.run.mode:
‘https’ (par exception en test ‘http’).run.port:
numéro de port d’écoute.run.storage_provider:
identifiant du provider de Storage (référencé au-dessus).run.db_provider:
identifiant du provider de DB (référencé au-dessus).run.projectId:
ID du project Google si l’un des providers storage / db est un service de Google.run.rooturl:
en général absent. URL externe d’appel du serveur qui ne sert qu’à un provider de storage qui doit utiliser le serveur pour délivrer une URL get / put file. Cas storageFS / storageGC en mode emulator.
Build par webpack
Fichier webpack.config.mjs
:
import path from 'path'
export default {
entry: './src/server.js',
target: 'node',
mode: 'production',
output: {
filename: 'srv.js',
path: path.resolve('dist/srv')
}
}
Le résultat du _build par webpack ira dans le folder dist/srv
et son .js principal y sera srv.js
Gestion de package.json
et build
En développement il y a une ligne:
"type": "module",
Pour effectuer un build il faut renommer cette directive “typeX” (ou la supprimer).
Commande dans un terminal (à la racine du projet):
npx webpack
- durée de 30s à 1 minute: être patient, rien ne s’affiche avant la fin.
Il faut renommer la directive ““typeX” en “type” sinon le développement ne marche plus.
Dans le folder dist/srv
insérer un fichier package.json ne contenant que {}
:
echo "{}" > dist/srv/package.json
Si on veut exécuter immédiatement le résultat du build directement dans le folder dist/srv
, node
va chercher un package.json
, y compris au niveau de folder supérieur et va trouver le package.json
du projet qui a une directive "type"module"
ce qui met l’exécution en erreur car srv.js
utilise des require
.
La présence du package.json
fake permet d’éviter ce problème.
Exécution de test dans dist/srv
- si le provider de storage était par exemple
sqlite_a: { path: './sqlite/testa.db3' },
vérifier qu’il y a bien une basedist/op/sqlite/testa.db3
. - si le provider de storage était par exemple
fs_a: { rootpath: './fsstoragea' },
dans config.mjs, vérifier qu’il existe bien un folderdist/op/fsstoragea
.
Exécution:
cd dist/srv
node srv.js
Attention:
srv.js
est le vrai exécutable et écrit vraiment dans la vraie base et le vrai storage.
Déploiements de tools
Fichier src/keys.mjs
keys
- les clés vapid… sont inutiles (mais ne nuisent pas).
service_account
- uniquement si l’un des providers de base de données est Firestore.
s3_config
- uniquement si l’un des providers de Storage est S3.
Folder keys
Non utilisé.
Fichier src/config.mjs
export const config = {
// Configuration du déploiement
env: { },
fs_a: { rootpath: './fsstoragea' },
gc_a: { bucket: 'asocial-test1.appspot.com' */ },
sqlite_a: { path: './sqlite/testa.db3' },
firestore_a: { },
run: {
}
}
Commentaires
gc_a:
configuration du provider Google Cloud Storage. Par commodité on peut en décrire plusieurs (gc_a gc_b etc.)sqlite_a:
configuration du provider DB SQLite. Par Par commodité on peut en décrire plusieurs (sqlite_a sqlite_b etc.)firestore_a:
configuration du provider DB Firestore. Par Par commodité on peut en décrire plusieurs (firestore_a firestore_b etc.)
Build par webpack
Fichier webpack.config.mjs
:
import path from 'path'
export default {
entry: './src/tools.mjs',
target: 'node',
mode: 'production',
output: {
filename: 'tools.js',
path: path.resolve('dist/tools')
}
}
Le résultat du _build par webpack ira dans le folder dist/tools
et son .js principal y sera tools.js
Gestion de package.json
et build
En développement il y a une ligne:
"type": "module",
Pour effectuer un build il faut renommer cette directive “typeX” (ou la supprimer).
Commande dans un terminal (à la racine du projet):
npx webpack
- durée de 30s à 1 minute: être patient, rien ne s’affiche avant la fin.
Il faut renommer la directive ““typeX” en “type” sinon le développement ne marche plus.
Dans le folder dist/tools
insérer un fichier package.json ne contenant que {}
:
echo "{}" > dist/tools/package.json
Exécution de test dans dist/tools
Les providers qui seront cités dans la ligne de commande doivent être déclarés.
Exécution:
cd dist/tools
node tools.js ... arguments
Voir en annexe les arguments de tools
.
Attention:
tools.js
est le vrai exécutable et écrit vraiment dans la vraie base et le vrai storage.
Déploiement GAE
Il faut avoir configuré son projet Google pour:
- activer App Engine
- utiliser Firestore: créer la base.
- utiliser Storage: créer son bucket.
- activer CRON sur App Engine.
Le déploiement se fait dans un directory dédié, qui n’a pas lieu d’être archivé dans git.
Il n’a pas été possible d’effectuer un build webpack avant déploiement: en conséquence le déploiement s’effectue en source.
Les fichiers spécifiques au déploiement GAE sont à préparer dans asocial-srv/gae
.
- Copie et adaptation des fichiers sous
asocial-srv
:keys.json
- supprimer l’entrée
s3_config
- supprimer l’entrée
config.mjs
- première ligne:
EMULATOR = false
- vérifier dans le
run
: http/port db_provider storage_provider.
- première ligne:
package.json
- enlever les sections
devDependencies packageManger
- vérifier qu’il y a bien
type: module
- vérifier qu’il n’y a qu’un seul
script: {"start": "node ./src/},secret.js"}
.
- enlever les sections
- Fichiers spécifique de
gae
:app.yaml
: vérifier la version de node.cron.yaml
: ajuster l’heure si nécessaire..cloudignore
depl.sh
. Ce fichier recopie les fichiers nécessaires dans le directory de déploiement.
Scénario de déploiement
Préparer le folder de déploiement: asocial-gae1
(par exemple)
Y créer les folders src
et node_modules
.
cd ./asocial-srv/gae
./depl.sh
cd ../../asocial-gae1
npm install
# OUI npm, pas yarn, deploy utilise package-lock.json
node src/gensecret.mjs
# pour intégrer une éventuelle mise à jour de keys.json
npm install
à deux fonctions:
- permettre d’effectuer un test final après déploiement,
- générer un package-lock.json qui accélère le déploiement ET fixe les versions exactes des modules.
Tester localement
On peut tester le serveur avec: node src/server.js
MAIS ça s’exécuterait sur la base de production, c’est inopportun. Il faut donc:
- changer dans
config.mjs
la première ligneEMULATOR = true
- lancer l’emulator dans une autre fenêtre et l’initialiser avec des données de test d’intégration.
Après tests, changer à nouveau dans config.mjs
la première ligne EMULATOR = false
.
Déployer depuis asocial-gae1
gcloud app deploy --verbosity debug --no-cache
no-cache : sinon plantage du build step 2 en cherchant à comparer avec une version antérieure.
Quelques minutes …, puis si nécessaire (si cron.yaml
a changé par rapport à l’opérationnel):
gcloud app deploy cron.yaml
C’est rapide.
Dans un autre terminal gcloud app logs tail
permet de voir les logs de l’application quand ils vont survenir.
Les logs complets s’obtienne depuis la console Google du projet (menu hamburger en haut à gauche >>> Logs >>> Logs Explorer
).
Déploiements Cloud Function des services OP et PUBSUB
A rédiger, après un premier déploiement réel.
L’utilitaire upload
Un browser ne peut pas écrire dans le file-system de son poste. L’application Web offre la possibilité du download d’une sélection de notes et de leurs fichiers attachés. Pour ce faire elle invoque l’URL http://localhost:33666
upload est un micro serveur Web qui, une fois lancé, écoute ce port: il reçoit des requêtes PUT émises par l’application Web, une par fichier à écrire localement, et en écrit le contenu sur le répertoire local:
- le path du fichier ‘abcd…‘ en relatif au directory courant d’exécution, est donné dans l’URL en base64 URL: http://localhost:33666/abcd…
- le contenu du fichier est dans le body de la requête.
Un build + packaging délivre deux exécutables, un pour Linux upload
, l’autre Windows upload.exe
, autonomes: ils embarquent un runtime node.js
qui dispense l’utilisateur d’une installation un peu technique de node.js
.
Il est aussi possible de mettre à disposition upload.js: dans ce cas le PC devra installer node et lancer l’exécution par node upload.js
.
Les fichiers envoyés par PUT sont installés dans le répertoire courant ou s’exécute upload
. Argument optionnel: numéro de port d’écoute.
cd ...
upload 33666
upload
Build
Depuis le folder où a été installé upload
depuis git:
npm run build
npx webpack // devrait aussi fonctionner.
Packaging
Installation de pkg
npm install -g pkg
Génération des exécutables
cd dist
pkg -t node14-win upload.js
pkg -t node14-linux upload.js
Créé des exécutables pour linux upload
et windows (en x64) upload.exe
.
Distribution
Dans un dépôt de distribution (par exemple github.com/asocialapps
):
- créer un repository
upload
Localement publier dans ce repository:
index.html
upload.exe
upload
upload.js
Dans le settings de ce repository, rubrique Pages, donner main
comme branche de publication.
<!DOCTYPE html>
<html>
<head>
<title>Utilitaires "upload"</title>
</head>
<body>
<div><a href="./upload.exe">Pour Windows (x86): upload.exe</a></div>
<div><a href="./upload">Pour Linux (x86): upload</a></div>
</body>
</html>
Cette page permet de télécharger les exécutables.
On pourrait être un peu plus bavard dans index.html
et y inscrire un minimum de manuel d’utilisation.
Annexe I: CLI tools
tools
est invoqué depuis son folder d’installation.
node tools.js commande arguments
tools
a été buildé avec un fichier de configurationsrc/config.mjs
qui en général comporte des paths relatifs ou absolus. S’assurer de la validité de ceux-ci depuis le folder d’exécution detools
.
Les commandes sont:
export-db
: exporter un espace d’une base de données sur un autre espace d’une autre base de données.export-st
: exporter un espace d’un Storage sur un autre espace d’un autre Storage.purge-db
: purge d’un espace d’une base de données.vapid
: génération d’un nouveau couple de clés privée / publique VAPID. Pas d’arguments, résultat dans./vapid.json
.
export-db -s --in ... --out ...
-s
: optionnel. Simulation, rien n’est écrit.--in N,org,prov_x,S
- Espace sourceN
: lettre / chiffre de l’espace0..9 a..z A..Z
org
: code de l’organisationprov
: nom du provider:sqlite firestore
x
: le providerprov_x
doit être décrit dans la configuration.S
: lettre du site dans la liste des sites de la configuration.
--out N,org,prov_x,S
- Espace cible
purge-db --in ...
--in N,org,prov_x,S
- Espace à purgerN
: lettre / chiffre de l’espace0..9 a..z A..Z
org
: code de l’organisationprov
: nom du provider:sqlite firestore
x
: le providerprov_x
doit être décrit dans la configuration.S
: lettre du site dans la liste des sites de la configuration.
export-st -s --in ... --out ...
-s
: optionnel. Simulation, rien n’est écrit.--in org,prov_x
- Storage sourceorg
: code de l’organisationprov
: nom du provider:fs gc s3
x
: le providerprov_x
doit être décrit dans la configuration.
--out org,prov_x
- Cible
Exemples:
node tools export-db --in 1,doda,sqlite_a,A --out 2,coltes,sqlite_b,B
node tools export-db --in 1,doda,sqlite_a,A --out 1,doda,firestore_a,A
node tools export-db --in A,doda,firestore_a,A --out A,doda,sqlite_b,A
Exemple export-st:
node tools export-st --in doda,fs_a --out doda,gc_a
Exemple purge-db
node tools purge-db --in 2,coltes,firebase_b,A
node tools purge-db --in 2,coltes,sqlite_b,B
Utilitaire d’envoi de mails d’alertes
Certaines alertes peuvent être notifiées sur le mail de l’administrateur technique.
Un des moyens est d’utiliser un site Web d’URL http://monsite.truc.fr/
ayant PHP et acceptant le mailing par PHP. Y inscrire un script sendMail.php
ayant l’interface suivant:
- il accepte des requêtes POST
application/x-www-form-urlencoded
avec les arguments suivants:mailer
: ‘A’ # Au cas où le script accepte plusieurs configuration de mail.mdp
: # mot de passe du service SMTP utiliséto
: # adresse email de l’administrateur techniquesubject
: # texte du sujettext
: # Corps du texte
- cas de succès d’envoi du mail retourne
OK: date-heure
et en cas d’échecKO: date-heure
.
Un exemple figure dans etc/sendMail.php
et un exemple de soumission de requête est dans etc/testMail.html
.