Dans cette série d'articles, j'aimerais présenter et discuter de plusieurs approches possibles pour le développement de logiciels avec les technologies d'InterSystems et GitLab. J'aborderai des sujets tels que:
- Git 101
- Flux Git (processus de développement)
- Installation de GitLab
- Flux de travail GitLab
- Diffusion continue
- Installation et configuration de GitLab
- GitLab CI/CD
- Pourquoi des conteneurs?
- Infrastructure de conteneurs
- CD utilisant des conteneurs
- CD utilisant ICM
- Architecture des conteneurs
Dans cet article, nous aborderons la construction de votre propre conteneur et son déploiement.
Durable %SYS
Les conteneurs étant plutôt éphémères, ils ne doivent pas stocker de données d'application. Durable %SYS est une fonction qui permet justement de stocker les paramètres, la configuration, les données %SYS, etc. sur un volume hôte, à savoir :
- TLe fichier iris.cpf.
- Le répertoire /csp, qui contient la configuration de la passerelle web et les fichiers journaux.
- Le fichier /httpd/httpd.conf, qui est le fichier de configuration du serveur web privé de l'instance.
- Le répertoire /mgr, qui contient les éléments suivants:
- La base de données du système IRISSYS, qui contient les fichiers IRIS.DAT et iris.lck et le répertoire stream, ainsi que les répertoires iristemp, irisaudit, iris et user qui contiennent les bases de données du système IRISTEMP, IRISAUDIT, IRIS et USER.
- Le fichier de journalisation d'image en écriture, IRIS.WIJ.
- Le répertoire /journal qui contient les fichiers journaux.
- Le répertoire /temp pour les fichiers temporaires.
- Les fichiers journaux, y compris messages.log, journal.log et SystemMonitor.log.
Architecture des conteneurs
D'autre part, nous devons stocker le code de l'application dans notre conteneur afin de pouvoir le mettre à jour en cas de besoin.
Tout cela nous amène à l'architecture suivante :
Pour ce faire, lors des étapes de construction, nous devons au minimum créer une base de données supplémentaire (pour stocker le code de l'application) et la faire correspondre à l'espace de noms de l'application. Dans mon exemple, j'utiliserai l'espace de noms USER pour contenir les données d'application car elles existent déjà et sont durables.
Installation
Sur la base de ce qui précède, notre installateur nécessite le suivant :
- Créer l'espace de noms et de la base de données d'APP
- Télécharger le code dans l'espace de noms d'APP
- Faire correspondre nos classes d'application à l'espace de noms USER
- Faites toutes les autres installations (dans ce cas, j'ai créé l'application Web CSP et l'application REST)
Class MyApp.Hooks.Local { Parameter Namespace = "APP"; /// Voir le code généré dans zsetup+1^MyApp.Hooks.Local.1 XData Install [ XMLNamespace = INSTALLER ] { <Manifest> <Log Text="Creating namespace ${Namespace}" Level="0"/> <Namespace Name="${Namespace}" Create="yes" Code="${Namespace}" Ensemble="" Data="IRISTEMP"> <Configuration> <Database Name="${Namespace}" Dir="/usr/irissys/mgr/${Namespace}" Create="yes" MountRequired="true" Resource="%DB_${Namespace}" PublicPermissions="RW" MountAtStartup="true"/> </Configuration> <Import File="${Dir}Form" Recurse="1" Flags="cdk" IgnoreErrors="1" /> </Namespace> <Log Text="End Creating namespace ${Namespace}" Level="0"/> <Log Text="Mapping to USER" Level="0"/> <Namespace Name="USER" Create="no" Code="USER" Data="USER" Ensemble="0"> <Configuration> <Log Text="Mapping Form package to USER namespace" Level="0"/> <ClassMapping From="${Namespace}" Package="Form"/> <RoutineMapping From="${Namespace}" Routines="Form" /> </Configuration> <CSPApplication Url="/" Directory="${Dir}client" AuthenticationMethods="64" IsNamespaceDefault="false" Grant="%ALL" Recurse="1" /> </Namespace> </Manifest> } /// C'est un générateur de méthodes dont le code est généré par XGL. /// Méthode principale de paramétrage /// fixer vars("Namespace")="TEMP3" /// exécuter ##class(MyApp.Hooks.Global).setup(.vars) ClassMethod setup(ByRef pVars, pLogLevel As %Integer = 0, pInstaller As %Installer.Installer) As %Status [ CodeMode = objectgenerator, Internal ] { Quit ##class(%Installer.Manifest).%Generate(%compiledclass, %code, "Install") } /// Point d'entrée ClassMethod onAfter() As %Status { try { write "START INSTALLER",! set vars("Namespace") = ..#Namespace set vars("Dir") = ..getDir() set sc = ..setup(.vars) write !,$System.Status.GetErrorText(sc),! set sc = ..createWebApp() } catch ex { set sc = ex.AsStatus() write !,$System.Status.GetErrorText(sc),! } quit sc } /// Modifier l'application Web REST ClassMethod createWebApp(appName As %String = "/forms") As %Status { set:$e(appName)'="/" appName = "/" _ appName #dim sc As %Status = $$$OK new $namespace set $namespace = "%SYS" if '##class(Security.Applications).Exists(appName) { set props("AutheEnabled") = $$$AutheUnauthenticated set props("NameSpace") = "USER" set props("IsNameSpaceDefault") = $$$NO set props("DispatchClass") = "Form.REST.Main" set props("MatchRoles")=":" _ $$$AllRoleName set sc = ##class(Security.Applications).Create(appName, .props) } quit sc } ClassMethod getDir() [ CodeMode = expression ] { ##class(%File).NormalizeDirectory($system.Util.GetEnviron("CI_PROJECT_DIR")) } }
Pour créer la base de données non durable, j'utilise un sous-répertoire de /usr/irissys/mgr, qui n'est pas persistant. Notez que l'appel à ##class(%File).ManagerDirectory() envoie le chemin vers le répertoire durable et non le chemin vers le répertoire interne du conteneur.
Configuration de diffusion continue
Consultez la partie VII pour plus d'informations, mais tout ce que nous avons à faire est d'ajouter ces deux lignes (en gras) à notre configuration existante.
run image: stage: run environment: name: $CI_COMMIT_REF_NAME url: http://$CI_COMMIT_REF_SLUG.docker.eduard.win/index.html tags: - test script: - docker run -d --expose 52773 --volume /InterSystems/durable/$CI_COMMIT_REF_SLUG:/data --env ISC_DATA_DIRECTORY=/data/sys --env VIRTUAL_HOST=$CI_COMMIT_REF_SLUG.docker.eduard.win --name iris-$CI_COMMIT_REF_NAME docker.eduard.win/test/docker:$CI_COMMIT_REF_NAME --log $ISC_PACKAGE_INSTALLDIR/mgr/messages.log
l'argument volume installe le répertoire hôte dans le conteneur et la variable ISC_DATA_DIRECTORY indique à InterSystems IRIS le répertoire à utiliser. La documentation suivante peut être citée :
Lorsque vous exécutez un conteneur IRIS InterSystems à l'aide de ces options, les événements suivants se produisent:
Si le répertoire %SYS durable spécifié par la variable d'environnement ISC_DATA_DIRECTORYiconfig/ dans l'exemple précédent, existe déjà et contient des données %SYS durables, tous les pointeurs internes de l'instance sont réinitialisés sur ce répertoire et l'instance utilise les données qu'il contient. Si le répertoire %SYS durable spécifié par la variable d'environnement ISC_DATA_DIRECTORY existe déjà mais ne contient pas de données %SYS durables, aucune donnée n'est copiée et l'instance s'exécute en utilisant les données de l'arborescence d'installation à l'intérieur du conteneur, ce qui signifie que les données spécifiques à l'instance ne sont pas persistantes. C'est pourquoi il peut être utile pour vous d'inclure dans les scripts une vérification de cette condition avant d'exécuter le conteneur.
Les répertoires et les fichiers répertoriés dans le contenu du répertoire %SYS durable sont copiés depuis leur emplacement d'installation vers le répertoire %SYS durable (les originaux restent en place).
Mises à Jour
Lorsque l'application évolue et qu'une nouvelle version (conteneur) est publiée, vous pouvez parfois avoir besoin d'exécuter du code. Il peut s'agir d'accrochages avant/après la compilation, de migrations de schémas, de tests unitaires, mais tout cela se résume à la nécessité d'exécuter un code arbitraire. C'est pourquoi vous avez besoin d'un framework qui gère votre application. Dans des articles précédents, J'ai décrit une structure de base de ce framework, mais il peut bien sûr être considérablement étendu pour répondre aux exigences spécifiques de l'application.
Conclusion
La création d'une application conteneurisée doit être mûrement réfléchie, mais InterSystems IRIS offre plusieurs fonctionnalités qui facilitent ce processus.