#Mise en miroir

0 Abonnés · 11 Publications

La mise en miroir est une technologie InterSystems pour la haute disponibilité, la reprise après sinistre et la sauvegarde des bases de données et des solutions OLAP.

Documentation.

Article Guillaume Rongier · Oct 15, 2025 9m read

Vous êtes familier avec les bases de données SQL, mais vous ne connaissez pas IRIS ? Alors lisez la suite...

Il y a environ un an, j'ai rejoint InterSystems, et c'est ainsi que j'ai découvert IRIS.  J'utilise des bases de données depuis plus de 40 ans, la plupart du temps pour des fournisseurs de bases de données, et je pensais qu'IRIS serait similaire aux autres bases de données connues.  Cependant, j'ai été surpris de constater qu'IRIS est très différente par rapport aux autres bases de données, et souvent bien meilleure.  Avec mon premier article dans la communauté Dev, je vais présenter IRIS de manière générale aux personnes qui connaissent déjà d'autres bases de données telles qu'Oracle, SQL Server, Snowflake, PostgeSQL, etc.   J'espère vous rendre les choses plus claires et plus simples et vous faire gagner du temps pour vous lancer.

Tout d'abord, IRIS prend en charge les commandes et la syntaxe SQL de la norme ANSI. Il dispose de tables, de colonnes, de types de données, de procédures stockées, de fonctions...   bref, tout ce qui concerne les relations.  Et vous pouvez utiliser ODBC, JDBC, DBeaver ou tout autre navigateur de base de données que vous préférez.  Donc, oui, la plupart des connaissances et des opérations que vous maîtrisez avec d'autres bases de données fonctionneront très bien avec IRIS.  Youpi!  

Mais qu'en est-il de ces différences que j'ai mentionnées?  Bien, attachez vos ceintures:

Multi-Model: IRIS est une base de données relationnelle, mais c'est aussi une base de données orientée objet, un magasin de documents, et elle prend en charge les vecteurs, les cubes/MDX, et... vous comprenez où je veux en venir.  Ce qui est incroyable, c'est que vous pouvez profiter de tous ces modèles... dans la même instruction SQL!  Et bien souvent, les données peuvent être stockées sous plusieurs de ces structures de données — sans avoir à les sauvegarder à deux reprises — ni à utiliser plusieurs types de bases de données!  Lorsque vous accédez à des données identiques comme s'il s'agissait de modèles différents, InterSystems parle de CDP (Common Data Plane, ou plan de données commun).  C'est pour le moins rare, voire unique, dans le secteur des bases de données.  Personne ne s'intéressait vraiment au CDP jusqu'à ce que la révolution de l'IA rende tout à coup indispensable la prise en charge du multimodèle. Il ne s'agit pas d'une fonctionnalité que d'autres bases de données sont susceptibles d'implémenter, car elle est intégrée au cœur même du noyau.  IRIS facilite l'utilisation des modèles multiples ainsi que des technologies NoSQL et NewSQL pour les utilisateurs SQL:

Pour la base de données Object, vous extrayez une clé-valeur de l'arborescence JSON, qui correspond simplement à la valeur d'une table classique. 

-- exemple de requête dans une base de données ObjectSELECT JSON_OBJECT('product':Product,'sizes':PopularSizes) FROM Sample.Clothing

-- Cela renvoie une liste de paires clé-valeur. Si une paire manque, -- IRIS crée par défaut une paire avec une valeur nulle.

En ce qui concerne Vector, considérez-le simplement comme un autre type de données, mais avec certaines fonctions spéciales qui ne fonctionnent qu'avec le type de données en question 

-- exemple de création d'une table avec une colonne vectorielleCREATETABLE Sample.CustEventV1 (
  CustID INTEGER,
  EventDt DATE,
  Vtest VECTOR(integer,4),
  EventValue NUMERIC(12,2),  
  EventCD VARCHAR(8)) 

-- Vous pouvez utiliser des fonctions telles que VECTOR_DOT_PRODUCT ou VECTOR_COSINE sur Vtest

Taxonomie:  les différents fournisseurs de bases de données n'utilisent pas tels termes comme base de données, schéma, déploiement, instance, etc. exactement de la même manière. 

  • Instance: lorsque vous installez le logiciel de base de données, généralement appelé 'instance' par les éditeurs de bases de données. J'entends parfois ce terme chez InterSystems, mais plus souvent, j'entends le terme 'déploiement'.  Cela s'explique probablement par le fait que le terme 'instance' est déjà utilisé dans le monde orienté objet.  Quel que soit le terme utilisé, la hiérarchie pour les autres bases de données est généralement la suivante:
    • instance/déploiement
      • base de deonnées
        • schéma
          • tables, vues, etc.

            .. ou bien:

  • instance/déploiement (il *s'agit* de la base de données)
    • schéma
      • tables, vues, etc.

            .. mais IRIS est un peu différent dans la mesure où il comporte une couche supplémentaire appelée 'espace de nom':

  • instance/déploiement
    • espace de nom
      • base de données
        • schéma
          • tables, viues, etc.

Un espace de noms est une entité logique qui contient des bases de données. Cependant, plusieurs espaces de noms peuvent contenir la même base de données, il ne s'agit donc peut-être pas d'une hiérarchie.  Il est principalement utilisé pour le contrôle d'accès. Et il peut contenir des bases de données provenant d'autres instances/déploiements!

HA: La haute disponibilité (High Availability) est obtenue grâce à une technique appelée mise en miroir ( mirroring ).  Il s'agit d'un type de réplication où l'intégralité de la base de données est répliquée, y compris le code.  Vous pensez peut-être que vous ne souhaitez pas répliquer l'intégralité de la base de données.  Mais grâce aux espaces de noms, vous pouvez considérer une base de données comme une sorte de schéma et diviser vos données de manière à ce que celles que vous souhaitez mettre en miroir et celles que vous ne souhaitez pas mettre en miroir se trouvent dans des bases de données distinctes. 

Stockage du code: Oui, vous avez parfaitement compris: lorsque vous mettez une base de données en miroir, le code est également transféré!  Il s'agit d'une fonctionnalité très récente pour certaines bases de données à la mode, mais IRIS l'offre depuis toujours. Vous pouvez stocker à la fois le code et les données dans la même base de données, mais le plus souvent, les utilisateurs préfèrent les séparer.

ECP: Bien; c'est le protocole Enterprise Cache Protocol qui rend IRIS vraiment intéressant.  Je ne savais même pas que cela était possible, mais j'ai récemment découvert qu'il existe quelques bases de données NoSQL peu connues qui le permettent.  Avec le protocole ECP vous pouvez configurer le système de manière à ce que différents déploiements puissent partager leurs caches!  Oui, je veux bien dire leurs caches memory réels.. et non pas le partage des données des tables. Pour ce faire, le cache d'un déploiement est automatiquement synchronisé avec celui d'un autre déploiement.  C'est ce qu'on appelle être synchronisé!  C'est très facile à configurer, même si cela doit être compliqué en coulisses. Il s'agit d'un tout autre type de mise à l'échelle horizontale qui peut rendre les applications ultra-rapides.

Translytique: Ce terme, translytique, est utilisé pour décrire une base de données qui est à la fois OLTP et OLAP. Il peut également être appelé HTAP ou HOAP. Parfois, on emploie le terme hybride mais ce terme est trop utilisé dans le monde technologique, je vais donc m'en tenir au terme commençant par T.  Au début, toutes les bases de données étaient translytiques.  Mais avec l'avènement des structures en colonnes et d'autres structures, ainsi que de nouveaux types de stockage (par exemple le stockage en blocs par opposition au stockage en blobs) elles ont été séparées en OLTP et OLAP. Aujourd'hui, les fournisseurs tentent de les réunir à nouveau.   Il est beaucoup plus facile d'ajouter OLAP à un noyau OLTP que de faire l'inverse. Bien sûr, les fournisseurs de solutions DW peuvent ajouter quelques indexations pour les recherches sur une seule ligne, mais je doute qu'ils ajoutent rapidement la prise en charge de fonctionnalités complexes telles que les déclencheurs et les insertions/mises à jour rapides. Le fait est que l'OLTP rapide est plus compliqué à construire que l'OLAP... c'est une technologie beaucoup plus mature. IRIS est une excellente base de données translytique (voir les évaluations des analystes pour comprendre pourquoi). Par exemple, certaines bases de données prennent en charge à la fois le stockage en lignes et en colonnes, mais dans des tables différentes.  IRIS peut disposer de colonnes de stockage en lignes dans la même table que les colonnes de stockage en colonnes.

/* Exemple de combinaison entre stockage en lignes et stockage en colonnes. 
   Toutes les colonnes sont stockées en lignes (par défaut), à l'exception de EventValue.
   EventValue est explicitement définie comme stockage en colonnes. 
   Si vous interrogiez la valeur moyenne de EventValue pour l'ensemble de la table, la réponse serait RAPIDE! */CREATETABLE Sample.CustEvent (
  CustID INTEGER,
  EventDt DATE,
  EventValue NUMERIC(12,2) WITH STORAGETYPE = COLUMNAR,
  EventCD VARCHAR(8))

Installation: Avec d'autres bases de données, vous devez généralement les installer quelque part (sur site ou dans le cloud), comme vous le faites avec Postgres ou SQL Server, ou bien recourir à un SAAS cloud tel que RedShift ou Snowflake. Avec IRIS, cela dépend. Il y a trois moyens d'obtenir IRIS : via une licence, via un service géré ou via Cloud SQL. 

  1. Grâce à une licence, vous pouvez l'installer, le configurer et le maintenir de manière indépendante. Cela peut se faire sur site ou sur le cloud de votre choix. J'ai surtout entendu parler de son utilisation sur AWS, Azure, GCP et TenCent.
  2. Grâce à un service géré, InterSystems installe, configure et assure la maintenance d'IRIS pour vous via un cloud public. 
  3. Grâce à Cloud SQL, il est possible de bénéficier d'un service SAAS (ou devrais-je dire PAAS ? DBAAS ?).  Vous n'avez rien à installer.  Il est conçu pour s'intégrer dans des systèmes plus vastes en tant que module composable, n'offrant qu'un sous-ensemble des fonctionnalités IRIS, telles que SQL et les fonctions d'apprentissage automatique (ML).  La suite de cet article concerne IRIS sous licence ou IRIS géré, et ne concerne pas Cloud SQL.

Langages intégrés: Outre SQL, IRIS a toujours pris en charge un langage orienté objet appelé ObjectScript, qui est un dérivé du langage médical MUMPS. Il s'agit d'un langage très puissant, mais peu connu. Ne vous inquiétez pas, IRIS prend également en charge Python intégré. 

Documentation: Comme IRIS a toujours été étroitement lié à ObjectScript, la documentation a tendance à utiliser une terminologie orientée objet.  Vous trouverez donc des termes simples tels que tables désignés par 'classes persistentes'.  Mais cela semble disparaître de la documentation au fil du temps, et vous pouvez tout simplement ignorer ces termes, sauf si vous souhaitez devenir programmeur IRIS.

IRIS prend donc en charge le langage SQL que vous connaissez et appréciez, ainsi que Python, il est translytique, fonctionne sur site ou dans le cloud, est multimodèle et dispose de fonctionnalités futuristes telles que l'ECP.  Il y a bien d'autres choses encore mais ce sont celles-ci qui m'ont paru les plus importantes et interessantes.  Je pense qu'elles pourraient être utiles à d'autres développeurs SQL et administrateurs de bases de données provenant d'autres produits.   Si c'est votre cas et que vous essayez IRIS, je souhaiterais connaître votre avis sur votre expérience.

0
0 27
InterSystems officiel Adeline Icard · Juil 24, 2025

InterSystems annonce la disponibilité générale d'InterSystems IRIS 2025.2

InterSystems a le plaisir d'annoncer la disponibilité générale (GA) de la version 2025.2 de la plateforme de données InterSystems IRIS. Il s'agit d'une version en livraison continue (CD). Veuillez noter que les versions GA d'InterSystems IRIS for Health et HealthShare Health Connect 2025.2 sont actuellement suspendues en raison de limitations de mise en miroir introduites par les mises à jour de sécurité (détails ci-dessous).

Points forts de la version

0
0 27
Article Developer Community Admin · Juin 2, 2025 6m read

Le déplacement d'InterSystems IRIS et d'InterSystems IRIS for Health d'un environnement sur site vers le cloud offre de nombreux avantages aux Fournisseurs d'applications et de solutions. Ces avantages comprennent notamment la simplification des opérations, l'accès à des ressources flexibles et une résilience accrue. Les entreprises n'ont plus à se soucier des contraintes physiques et des dépenses liées à la maintenance d'une infrastructure sur site, telles que les besoins en énergie et en espace, ainsi que le coût élevé du matériel informatique.

L'un des avantages les plus convaincants est la possibilité d'accélérer la vitesse de commercialisation. En supprimant la charge liée à la maintenance de l'infrastructure, les environnements cloud permettent des cycles de développement et de déploiement plus rapides, ce qui permet aux entreprises de réagir rapidement aux demandes et aux opportunités du marché. Les coûts opérationnels sont également réduits, car les entreprises peuvent sadapter leurs ressources à la hausse ou à la baisse en fonction de leurs besoins réels, ce qui se traduit par une utilisation plus efficace du capital. De plus, la migration vers le cloud peut contribuer à réduire l'empreinte carbone en optimisant la consommation d'énergie grâce à une infrastructure cloud partagée.

Le déplacement vers le cloud peut impliquer des changements importants. Les entreprises peuvent bénéficier d'une orientation plus opérationnelle, en gérant et en optimisant en permanence les ressources cloud. Cette évolution peut nécessiter des changements dans les modèles commerciaux, une redéfinition des marges et des stratégies d'expansion ou de réduction des activités. Bien qu'ils nécessitent des investissements plus importants, ces changements peuvent améliorer la flexibilité et l'avantage compétitif sur le marché.

Choix architecturaux dans la migration vers le cloud

Lorsqu'elles envisagent la migration vers le cloud la plus simple, les entreprises doivent choisir un ou plusieurs services (AWS, Azure, Google ou autre) pour déplacer une application existante sur site vers l'un des clouds publics. Elles sont alors confrontées à un choix architectural important : migrer entièrement vers le cloud ou créer un cluster hybride sur site et dans le cloud. InterSystems IRIS et InterSystems IRIS for Health prennent tous deux entièrement en charge ces deux options. Un cluster hybride miroite l'instance sur site vers le cloud de manière asynchrone. Cette alternative peut être utile dans des situations telles que celles où l'OLTP continue de fonctionner sur site, mais où l'instance cloud fournit une prise en charge pour l'analyse, la création de rapports et d'autres opérations en lecture seule.

Options de migration

Chaque choix architectural pour la migration vers le cloud a ses avantages et ses limites,  il est donc essentiel pour les entreprises d'évaluer leurs besoins et leurs objectifs spécifiques lors de la planification d'une stratégie cloud. La première étape consiste à choisir entre une migration complète vers le cloud ou une configuration hybride.

Choix migratoireNombre de  déploiements InterSystems IRIS après la migrationCaractéristiques
Lift & Shift: migration complète vers le cloud1Configuration sur site locale transférée vers une architecture cloud
Cluster hybride : sur site plus copie miroir dans le cloud ("cluster étendu")2Cluster sur site mis en miroir vers une copie cloud en lecture seule mise à jour de manière asynchrone

Le choix Lift & Shift permet de profiter des avantages du cloud tout en conservant la propriété d'une seule copie d'InterSystems IRIS.

Le choix Hybrid combine la stabilité et la familiarité des systèmes sur site avec la flexibilité et l'évolutivité du cloud.

Consultez notre documentation en ligne pour plus d'informations sur la mise en miroir Mirroring.

Architecture multitenant ou monotenant avec InterSystems IRIS

Bien que la migration ne nécessite aucune modification de votre méthode de mutualisation, le cloud offre de puissantes options d'évolutivité et de facturation. Pour cette raison, vous souhaiterez peut-être réévaluer votre modèle de mutualisation. Pour toutes nos offres, lors du déploiement d'applications InterSystems IRIS dans le cloud, les entreprises peuvent choisir entre les architectures suivantes pour plusieurs utilisateurs:

  • Mono-tenant: Déploiements multiples ; un pour chacun de vos utilisateurs.
  • Multi-tenant: Plusieurs utilisateurs sur un seul déploiement.

Chaque architecture présente des avantages et des inconvénients distincts. Cela est particulièrement important pour les fournisseurs d'applications et de solutions qui ont développé des solutions à l'aide de la technologie InterSystems IRIS, que ce soit pour un grand nombre d'utilisateurs, dans le cadre d'une expansion majeure ou pour l'hébergement de données sensibles ou réglementées.

Évolutivité des ressources et des opérations

  • Multi-tenant: L'évolutivité d'un environnement multi-tenant implique l'ajout de ressources à une instance partagée unique pour chaque utilisateur (tenant), ce qui peut s'avérer plus rentable et plus simple à gérer. Cependant, les performances d'un tenant peuvent affecter celles des autres si les ressources allouées sont insuffisantes, ce qui peut entraîner des contention de ressources.
  • Mono-tenant: Faire évoluer un environnement mono-tenant signifie provisionner davantage de ressources pour chaque utilisateur individuellement. Bien que cela offre des performances plus prévisibles, le besoin d'infrastructure supplémentaire et les frais généraux liés à la gestion peuvent rendre ce choix plus complexe à faire évoluer.

Isolation des données

  • Multi-tenant: Dans une configuration multi-tenant, plusieurs tenants partagent la même instance de l'application et de la base de données. L'isolation des données est assurée par un partitionnement au niveau logiciel, qui garantit la sécurité et la séparation des données de chaque tenant. Cette approche peut être efficace en termes d'utilisation des ressources, mais elle peut nécessiter des mesures de sécurité rigoureuses pour prévenir les violations de données.
  • Mono-tenant: Avec une architecture mono-tenant, chaque utilisateur dispose d'une instance distincte de l'application et de la base de données. Cette configuration fournit un niveau plus élevé d'isolation des données, car les données de chaque tenant résident dans un environnement distinct. Ce choix peut être plus sûr et plus facile à gérer, facilitant la conformité aux réglementations en matière de protection des données. 

Méthodes de migration

Plusieurs approches sont disponibles pour migrer votre solution InterSystems IRIS de vos sites vers le service cloud de votre choix.

Les deux méthodes les plus courantes sont décrites ci-dessous. Elles commencent toutes deux par la même étape, qui consiste à miroiter un déploiement existant vers le cloud, mais elles divergent ensuite.

Choisir entre miroir et lift-and-shift

Les méthodes du miroir et du lift-and-shift commencent toutes deux par la copie de votre InterSystems IRIS existant depuis votre environnement sur site vers une plateforme cloud. Une fois la copie cloud synchronisée avec l'instance sur site, vous choisissez définitivement où se termine le chemin de migration:

  • Miroir: vous continuez à utiliser l'instance sur site comme instance principale et l'instance cloud comme instance de sauvegarde et pour les opérations en lecture seule, telles que l'analyse et l'apprentissage automatique. L'instance cloud est asynchrone, mais mise à jour régulièrement.
  • Lift-and-shift: Une fois l'instance principale sur site et les instances secondaires basées sur le cloud synchronisées, les opérations de "basculement" s'effectuent depuis l'instance sur site vers la copie dans le cloud, qui devient alors l'instance principale pour toutes les opérations (et pas seulement en lecture seule). À ce stade, le déploiement sur site peut être archivé sous forme de sauvegarde instantanée.

La mise en miroir de votre instance InterSystems IRIS locale existante vers le cloud est le moyen le plus courant, le plus résilient et le plus simple de migrer votre déploiement sur site. Pour plus d'informations, consultez le Guide de migration du serveur Server Migration Guide dans notre documentation en ligne.


Plus d'articles sur le sujet:

Source: Déplacement d'InterSystems IRIS vers le cloud

0
0 38
Article Matthieu LAURENT · Sept 11, 2024 4m read

Bonjour,

je vous soumets cet article sous forme d'ADR (Architecture decision record) que nous avons rédigé dans nos équipes. L'objectif était d'être pertinent dans le choix de nos types de stream dans un contexte mirroré. A noter que des éléments peuvent être utiles même dans un environnement sans miroir.

Stockage des "Character Stream" dans un environnement mirroré

  • Auteur : Matthieu LAURENT et Vincent DHEILLY
  • Date : 2024-09-11
  • Version : IRIS 2024.1

Contexte

Les streams sont très utilisées au sein d'InterSystems notamment dans 2 contextes très différents :

  • Stocker des fichiers contenant des caractères (PDF par exemple)
  • Stocker des chaines de caractères très volumineuses

Nos analyses ont été menées avec des CharacterStream. Cependant, les éléments de conclusion et de bonnes pratiques sont transposables pour les BinaryStream.

Il existe 3 classes permettant de manipuler les streams de caractère.

  • %Stream.GlobalCharacter : Avec cette classe, les streams sont stockées dans une globale dédiée.
  • %Stream.FileCharacter : Avec cette classe, les streams sont stockées dans un fichier externe. Seul un pointeur vers le fichier est stocké dans une globale.
  • %Stream.TmpCharacter : Permet de stocker une stream temporairement mais ne peut être sauvegardée.

Solutions étudiées

Le but étant d'étudier le stockage pérenne, la classe TmpCharacter est totalement exclue des solutions viables et donc étudiées.

Utilisation des GlobalCharacter

Les GlobalCharacter sont stockés dans une globale dédiée. Elles sont donc par défaut stockées dans la base de données "DATA" du namespace dans laquelle elle se trouve.

AvantagesInconvénients
Les streams sont stockées dans la base et donc mirroréesLa taille conséquente des streams peuvent faire grossir la base
Aucune date de création des fichiers. Difficile d'isoler les "vieux" fichiers

Utilisation des FileCharacter

Les FileCharacter sont stockés dans des fichiers externes. Elles sont donc par défaut stockées dans un sous dossier stream de la base de données "DATA" du namespace dans laquelle elle se trouve. Seul un pointeur vers le fichier est stocké en base de données.

AvantagesInconvénients
Les fichiers sont stockés sur le serveur directement et ne font pas grossir la baseLes fichiers ne sont pas mirrorés. En cas de document métier important, il faut une solution tierce pour prévoir une copie temps réel de ces fichiers
Les fichiers étant datés, une purge est facilement envisageable

Décision

L'utilisation des FileCharacter stream n'est pas une solution viable de façon autonome dans un environnement mirroré. Il est donc impossible d'utiliser ce type dans le cas d'un document de gestion persisté.

Les streams stockés dans les messages n'ont par contre aucune utilité d'être stockées de façon pérenne.

La décision est d'utiliser dans tous les cas la classe GlobalCharacter lorsque l'attribut se trouve dans une classe persistante. Elle est aussi d'utiliser dans tous les cas un FileCharacter lorsque l'attribut fait partie d'une classe sérialisable.

A noter que dans les deux cas, il est impératif de définir une localisation de stockage.

Exemple avec un GlobalCharacter pour stocker un fichier Justificatif
Toujours préfixer avec le mot clef STREAM pour identifier les globales

Property Justificatif As %Stream.GlobalCharacter(LOCATION = "^STREAMJustificatif");

Exemple avec un FileCharacter pour stocker un fichier Justificatif.
Mettre dans un dossier indiquant que c'est des streams et que c'est temporaire

Property Justificatif As %Stream.FileCharacter(LOCATION = "/stream/tmp/justificatif");

Dans le cas des FileCharacter, prévoir dès l'implémentation une stratégie de purge des fichiers sur base de date.

Conséquences

En choisissant cette stratégie, voici les conséquences :

  1. Mirroring automatique : Toutes les streams persistantes sont automatiquement mirrorées

  2. Stockage maîtrisé : Les streams non pérennes peuvent être facilement purgées. Attention, ce n'est pas automatique, purge manuelle via le système de fichier nécessaire. Il est également possible de créer des tâches de purge directement via IRIS.

  3. Base de données dédiées aux fichiers : Les streams étant stockés dans des globales dédiées, il est possible de prévoir une base de données locales dédiées aux streams par namespace et de gérer avec une transposition de package.

Références

1
3 130
Article Guillaume Rongier · Août 13, 2024 17m read

Si vous exécutez IRIS dans une configuration miroir pour HA dans GCP, la question de la fourniture de Mirror VIP (adresse IP virtuelle) devient pertinente. L'adresse IP virtuel permet aux systèmes en aval d'interagir avec IRIS en utilisant une seule adresse IP. Même en cas de basculement, les systèmes en aval peuvent se reconnecter à la même adresse IP et continuer à fonctionner.

Le principal problème, lors du déploiement sur GCP, est qu'un VIP IRIS doit être essentiellement un administrateur de réseau, conformément aux docs.

Pour obtenir l'HA, les membres du miroir IRIS doivent être déployés dans différentes zones de disponibilité d'un sous-réseau (ce qui est possible dans GCP car les sous-réseaux couvrent toujours toute la région). L'une des solutions pourrait être les équilibreurs de charge, mais ils coûtent bien sûr plus cher et nécessitent d'être administrés.

Dans cet article, j'aimerais fournir un moyen de configurer un VIP miroir sans utiliser les équilibreurs de charge suggérés dans la plupart des autres architectures de référence GCP.

Architecture

GCP VIP

Nous avons un sous-réseau qui s'étend sur la région de disponibilité (je simplifie ici - bien sûr, vous aurez probablement des sous-réseaux publics, un arbitre dans une autre zone, et ainsi de suite, mais il s'agit d'un minimum absolu suffisant pour démontrer cette approche). La notation CIRD du sous-réseau est 10.0.0.0/24, ce qui signifie que les adresses IP 10.0.0.1 à 10.0.0.255 lui sont allouées. En tant que GCP réserve les deux premières et dernières adresses, nous pouvons utiliser 10.0.0.2 'à 10.0.0.253'`.

Nous mettrons en œuvre des VIP publics et privés en même temps. Si vous voulez, vous pouvez implémenter uniquement le VIP privé.

Idée

Les machines virtuelles dans GCP ont des Interfaces réseau. Ces interfaces réseau ont des Plages IP Alias IP Ranges qui sont des adresses IP privées. Des adresses IP publiques peuvent être ajoutées en spécifiant la configuration d' accès Access Config La configuration d'interfaces réseau est une combinaison d'IP publiques et/ou privées, et elle est acheminée automatiquement vers la Machine virtuelle associée à l'Interface réseau. Il n'est donc pas nécessaire de mettre à jour les routes. Lors d'un basculement de miroir, nous allons supprimer la configuration IP VIP de l'ancien primaire et la créer pour un nouveau primaire. Toutes les opérations nécessaires à cette fin prennent de 5 à 20 secondes pour une IP VIP privée uniquement, de 5 secondes à une minute pour une combinaison d'IP VIP publique/privée.

Mise en œuvre de VIP

  1. Allouez l'adresse IP à utiliser en tant que VIP public. Ignorez cette étape si vous souhaitez uniquement un VIP privé.
  2. Choisissez une valeur VIP privée. Je vais utiliser '10.0.0.250'`
  3. Provisionnez vos instances IRIS avec un compte de service
  • compute.instances.get
  • compute.addresses.use
  • compute.addresses.useInternal
  • compute.instances.updateNetworkInterface
  • compute.subnetworks.use

Pour les VIP externes, vous aurez également besoin de:

  • compute.instances.addAccessConfig
  • compute.instances.deleteAccessConfig
  • compute.networks.useExternalIp
  • compute.subnetworks.useExternalIp
  • compute.addresses.list
  1. Lorsqu'un membre miroir actuel devient primaire, nous utilisons un callback ZMIRROR pour supprimer une configuration IP VIP sur l'interface réseau d'un autre membre miroir et créer une configuration IP VIP pointant sur lui-même :

C'est tout!

ROUTINE ZMIRROR

NotifyBecomePrimary() PUBLIC {
    #include %occMessages
    set sc = ##class(%SYS.System).WriteToConsoleLog("Setting Alias IP instead of Mirror VIP"_$random(100))
    set sc = ##class(%SYS.Python).Import("set_alias_ip")
    quit sc
}

Et voici set_alias_ip.py qui doit être placé dans le répertoire mgr\python:

"""
Ce script ajoute l'Alias IP (https://cloud.google.com/vpc/docs/alias-ip) à l'interface réseau de la VM.

Vous pouvez allouer des plages d'Alias IP à partir de la plage de sous-réseau primaire, ou vous pouvez ajouter une plage secondaire au sous-réseau 
et allouer des plages d'alias IP à partir de la plage secondaire.
Pour simplifier, nous utilisons la plage de sous-réseau primaire.

En utilisant Google cli, gcloud, cette action pourrait être effectuée de la manière suivante:
$ gcloud compute instances network-interfaces update <instance_name> --zone=<subnet_zone> --aliases="10.0.0.250/32"

Notez que la commande de suppression des alias est similaire - fournissez simplement un `alias`vide:
$ gcloud compute instances network-interfaces update <instance_name> --zone=<subnet_zone> --aliases=""

Nous utilisons l'API de métadonnées de Google Compute Engine pour récupérer <instance_name> ainsi que <subnet_zone>.

Notez également https://cloud.google.com/vpc/docs/subnets#unusable-ip-addresses-in-every-subnet.

Google Cloud utilise les deux premières et les deux dernières adresses IPv4 de chaque plage d'adresses IPv4 primaires pour héberger le sous-réseau.
Google Cloud vous permet d'utiliser toutes les adresses des plages IPv4 secondaires, c'est-à-dire:
- 10.0.0.0 - Adresse réseau
- 10.0.0.1 - Adresse de la passerelle par défaut
- 10.0.0.254 - Avant-dernière adresse. Réservée pour une utilisation future potentielle
- 10.0.0.255 - Adresse de diffusion

Après avoir ajouté l'adresse de l'Alias IP, vous pouvez vérifier son existence à l'aide de l'utilitaire "ip" :
$ ip route ls table local type local dev eth0 scope host proto 66
local 10.0.0.250
"""

import subprocess
import requests
import re
import time
from google.cloud import compute_v1

ALIAS_IP = "10.0.0.250/32"
METADATA_URL = "http://metadata.google.internal/computeMetadata/v1/"
METADATA_HEADERS = {"Metadata-Flavor": "Google"}
project_path = "project/project-id"
instance_path = "instance/name"
zone_path = "instance/zone"
network_interface = "nic0"
mirror_public_ip_name = "isc-mirror"
access_config_name = "isc-mirror"
mirror_instances = ["isc-primary-001", "isc-backup-001"]


def get_metadata(path: str) -> str:
    return requests.get(METADATA_URL + path, headers=METADATA_HEADERS).text


def get_zone() -> str:
    return get_metadata(zone_path).split('/')[3]


client = compute_v1.InstancesClient()
project = get_metadata(project_path)
availability_zone = get_zone()


def get_ip_address_by_name():
    ip_address = ""
    client = compute_v1.AddressesClient()
    request = compute_v1.ListAddressesRequest(
        project=project,
        region='-'.join(get_zone().split('-')[0:2]),
        filter="name=" + mirror_public_ip_name,
    )
    response = client.list(request=request)
    for item in response:
        ip_address = item.address
    return ip_address


def get_zone_by_instance_name(instance_name: str) -> str:
    request = compute_v1.AggregatedListInstancesRequest()
    request.project = project
    instance_zone = ""
    for zone, response in client.aggregated_list(request=request):
        if response.instances:
            if re.search(f"{availability_zone}*", zone):
                for instance in response.instances:
                    if instance.name == instance_name:
                        return zone.split('/')[1]
    return instance_zone


def update_network_interface(action: str, instance_name: str, zone: str) -> None:
    if action == "create":
        alias_ip_range = compute_v1.AliasIpRange(
            ip_cidr_range=ALIAS_IP,
        )
    nic = compute_v1.NetworkInterface(
        alias_ip_ranges=[] if action == "delete" else [alias_ip_range],
        fingerprint=client.get(
            instance=instance_name,
            project=project,
            zone=zone
        ).network_interfaces[0].fingerprint,
    )
    request = compute_v1.UpdateNetworkInterfaceInstanceRequest(
        project=project,
        zone=zone,
        instance=instance_name,
        network_interface_resource=nic,
        network_interface=network_interface,
    )
    response = client.update_network_interface(request=request)
    print(instance_name + ": " + str(response.status))


def get_remote_instance_name() -> str:
    local_instance = get_metadata(instance_path)
    mirror_instances.remove(local_instance)
    return ''.join(mirror_instances)


def delete_remote_access_config(remote_instance: str) -> None:
    request = compute_v1.DeleteAccessConfigInstanceRequest(
        access_config=access_config_name,
        instance=remote_instance,
        network_interface="nic0",
        project=project,
        zone=get_zone_by_instance_name(remote_instance),
    )
    response = client.delete_access_config(request=request)
    print(response)


def add_access_config(public_ip_address: str) -> None:
    access_config = compute_v1.AccessConfig(
        name = access_config_name,
        nat_i_p=public_ip_address,
    )
    request = compute_v1.AddAccessConfigInstanceRequest(
        access_config_resource=access_config,
        instance=get_metadata(instance_path),
        network_interface="nic0",
        project=project,
        zone=get_zone_by_instance_name(get_metadata(instance_path)),
    )
    response = client.add_access_config(request=request)
    print(response)


# Obtention du nom et de la zone de l'instance d'un autre membre du basculement
remote_instance = get_remote_instance_name()
print(f"Alias IP is going to be deleted at [{remote_instance}]")

# Supprimer l'Alias IP de l'interface réseau d'un membre de basculement distant
#
# TODO : Effectuer les étapes suivantes lorsqu'un problème https://github.com/googleapis/google-cloud-python/issues/11931 sera clôturé:
# - mettre à jour le paquet google-cloud-compute pip vers une version contenant un correctif (>1.15.0)
# - supprimer une ligne ci-dessous appelant gcloud avec un sous-processus subprocess.run()
# - décommenter la fonction update_network_interface()
subprocess.run([
    "gcloud",
    "compute",
    "instances",
    "network-interfaces",
    "update",
    remote_instance,
    "--zone=" + get_zone_by_instance_name(remote_instance),
    "--aliases="
])
# update_network_interface("delete",
#                          remote_instance,
#                          get_zone_by_instance_name(remote_instance)


# Ajouter un Alias IP à l'interface réseau d'un membre du basculement local
update_network_interface("create",
                         get_metadata(instance_path),
                         availability_zone)


# Gérer la commutation IP publique
public_ip_address = get_ip_address_by_name()
if public_ip_address:
    print(f"Public IP [{public_ip_address}] is going to be switched to [{get_metadata(instance_path)}]")
    delete_remote_access_config(remote_instance)
    time.sleep(10)
    add_access_config(public_ip_address)

Démo

Déployons maintenant cette architecture IRIS dans GCP en utilisant Terraform et Ansible. Si vous utilisez déjà IRIS dans GCP ou un autre outil, le script ZMIRROR est disponible ici.

Outils

Nous aurons besoin des outils suivants. Ansible étant réservé à Linux, je recommande vivement de l'exécuter sur Linux, même si j'ai confirmé qu'il fonctionnait également sur Windows dans WSL2.

gcloud:

$ gcloud version
Google Cloud SDK 459.0.0
...

terraform:

$ terraform version
Terraform v1.6.3

python:

$ python3 --version
Python 3.10.12

ansible:

$ ansible --version
ansible [core 2.12.5]
...

ansible-playbook:

$ ansible-playbook --version
ansible-playbook [core 2.12.5]
...

WSL2

Si vous utilisez WSL2 sous Windows, vous devrez redémarrer l'agent ssh en exécutant:

eval `ssh-agent -s`

Il arrive également que l'horloge du WSL ne soit pas synchronisée (lorsque Windows passe en mode veille/hibernation et vice-versa), vous devrez peut-être la synchroniser explicitement:

sudo hwclock -s

Serveurs sans affichage

Si vous utilisez un serveur sans affichage, utilisez gcloud auth login --no-browser pour vous authentifier auprès de GCP.

IaC

Nous nous appuyons sur Terraform et stockons son état dans un espace de stockage en nuage. Voir les détails ci-dessous sur la façon dont ce stockage est créé.

Définition des variables requises

$ export PROJECT_ID=<project_id>
$ export REGION=<region> # For instance, us-west1
$ export TF_VAR_project_id=${PROJECT_ID}
$ export TF_VAR_region=${REGION}
$ export ROLE_NAME=MyTerraformRole
$ export SA_NAME=isc-mirror

Remarque: Si vous souhaitez ajouter une VIP publique qui expose publiquement les ports IRIS Mirror (ce qui n'est pas recommandé), vous pouvez l'activer avec:

$ export TF_VAR_enable_mirror_public_ip=true

Préparation du registre des artefacts

Il est recommandé d'utiliser Google Artifact Registry au lieu de Container Registry. Créons donc d'abord le registre:

$ cd <root_repo_dir>/terraform
$ cat ${SA_NAME}.json | docker login -u _json_key --password-stdin https://${REGION}-docker.pkg.dev
$ gcloud artifacts repositories create --repository-format=docker --location=${REGION} intersystems

Préparation des images Docker

Supposons que les instances de VM n'aient pas accès au dépôt de conteneurs ISC. Mais vous y avez un accès personnel et vous ne voulez pas mettre vos informations d'identification sur les machines virtuelles.

Dans ce cas, vous pouvez extraire les images Docker IRIS du registre de conteneurs ISC et les pousser vers le registre de conteneurs Google auquel les machines virtuelles ont accès:

$ docker login containers.intersystems.com
$ <Put your credentials here>

$ export IRIS_VERSION=2023.2.0.221.0

$ cd docker-compose/iris
$ docker build -t ${REGION}-docker.pkg.dev/${PROJECT_ID}/intersystems/iris:${IRIS_VERSION} .

$ for IMAGE in webgateway arbiter; do \
    docker pull containers.intersystems.com/intersystems/${IMAGE}:${IRIS_VERSION} \
    && docker tag containers.intersystems.com/intersystems/${IMAGE}:${IRIS_VERSION} ${REGION}-docker.pkg.dev/${PROJECT_ID}/intersystems/${IMAGE}:${IRIS_VERSION} \
    && docker push ${REGION}-docker.pkg.dev/${PROJECT_ID}/intersystems/${IMAGE}:${IRIS_VERSION}; \
done

$ docker push ${REGION}-docker.pkg.dev/${PROJECT_ID}/intersystems/iris:${IRIS_VERSION}

Mise en place de la licence IRIS

Mettez le fichier de clé de licence IRIS, iris.key dans <root_repo_dir>/docker-compose/iris/iris.key. Notez qu'une licence doit supporter le Mirroring.

Création d'un rôle Terraform

Ce rôle sera utilisé par Terraform pour gérer les ressources GCP nécessaires:

$ cd <root_repo_dir>/terraform/
$ gcloud iam roles create ${ROLE_NAME} --project ${PROJECT_ID} --file=terraform-permissions.yaml

Remarque: utiliser update pour une utilisation ultérieure:

$ gcloud iam roles update ${ROLE_NAME} --project ${PROJECT_ID} --file=terraform-permissions.yaml

Création d' un compte de service avec le rôle Terraform

$ gcloud iam service-accounts create ${SA_NAME} \
    --description="Terraform Service Account for ISC Mirroring" \
    --display-name="Terraform Service Account for ISC Mirroring"

$ gcloud projects add-iam-policy-binding ${PROJECT_ID} \
    --member="serviceAccount:${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com" \
    --role=projects/${PROJECT_ID}/roles/${ROLE_NAME}

Génération de la clé du compte de service

Générer la clé du compte de service et stocker sa valeur dans une certaine variable d'environnement:

$ gcloud iam service-accounts keys create ${SA_NAME}.json \
    --iam-account=${SA_NAME}@${PROJECT_ID}.iam.gserviceaccount.com

$ export GOOGLE_APPLICATION_CREDENTIALS=<absolute_path_to_root_repo_dir>/terraform/${SA_NAME}.json

Génération d'une paire de clés SSH

Stockez une partie privée localement sous .ssh/isc_mirror et rendez-la visible pour ssh-agent. Mettre une partie publique dans un fichier isc_mirror.pub:

$ ssh-keygen -b 4096 -C "isc" -f ~/.ssh/isc_mirror
$ ssh-add  ~/.ssh/isc_mirror
$ ssh-add -l # Check if 'isc' key is present
$ cp ~/.ssh/isc_mirror.pub <root_repo_dir>/terraform/templates/

Création d'un stockage en nuage

Le stockage dans le nuage est utilisé pour stocker l'état de Terraform à distance. Vous pouvez consulter Store Terraform state in a bucket Cloud Storage comme exemple.

Remarque: Le Cloud Storage créé aura un nom comme isc-mirror-demo-terraform-<project_id>:

$ cd <root_repo_dir>/terraform-storage/
$ terraform init
$ terraform plan
$ terraform apply

Création de ressources avec Terraform

$ cd <root_repo_dir>/terraform/
$ terraform init -backend-config="bucket=isc-mirror-demo-terraform-${PROJECT_ID}"
$ terraform plan
$ terraform apply

Remarque 1: Quatre machines virtuelles seront créées. Une seule d'entre elles a une adresse IP publique et joue le rôle d'hôte bastion. Cette machine est appelée isc-client-001. Vous pouvez trouver l'adresse IP publique de l'instance isc-client-001 en exécutant la commande suivante:

$ export ISC_CLIENT_PUBLIC_IP=$(gcloud compute instances describe isc-client-001 --zone=${REGION}-c --format=json | jq -r '.networkInterfaces[].accessConfigs[].natIP')

Remarque 2: Parfois Terraform échoue avec des erreurs comme:

Failed to connect to the host via ssh: kex_exchange_identification: Connection closed by remote host...

Dans ce cas, essayez de purger un fichier local ~/.ssh/known_hosts:

$ for IP in ${ISC_CLIENT_PUBLIC_IP} 10.0.0.{3..6}; do ssh-keygen -R "[${IP}]:2180"; done

et répétez terraform apply.

Quick test

Accès aux instances miroir IRIS avec SSH

Toutes les instances, à l'exception de isc-client-001, sont créées dans un réseau privé pour augmenter le niveau de sécurité. Mais vous pouvez y accéder en utilisant la fonctionnalité SSH ProxyJump. Obtenez d'abord l'IP publique de isc-client-001:

$ export ISC_CLIENT_PUBLIC_IP=$(gcloud compute instances describe isc-client-001 --zone=${REGION}-c --format=json | jq -r '.networkInterfaces[].accessConfigs[].natIP')

Then connect to, for example, isc-primary-001 with a private SSH key. Remarquez que nous utilisons un port SSH personnalisé, 2180:

$ ssh -i ~/.ssh/isc_mirror -p 2180 isc@10.0.0.3 -o ProxyJump=isc@${ISC_CLIENT_PUBLIC_IP}:2180

Après la connexion, vérifions que le membre miroir principal a un Alias IP:

[isc@isc-primary-001 ~]$ ip route ls table local type local dev eth0 scope host proto 66
local 10.0.0.250

[isc@isc-primary-001 ~]$ ping -c 1 10.0.0.250
PING 10.0.0.250 (10.0.0.250) 56(84) bytes of data.
64 bytes from 10.0.0.250: icmp_seq=1 ttl=64 time=0.049 ms

Accès aux portails de gestion des instances miroir IRIS

Pour ouvrir des instances miroirs des portails de gestion situés dans un réseau privé, nous utilisons SSH Socks Tunneling.

Connectons-nous à l'instance isc-primary-001. Remarquez qu'un tunnel restera en arrière-plan après la prochaine commande:

$ ssh -f -N  -i ~/.ssh/isc_mirror -p 2180 isc@10.0.0.3 -o ProxyJump=isc@${ISC_CLIENT_PUBLIC_IP}:2180 -L 8080:10.0.0.3:8080

Le port 8080, au lieu de l'habituel 52773, est utilisé puisque nous démarrons IRIS avec une passerelle WebGateway dédiée fonctionnant sur le port 8080.

Une fois la connexion établie, ouvrez http://127.0.0.1:8080/csp/sys/UtilHome.csp dans un navigateur. Vous devriez voir un portail de gestion. Les informations d'identification sont typiques : _system/SYS.

La même approche fonctionne pour toutes les instances : primaire (10.0.0.3), de sauvegarde (10.0.0.4) et d'arbitre (10.0.0.5). Établissez d'abord une connexion SSH avec eux.

Test

Connectons-nous à ' isc-client-001`:

$ ssh -i ~/.ssh/isc_mirror -p 2180 isc@${ISC_CLIENT_PUBLIC_IP}

Vérifier la disponibilité du portail de gestion du membre miroir primaire sur l'adresse de l'Alias IP:

$ curl -s -o /dev/null -w "%{http_code}\n" http://10.0.0.250:8080/csp/sys/UtilHome.csp
200

Connectons-nous à 'isc-primary-001' sur une autre console:

$ ssh -i ~/.ssh/isc_mirror -p 2180 isc@10.0.0.3 -o ProxyJump=isc@${ISC_CLIENT_PUBLIC_IP}:2180

Et désactivez l'instance principale actuelle. Remarquez qu'IRIS ainsi que son portail Web s'exécutent dans Docker:

[isc@isc-primary-001 ~]$ docker-compose -f /isc-mirror/docker-compose.yml down

Vérifions à nouveau la disponibilité du portail de gestion du membre miroir sur l'adresse IP Alias à partir de isc-client-001 :

[isc@isc-client-001 ~]$ curl -s -o /dev/null -w "%{http_code}\n" http://10.0.0.250:8080/csp/sys/UtilHome.csp
200

Cela devrait fonctionner car l'Alias IP a été déplacé vers l'instance ' isc-backup-001`:

$ ssh -i ~/.ssh/isc_mirror -p 2180 isc@10.0.0.4 -o ProxyJump=isc@${ISC_CLIENT_PUBLIC_IP}:2180
[isc@isc-backup-001 ~]$ ip route ls table local type local dev eth0 scope host proto 66
local 10.0.0.250

Nettoyage

Suppression de l'infrastructure

$ cd <root_repo_dir>/terraform/
$ terraform init -backend-config="bucket=isc-mirror-demo-terraform-${PROJECT_ID}"
$ terraform destroy

Suppression du registre des artefacts

$ cd <root_repo_dir>/terraform
$ cat ${SA_NAME}.json | docker login -u _json_key --password-stdin https://${REGION}-docker.pkg.dev

$ for IMAGE in iris webgateway arbiter; do \
    gcloud artifacts docker images delete ${REGION}-docker.pkg.dev/${PROJECT_ID}/intersystems/${IMAGE}
done
$ gcloud artifacts repositories delete intersystems --location=${REGION}

Suppression du stockage en nuage

Supprimez le stockage en nuage où Terraform stocke son état. Dans notre cas, il s'agit d'un isc-mirror-demo-terraform-<project_id>.

Suppression du rôle Terraform

Supprimez le rôle Terraform créé dans Création d'un rôle Terraform.

Conclusion

Et c'est tout! We change networking configuration pointing to a current mirror Primary when the NotifyBecomePrimary event happens.

L'auteur souhaite remercier @Mikhail Khomenko, @Vadim Aniskin, et @Evgeny Shvarov pour le Programme d'idées de la Communauté (Community Ideas Program) qui a rendu cet article possible.

2
0 63
Article Sylvain Guilbaud · Mars 27, 2024 8m read

Si vous exécutez IRIS dans une configuration miroir pour HA dans Azure, la question de la fourniture de Mirror VIP (adresse IP virtuelle) devient pertinente. L'adresse IP virtuel permet aux systèmes en aval d'interagir avec IRIS en utilisant une seule adresse IP. Même en cas de basculement, les systèmes en aval peuvent se reconnecter à la même adresse IP et continuer à fonctionner.

Le principal problème, lors du déploiement sur Azure, est qu'un VIP IRIS doit être essentiellement un administrateur de réseau, conformément aux docs.

Pour obtenir l'HA, les membres du miroir IRIS doivent être déployés dans différentes zones de disponibilité d'un sous-réseau (ce qui est possible dans Azure car les sous-réseaux peuvent s'étendre sur plusieurs zones). L'une des solutions pourrait être les équilibreurs de charge, mais ils coûtent bien sûr plus cher et nécessitent d'être administrés.

Dans cet article, j'aimerais fournir un moyen de configurer un VIP miroir sans utiliser les équilibreurs de charge suggérés dans la plupart des autres architectures de référence Azure.

Architecture

Architecture

Nous avons un sous-réseau qui s'étend sur deux zones de disponibilité (je simplifie ici - bien sûr, vous aurez probablement des sous-réseaux publics, un arbitre dans une autre zone, et ainsi de suite, mais il s'agit d'un minimum absolu suffisant pour démontrer cette approche). La notation CIDR du sous-réseau est 10.0.0.0/24, ce qui signifie que les adresses IP 10.0.0.1 à 10.0.0.255 lui sont allouées. Puisque Azure réserve les quatre premières adresses et la dernière adresse, nous pouvons utiliser 10.0.0.4 à 10.0.0.254.

Nous mettrons en œuvre des VIP publics et privés en même temps. Si vous voulez, vous pouvez implémenter uniquement le VIP privé.

Idée

Les machines virtuelles dans Azure ont des Interfaces réseau. Ces interfaces réseau ont des Configurations IP. La configuration IP est une combinaison d'IP publiques et/ou privées, et elle est acheminée automatiquement vers la Machine virtuelle associée à l'Interface réseau. Il n'est donc pas nécessaire de mettre à jour les routes. Lors d'un basculement de miroir, nous allons supprimer la configuration IP VIP de l'ancien primaire et la créer pour un nouveau primaire. Toutes les opérations nécessaires à cette fin prennent de 5 à 20 secondes pour une IP VIP privée uniquement, de 5 secondes à une minute pour une combinaison d'IP VIP publique/privée.

Mise en œuvre de VIP

  1. Allocation de l'IP externe à utiliser en tant que VIP public. Ignorez cette étape si vous souhaitez uniquement un VIP privé. Si vous attribuez le VIP, il doit résider dans le même groupe de ressources et dans la même région et se trouver dans toutes les zones avec le primaire et le backup. Vous aurez besoin d'un nom IP externe.
  2. Choisissez une valeur VIP privée. J'utiliserai la dernière adresse IP disponible '10.0.0.254'
  3. Sur chaque machine virtuelle, attribuez l'adresse IP VIP privée sur l'interface réseau eth0:1.
cat << EOFVIP >> /etc/sysconfig/network-scripts/ifcfg-eth0:1
          DEVICE=eth0:1
          ONPARENT=on
          IPADDR=10.0.0.254
          PREFIX=32
          EOFVIP
sudo chmod -x /etc/sysconfig/network-scripts/ifcfg-eth0:1
sudo ifconfig eth0:1 up

Si vous voulez juste faire un test, exécutez-le (mais il ne survivra pas au redémarrage du système) :

sudo ifconfig eth0:1 10.0.0.254

Selon le système d'exploitation que vous devrez peut-être exécuter:

ifconfig eth0:1
systemctl restart network
  1. Pour chaque machine virtuelle, activez Identité attribuée au système ou à l'utilisateur.
  2. Pour chaque identité, attribuez les autorisations de modifier les interfaces réseau. Pour ce faire, créez un rôle personnalisé. Dans ce cas, les autorisations minimales sont les suivantes :
{
  "roleName": "custom_nic_write",
  "description": "IRIS Role to assign VIP",
  "assignableScopes": [
    "/subscriptions/{subscriptionid}/resourceGroups/{resourcegroupid}/providers/Microsoft.Network/networkInterfaces/{nicid_primary}",
    "/subscriptions/{subscriptionid}/resourceGroups/{resourcegroupid}/providers/Microsoft.Network/networkInterfaces/{nicid_backup}"
  ],
  "permissions": [
    {
      "actions": [
        "Microsoft.Network/networkInterfaces/write",
        "Microsoft.Network/networkInterfaces/read"
      ],
      "notActions": [],
      "dataActions": [],
      "notDataActions": []
    }
  ]
}

Pour les environnements non productifs, vous pouvez utiliser un rôle système Contributeur réseau sur le groupe de ressources, mais ce n'est pas une approche recommandée car Contributeur réseau est un rôle très large.

  1. Chaque interface réseau dans Azure peut avoir un ensemble de configurations IP. Lorsqu'un membre miroir actuel devient primaire, nous utilisons un callback ZMIRROR pour supprimer une configuration IP VIP sur l'interface réseau d'un autre membre miroir et créer une configuration IP VIP pointant sur lui-même :

Voici les commandes Azure CLI pour les deux nœuds en supposant le groupe de ressources rg, la configuration IP vip et l'IP externe my_vip_ip :

az login --identity
az network nic ip-config delete --resource-group rg --name vip --nic-name mirrorb280_z2
az network nic ip-config create --resource-group rg --name vip --nic-name mirrora290_z1 --private-ip-address 10.0.0.254 --public-ip-address my_vip_ip

et

az login --identity
az network nic ip-config delete --resource-group rg --name vip --nic-name mirrora290_z1
az network nic ip-config create --resource-group rg --name vip --nic-name mirrorb280_z2 --private-ip-address 10.0.0.254 --public-ip-address my_vip_ip

Et le même code qu'une routine ZMIRROR :

ROUTINE ZMIRROR

NotifyBecomePrimary() PUBLIC {
    #include %occMessages
    set rg = "rg"
    set config = "vip"
    set privateVIP = "10.0.0.254"
    set publicVIP = "my_vip_ip"

    set nic = "mirrora290_z1"
    set otherNIC = "mirrorb280_z2"
    if ##class(SYS.Mirror).DefaultSystemName() [ "MIRRORB" {
        // we are on mirrorb node, swap
        set $lb(nic, otherNIC)=$lb(otherNIC, nic)
    }

    set rc1 = $zf(-100, "/SHELL", "export", "AZURE_CONFIG_DIR=/tmp", "&&", "az", "login", "--identity")
    set rc2 = $zf(-100, "/SHELL", "export", "AZURE_CONFIG_DIR=/tmp", "&&", "az", "network", "nic", "ip-config", "delete", "--resource-group", rg, "--name", config, "--nic-name", otherNIC)
    set rc3 = $zf(-100, "/SHELL", "export", "AZURE_CONFIG_DIR=/tmp", "&&", "az", "network", "nic", "ip-config", "create", "--resource-group", rg, "--name", config, "--nic-name",      nic,  "--private-ip-address", privateVIP, "--public-ip-address", publicVIP)
    quit 1
}

La routine est la même pour les deux membres du miroir, nous échangeons simplement les noms des cartes réseau en fonction du nom du membre du miroir actuel. Vous pourriez ne pas avoir besoin du paramètre export AZURE_CONFIG_DIR=/tmp, mais parfois az cherche à écrire les informations d'identification dans le répertoire personnel de la racine, ce qui peut échouer. Au lieu de /tmp, il est préférable d'utiliser le sous-répertoire personnel de l'utilisateur d'IRIS (ou vous pouvez même ne pas avoir besoin de cette variable d'environnement, en fonction de votre configuration).

Et si vous voulez utiliser Embedded Python, voici le code Azure Python SDK:

from azure.identity import DefaultAzureCredential
from azure.mgmt.network import NetworkManagementClient
from azure.mgmt.network.models import NetworkInterface, NetworkInterfaceIPConfiguration, PublicIPAddress

sub_id = "AZURE_SUBSCRIPTION_ID"
client = NetworkManagementClient(credential=DefaultAzureCredential(), subscription_id=sub_id)

resource_group_name = "rg"
nic_name = "mirrora290_z1"
other_nic_name = "mirrorb280_z2"
public_ip_address_name = "my_vip_ip"
private_ip_address = "10.0.0.254"
vip_configuration_name = "vip"


# remove old VIP configuration
nic: NetworkInterface = client.network_interfaces.get(resource_group_name, other_nic_name)
ip_configurations_old_length = len(nic.ip_configurations)
nic.ip_configurations[:] = [ip_configuration for ip_configuration in nic.ip_configurations if
                            ip_configuration.name != vip_configuration_name]

if ip_configurations_old_length != len(nic.ip_configurations):
    poller = client.network_interfaces.begin_create_or_update(
        resource_group_name,
        other_nic_name,
        nic
    )
    nic_info = poller.result()

# add new VIP configuration
nic: NetworkInterface = client.network_interfaces.get(resource_group_name, nic_name)
ip: PublicIPAddress = client.public_ip_addresses.get(resource_group_name, public_ip_address_name)
vip = NetworkInterfaceIPConfiguration(name=vip_configuration_name,
                                      private_ip_address=private_ip_address,
                                      private_ip_allocation_method="Static",
                                      public_ip_address=ip,
                                      subnet=nic.ip_configurations[0].subnet)
nic.ip_configurations.append(vip)

poller = client.network_interfaces.begin_create_or_update(
    resource_group_name,
    nic_name,
    nic
)
nic_info = poller.result()

Lancement initial

NotifyBecomePrimary est aussi appelé automatiquement au démarrage du système (après la reconnexion de miroirs), mais si vous voulez que vos environnements non-miroirs acquièrent VIP de la même manière, utilisez la routine ZSTART:

SYSTEM() PUBLIC {
  if '$SYSTEM.Mirror.IsMember() {
    do NotifyBecomePrimary^ZMIRROR()
  }
  quit 1
}

Conclusion

Et c'est tout! Nous changeons la configuration IP qui pointe vers un miroir primaire actuel lorsque l'événement NotifyBecomePrimary se produit.

0
0 126
Article Benjamin De Boe · Nov 22, 2023 3m read

Nous avons récemment publié un nouveau livre blanc sur l'utilisation de nœuds de reporting (« membres miroir de reporting asynchrone ») dans un environnement miroir. De plus en plus de clients considèrent ce mécanisme comme un moyen simple et rapide de configurer une copie de leurs données de production qui reste à jour, tout en pouvant être utilisée pour des requêtes analytiques ou des charges de travail de reporting lourdes sans impact sur le système source. Lisez le livre blanc ici.

Comme toujours, nous sommes curieux de connaître vos propres commentaires sur la manière dont vous avez utilisé cette option de mise en miroir dans votre organisation et si vous avez des idées sur la façon dont nous pouvons la rendre encore plus productive.

0
0 43
Article Lorenzo Scalese · Juin 23, 2023 8m read

Si vous utilisez IRIS dans une configuration miroir pour HA dans AWS, la question de la fourniture d'un Miroir VIP (IP virtuelle) devient pertinente. L'IP virtuelle permet aux systèmes en aval d'interagir avec IRIS en utilisant une seule adresse IP. Même en cas de basculement, les systèmes en aval peuvent se reconnecter à la même adresse IP et continuer à travailler.

Le principal problème, lors du déploiement sur AWS, est qu'un VIP IRIS exige que les deux membres du miroir soient dans le même sous-réseau, d'après les docs :

Pour utiliser un miroir VIP, les deux membres du basculement doivent être configurés dans le même sous-réseau et le VIP doit appartenir au même sous-réseau que l'interface réseau sélectionnée sur chaque système.

Cependant, pour obtenir l'HA, les membres du miroir IRIS doivent être déployés dans des zones de disponibilité différentes, ce qui signifie des sous-réseaux différents (car les sous-réseaux ne peuvent être que dans un seul az). L'une des solutions pourrait être les équilibreurs de charge, mais ils (A) coûtent cher, et (B) si vous devez acheminer du trafic non-HTTP (comme TCP pour HL7), vous devrez utiliser des équilibreurs de charge de réseau avec une limite de 50 ports au total.

Dans cet article, je voudrais fournir un moyen de configurer un Mirror VIP sans utiliser l'équilibrage de la charge du réseau suggéré dans la plupart des autres architectures de référence AWS. En production, nous avons trouvé des limitations qui entravaient les solutions avec le coût, les limites de 50 auditeurs, les dépendances DNS et la nature dynamique des deux adresses IP qu'AWS fournit à travers les zones de disponibilité.

Architecture

Architecture(4)

Nous avons un VPC avec trois sous-réseaux privés (je simplifie ici - bien sûr, vous aurez probablement des sous-réseaux publics, un arbitre dans une autre AZ, et ainsi de suite, mais c'est un minimum absolu suffisant pour démontrer cette approche). Le VPC se voit allouer des IPs : 10.109.10.1 à 10.109.10.254 ; les sous-réseaux (dans différents AZs) sont : 10.109.10.1 à 10.109.10.62, 10.109.10.65 à 10.109.10.126, et 10.109.10.224 à 10.109.10.254.

Implementation d'un VIP

  1. Sur chaque instance EC2 (SourceDestCheck doit être définie sur false), nous allons allouer la même adresse IP sur l'interface réseau eth0:1. Cette adresse IP se trouve dans la plage CIDR du VPC - dans une zone VIP spéciale. Par exemple, nous pouvons utiliser la dernière IP d'une plage - 10.109.10.254 :
cat << EOFVIP >> /etc/sysconfig/network-scripts/ifcfg-eth0:1
          DEVICE=eth0:1
          ONPARENT=on
          IPADDR=10.109.10.254
          PREFIX=27
          EOFVIP
sudo chmod -x /etc/sysconfig/network-scripts/ifcfg-eth0:1
sudo ifconfig eth0:1 up

En fonction du système d'exploitation, vous pouvez avoir besoin d'exécuter :

ifconfig eth0:1
systemctl restart network
  1. En cas de basculement du miroir, mettre à jour la table de routage pour qu'elle pointe vers l'eni sur le nouveau primaire. Nous utiliserons un rappel ZMIRROR pour mettre à jour le tableau de routage après que le membre du miroir actuel soit devenu le primaire. Ce code utilise Python intégré pour :
  • Obtenir l'IP sur eth0:1
  • Obtenir l'InstanceId et la Région à partir des métadonnées de l'instance
  • Trouver le tableau des routes principales pour le VPC EC2
  • Supprimer l'ancienne route, s'il y en a une
  • Ajouter une nouvelle route pointant vers elle-même

Le code:

import os
import urllib.request
import boto3
from botocore.exceptions import ClientError

PRIMARY_INTERFACE = 'eth0'
VIP_INTERFACE = 'eth0:1'

eth0_addresses = [
    line
    for line in os.popen(f'ip -4 addr show dev {PRIMARY_INTERFACE}').read().split('\n')
    if line.strip().startswith('inet')
]

VIP = None
for address in eth0_addresses:
    if address.split(' ')[-1] == VIP_INTERFACE:
        VIP = address.split(' ')[5]

if VIP is None:
    raise ValueError('Échec de la récupération d'un VIP valide !')

# Recherche de l'ID de l'instance du membre du miroir actuel
instanceid = (
    urllib.request.urlopen('http://169.254.169.254/latest/meta-data/instance-id')
    .read()
    .decode()
)

region = (
    urllib.request.urlopen('http://169.254.169.254/latest/meta-data/placement/region')
    .read()
    .decode()
)

session = boto3.Session(region_name=region)
ec2Resource = session.resource('ec2')
ec2Client = session.client('ec2')
instance = ec2Resource.Instance(instanceid)

# Recherche de l'ID du tableau de routage principal pour ce VPC
vpc = ec2Resource.Vpc(instance.vpc.id)

for route_table in vpc.route_tables.all():
    # Mise à jour du tableau de routage principal pour pointer vers cette instance
    try:
        ec2Client.delete_route(
            DestinationCidrBlock=VIP, RouteTableId=str(route_table.id)
        )
    except ClientError as exc:
        if exc.response['Error']['Code'] == 'InvalidRoute.NotFound':
            print('Rien à supprimer, continuer')
        else:
            raise exc
    # Ajout de la nouvelle route
    ec2Client.create_route(
        DestinationCidrBlock=VIP,
        NetworkInterfaceId=instance.network_interfaces[0].id,
        RouteTableId=str(route_table.id),
    )

et le même code comme routine ZMIRROR :

NotifyBecomePrimary() PUBLIC {
  try {
    set dir = $system.Util.ManagerDirectory()_ "python"
    do ##class(%File).CreateDirectoryChain(dir)

    try {
      set boto3 = $system.Python.Import("boto3")
    } catch {
      set cmd = "pip3"
      set args($i(args)) = "install"
      set args($i(args)) = "--target"
      set args($i(args)) = dir
      set args($i(args)) = "boto3"
      set sc = $ZF(-100,"", cmd, .args)
      // pour python précédant la version 3.7, installer également dataclasses
      set boto3 = $system.Python.Import("boto3")
    }
    kill boto3

    set code =  "import os" _ $c(10) _
				"import urllib.request" _ $c(10) _
				"import boto3" _ $c(10) _
				"from botocore.exceptions import ClientError" _ $c(10) _
				"PRIMARY_INTERFACE = 'eth0'" _ $c(10) _
				"VIP_INTERFACE = 'eth0:1'" _ $c(10) _
				"eth0_addresses = [" _ $c(10) _
				"    line" _ $c(10) _
				"    for line in os.popen(f'ip -4 addr show dev {PRIMARY_INTERFACE}').read().split('\n')" _ $c(10) _
				"    if line.strip().startswith('inet')" _ $c(10) _
				"]" _ $c(10) _
				"VIP = None" _ $c(10) _
				"for address in eth0_addresses:" _ $c(10) _
				"    if address.split(' ')[-1] == VIP_INTERFACE:" _ $c(10) _
				"        VIP = address.split(' ')[5]" _ $c(10) _
				"if VIP is None:" _ $c(10) _
				"    raise ValueError('Échec de la récupération d'un VIP valide !')" _ $c(10) _
				"# Recherche de l'ID de l'instance du membre du miroir actuel" _ $c(10) _
				"instanceid = (" _ $c(10) _
				"    urllib.request.urlopen('http://169.254.169.254/latest/meta-data/instance-id')" _ $c(10) _
				"    .read()" _ $c(10) _
				"    .decode()" _ $c(10) _
				")" _ $c(10) _
				"region = (" _ $c(10) _
				"    urllib.request.urlopen('http://169.254.169.254/latest/meta-data/placement/region')" _ $c(10) _
				"    .read()" _ $c(10) _
				"    .decode()" _ $c(10) _
				")" _ $c(10) _
				"session = boto3.Session(region_name=region)" _ $c(10) _
				"ec2Resource = session.resource('ec2')" _ $c(10) _
				"ec2Client = session.client('ec2')" _ $c(10) _
				"instance = ec2Resource.Instance(instanceid)" _ $c(10) _
				"# Recherche de l'ID du tableau de routage principal pour ce VPC" _ $c(10) _
				"vpc = ec2Resource.Vpc(instance.vpc.id)" _ $c(10) _
				"for route_table in vpc.route_tables.all():" _ $c(10) _
				"    # Mise à jour du tableau de routage principal pour pointer vers cette instance" _ $c(10) _
				"    try:" _ $c(10) _
				"        ec2Client.delete_route(" _ $c(10) _
				"            DestinationCidrBlock=VIP, RouteTableId=str(route_table.id)" _ $c(10) _
				"        )" _ $c(10) _
				"    except ClientError as exc:" _ $c(10) _
				"        if exc.response['Error']['Code'] == 'InvalidRoute.NotFound':" _ $c(10) _
				"            print('Rien à supprimer, continuer')" _ $c(10) _
				"        else:" _ $c(10) _
				"            raise exc" _ $c(10) _
				"    # Ajout de la nouvelle route" _ $c(10) _
				"    ec2Client.create_route(" _ $c(10) _
				"        DestinationCidrBlock=VIP," _ $c(10) _
				"        NetworkInterfaceId=instance.network_interfaces[0].id," _ $c(10) _
				"        RouteTableId=str(route_table.id)," _ $c(10) _
				"    )"


    set rc = $system.Python.Run(code)
    set sc = ##class(%SYS.System).WriteToConsoleLog("Attribution VIP " _ $case(rc, 0:"successful", :"error"), , $case(rc, 0:0, :1), "NotifyBecomePrimary:ZMIRROR")

  } catch ex {
    #dim ex As %Exception.General
    do ex.Log()
    set sc = ##class(%SYS.System).WriteToConsoleLog("Une exception a été détectée lors de I'attribution d'un VIP : " _ ex.DisplayString(), , 1, "NotifyBecomePrimary:ZMIRROR")
  }
  quit 1
}

Démarrage initial

NotifyBecomePrimary est aussi appelé automatiquement au démarrage du système (après la reconnexion des miroirs), mais si vous voulez que vos environnements non-miroirs acquièrent VIP de la même manière, utilisez la routine ZSTART routine:

SYSTEM() PUBLIC {
  if '$SYSTEM.Mirror.IsMember() {
    do NotifyBecomePrimary^ZMIRROR()
  }
  quit 1
}

Suppression

Si vous utilisez des outils de provisionnement automatique, comme CloudFormation, cette route doit être supprimée avant de pouvoir supprimer le sous-réseau. Vous pouvez ajouter le code de suppression à ^%ZSTOP, mais n'oubliez pas de vérifier $SYSTEM.Mirror.IsPrimary() parce que lorsque le miroir primaire s'arrête, pendant ^%ZSTOP il est toujours primaire. De manière générale, je recommanderais la suppression des routes externes dans le cadre d'un script d'outils de provisionnement.

Conclusion

Et c'est tout ! Dans le tableau de routage, nous obtenons une nouvelle route pointant vers un miroir primaire Primary actuel lorsque l'événement NotifyBecomePrimary se produit.

image

L'auteur tient à remercier Jared Trog et @sween pour la création de cette approche.

L'auteur tient à remercier @Tomohiro Iwamoto pour avoir testé cette approche et déterminé toutes les conditions requises pour qu'elle fonctionne.

0
0 131
Article Lorenzo Scalese · Mai 17, 2023 16m read

Nos clients ont souvent besoin de configurer HealthShare HealthConnect et IRIS en mode haute disponibilité.

D'autres moteurs d'intégration sur le marché sont souvent présentés comme ayant des configurations de "haute disponibilité", mais ce n'est pas vraiment le cas. En général, ces solutions fonctionnent avec des bases de données externes et donc, si celles-ci ne sont pas configurées en haute disponibilité, lorsqu'un crash de la base de données se produit ou que la connexion à celle-ci est perdue, l'ensemble de l'outil d'intégration devient inutilisable.

Dans le cas des solutions InterSystems, ce problème n'existe pas, car la base de données fait partie intégrante des outils eux-mêmes. Et comment InterSystems a-t-il résolu le problème de la haute disponibilité ? Par des configurations absconses qui pourraient nous entraîner dans une spirale d'aliénation et de folie ? NON ! Chez InterSystems, nous avons écouté et pris en compte vos plaintes (comme nous essayons toujours de le faire ;) ) et nous avons mis la fonction mirroring (mise en miroir) à la disposition de tous nos utilisateurs et développeurs.

Mirroring

Comment fonctionne le Miroir ? Le concept lui-même est très simple. Comme vous le savez déjà, IRIS et HealthShare fonctionnent avec un système de journalisation qui enregistre toutes les opérations de mise à jour des bases de données de chaque instance. Ce système de journalisation est celui qui nous aide à récupérer les instances sans perte de données après un crash. Ces fichiers journaux sont envoyés entre les instances configurées en miroir, ce qui permet aux instances configurées en miroir d'être mises à jour en permanence.

Architecture

Décrivons brièvement l'architecture d'un système configuré en miroir :

  • Deux instances configurées en mode basculement :
    • Nœud actif : reçoit toutes les opérations régulières de lecture/écriture.
    • Nœud passif : en mode lecture, il reçoit de manière synchrone toutes les modifications produites dans le nœud actif.
  • 0-14 instances asynchrones : autant d'instances asynchrones que vous souhaitez utiliser; elles peuvent être de deux types :
    • DR async (reprise après sinistre) : nœuds en mode lecture qui ne font pas partie du basculement, bien qu'ils puissent être transférés manuellement. Si tel est le cas, ils pourraient être automatiquement transférés vers le nœud principal en cas de défaillance des deux autres nœuds de basculement. La mise à jour de vos données se fait en mode asynchrone, leur fraîcheur n'est donc pas garantie.
    • Reporting Asyncs (rapports asynchrones) : Nœuds mis à jour de manière asynchrone pour une utilisation dans des tâches de BI ou d'exploration de données. Ils ne peuvent pas être transférés vers le basculement car des écritures peuvent être effectuées sur les données.
  • ISCAgent : Installé sur chaque serveur où se trouve une instance. Il sera chargé de surveiller l'état des instances de ce serveur. C'est un autre moyen de communication entre les Serveurs Miroirs en plus de la communication directe.
  • Arbiter : il s'agit d'un ISCAgent installé indépendamment par rapport aux serveurs qui composent le Miroir et qui permet d'augmenter la sécurité et le contrôle des bascules au sein de celui-ci en surveillant les ISCAgents installés et les instances d'IRIS/HealthShare. Son installation n'est pas obligatoire.

Il s'agirait du fonctionnement d'un Miroir formé par un basculement avec seulement deux nœuds :

Dans un miroir InterSystems IRIS, lorsque le primaire devient indisponible, le miroir bascule sur le backup.

Avertissement préalable

Le projet associé à cet article n'a pas de licence active permettant la configuration du miroir. Si vous voulez l'essayer, envoyez-moi un email directement ou ajoutez un commentaire en bas de l'article et je vous contacterai.

Déploiement dans Docker

Pour cet article, nous allons mettre en place un petit projet dans Docker qui nous permet de mettre en place 2 instances de basculement avec un Arbiter. Par défaut, les images IRIS disponibles pour Docker ont l'ISCAgent déjà installé et configuré, nous pouvons donc sauter cette étape. Il sera nécessaire de configurer le projet associé à l'article à partir d'un code Visual Studio, car cela nous permettra de travailler plus confortablement avec les fichiers du serveur par la suite.

Voyons quelle forme aurait notre docker-compose.yml :

version:'3.3'services:  arbiter:      container_name:arbiter      hostname:arbiter      image:containers.intersystems.com/intersystems/arbiter:2022.1.0.209.0      init:true      command:        -/usr/local/etc/irissys/startISCAgent.sh2188  mirrorA:    image:containers.intersystems.com/intersystems/iris:2022.1.0.209.0    container_name:mirrorA    depends_on:      -arbiter    ports:    -"52775:52773"    volumes:    -./sharedA:/shared    -./install:/install    -./management:/management    command:      --check-capsfalse      --key/install/iris.key      -a/install/installer.sh    environment:    -ISC_DATA_DIRECTORY=/shared/durable    hostname:mirrorA  mirrorB:    image:containers.intersystems.com/intersystems/iris:2022.1.0.209.0    container_name:mirrorB    depends_on:      -arbiter      -mirrorA    ports:    -"52776:52773"    volumes:    -./sharedB:/shared    -./install:/install    -./management:/management    command:      --check-capsfalse      --key/install/iris.key      -a/install/installer.sh    environment:    -ISC_DATA_DIRECTORY=/shared/durable    hostname:mirrorB

Nous pouvons remarquer que nous avons défini 3 conteneurs :

  • Arbiter : il correspond à l'ISCAgent (même si l'image s'appelle Arbiter) qui sera déployé pour contrôler les instances IRIS qui formeront le Mirror Failover (basculement miroir). Au démarrage du conteneur, il exécutera un fichier shell qui démarrera l'ISCAgent écoutant sur le port 2188 du conteneur.
  • mirrorA : conteneur dans lequel l'image IRIS v.2022.1.0.209 sera déployée et que nous configurerons ultérieurement en tant que nœud de basculement primaire.
  • mirrorB : conteneur dans lequel l'image IRIS v.2022.1.0.209 sera déployée et que nous configurerons ultérieurement en tant que nœud de basculement secondaire.

Lorsque nous exécutons la commande docker-compose up -d, les conteneurs définis seront déployés dans notre Docker, et cela devrait ressembler à ceci dans notre Docker Desktop (si nous le faisons à partir de Windows).

Configuration du miroir.

Avec nos conteneurs déployés, nous allons procéder à l'accès aux instances que nous allons configurer en miroir, la première sera à l'écoute sur le port 52775 (mirrorA) et la seconde sur 52776 (mirrorB). L'utilisateur et le mot de passe d'accès seront superuser / SYS

Du fait que les instances sont déployées dans Docker, nous aurons deux options pour configurer les IP de nos serveurs. La première est d'utiliser directement le nom de nos conteneurs dans la configuration (ce qui est le plus simple) ou de vérifier les IP que Docker a attribuées pour chaque conteneur (en ouvrant la console et en exécutant un ifconfig qui renvoie l'IP attribuée). Pour des raisons de clarté, nous utiliserons pour l'exemple les noms que nous avons donnés à chaque conteneur comme adresse de chacun au sein de Docker.

Tout d'abord, nous allons configurer l'instance que nous utiliserons comme nœud actif du basculement (FailOver). Dans notre cas, ce sera ce que nous avons appelé mirrorA.

La première étape consistera à activer le service de mise en miroir, ce qui nous permettra d'accéder au menu de mise en miroir à partir du portail de gestion : Administration du système --> Configuration --> Paramètres du miroir --> Activer le miroirService et cochez la case Service activé :

Une fois le service activé, nous pouvons commencer à configurer notre nœud actif. Après avoir activé le service, vous pourrez voir que de nouvelles options ont été activées dans le menu Miroir :

Dans ce cas, comme nous n'avons pas de configuration de miroir déjà créée, nous devons en créer une nouvelle avec l'option Créer un miroir. Lorsque nous accédons à cette option, le portail de gestion ouvrira une nouvelle fenêtre à partir de laquelle nous pourrons configurer notre miroir :

Examinons de plus près chacune des options :

  • Nom du miroir : le nom avec lequel nous identifierons notre miroir. Pour notre exemple, nous l'appellerons MIRRORSET. ** Nécessite le SSL/TLS** : pour notre exemple, nous ne configurerons pas de connexion utilisant le SSL/TLS, bien que dans les environnements de production, il serait plus que pratique d'éviter que le fichier journal soit partagé sans aucun type d'encryptage entre les instances. Si vous souhaitez configurer cette connexion, vous avez tous les renseignements nécessaires à l'adresse URL de la documentation.
  • Use Arbiter : cette option n'est pas obligatoire, mais elle est fortement recommandée, car elle ajoute une couche de sécurité à notre configuration de miroir. Pour notre exemple, nous la laisserons cochée et nous indiquerons l'IP dans laquelle nous avons notre Arbiter en cours d'exécution. Pour notre exemple, l'IP sera dans le nom du conteneur arbiter.
  • User Virtual IP : dans les environnements Linux/Unix, cette option est très intéressante car elle nous permet de configurer une IP virtuelle pour notre nœud actif qui sera géré par notre miroir. Cette IP virtuelle doit appartenir au même sous-réseau que les nœuds de basculement. Le fonctionnement de l'IP virtuelle est très simple, en cas de défaillance du nœud actif le miroir configurera automatiquement l'IP virtuelle sur le serveur où se trouve le nœud passif à promouvoir. De cette manière, la promotion du nœud passif en nœud actif sera complètement transparente pour les utilisateurs, puisqu'ils continueront à être connectés à la même IP, même si elle sera configurée sur un serveur différent. Si vous souhaitez en savoir plus sur l'IP virtuelle, vous pouvez consulter cette URL de la documentation.

Le reste de la configuration peut être laissé tel quel. Sur le côté droit de l'écran, nous verrons les renseignements relatifs à ce nœud dans le miroir :

  • Nom du membre du miroir : nom de ce membre du miroir, par défaut il prendra le nom du serveur avec le nom de l'instance.
  • Superserver Address : Adresse IP du super-serveur de ce nœud, dans notre cas, mirrorA.
  • Port de l'agent : port dans lequel l'agent ISCAgent correspondant à ce nœud a été configuré. Par défaut 2188.

Une fois les champs nécessaires configurés, nous pouvons procéder à la sauvegarde du miroir. Nous pouvons vérifier comment la configuration s'est déroulée à partir du moniteur du miroir (Opération du système --> Moniteur du miroir).

Parfait, nous avons notre miroir nouvellement configuré. Comme vous pouvez le constater, seul le nœud actif que nous venons de créer apparaît. Très bien, allons donc ajouter notre nœud passif dans le Failover. Nous accédons au portail de gestion mirrorB et au menu Mirror Settings. Comme nous l'avons déjà fait pour l'instance mirrorA, nous devons activer le service Mirror. Nous répétons l'opération et dès que les options du menu seront mises à jour, nous choisirons Join as Failover (Rejoindre en tant que basculement).

Nous avons ici l'écran de connexion au miroir. Expliquons brièvement la signification de chacun des champs :

  • Nom du miroir : nom que nous avons donné au miroir au moment de sa création, dans notre exemple MIRRORSET.
  • Adresse de l'agent sur l'autre système : IP du serveur où l'ISCAgent du nœud actif est déployé, pour nous ce sera mirrorA.
  • Port de l'agent : port d'écoute de l'ISCAgent du serveur dans lequel nous avons créé le miroir. Par défaut 2188.
  • Nom de l'instance IRIS d'InterSystems : le nom de l'instance IRIS sur le nœud actif. Dans ce cas, il coïncide avec celui du nœud passif, IRIS.

Après avoir enregistré les données du miroir, nous aurons la possibilité de définir les renseignements relatifs au nœud passif que nous sommes en train de configurer. Examinons à nouveau les champs que nous pouvons configurer pour le nœud passif :

  • Nom du membre du miroir : nom que le nœud passif prendra dans le miroir. Par défaut, il est formé par le nom du serveur et de l'instance. Superserver Address : Adresse IP du super-serveur dans notre nœud passif. Dans ce cas mirrorB.
  • Port de l'agent** : port d'écoute de l'agent ISCAgent installé sur le serveur du nœud passif que nous sommes en train de configurer. Par défaut 2188. SSL/TLS Requirement : non configurable dans cet exemple, nous n'utilisons pas SSL/TLS. Adresse privée du miroir : Adresse IP du nœud passif. Comme nous l'avons vu, lors de l'utilisation de Docker, nous pouvons utiliser le nom du conteneur mirrorB. Adresse de l'agent : Adresse IP du serveur où l'ISCAgent est installé. Même chose que précédemment, mirrorB.

Nous enregistrons la configuration comme nous l'avons indiqué et nous retournons au moniteur du miroir pour vérifier que nous avons tout configuré correctement. Nous pouvons visualiser le moniteur du nœud actif dans miroirA et du nœud passif dans miroirB. Examinons les différences entre les deux instances.

Moniteur miroir sur le nœud actif mirrorA :

Moniteur du miroir sur le nœud passif mirrorB:

Comme vous pouvez le constater, les renseignements affichés sont similaires, il s'agit essentiellement de changer l'ordre des membres du basculement. Les options sont également différentes, examinons-en quelques-unes :

  • Nœud actif mirrorA :
    • Set No Failover (Configurer pas de basculement) : empêche l'exécution du basculement dans le cas d'un arrêt de l'une des instances qui en font partie.
    • Demote other member (Démonter l'autre membre) : Supprime l'autre membre du basculement (dans ce cas mirrorB) de la configuration du miroir.
  • Nœud passif mirrorB :
    • Stop Mirror On This Member (Supprimer le miroir sur ce membre) : arrête la synchronisation du miroir sur le membre de basculement (ici mirrorB) : Arrête la synchronisation du miroir sur le nœud passif de basculement.
    • Demote To DR Member (Rétrograder vers le membre DR) : rétrograde ce nœud de la partie du basculement avec sa synchronisation en temps réel vers le mode de reprise après sinistre en mode asynchrone.

Parfait, nous avons déjà nos nœuds configurés, voyons maintenant la dernière étape de notre configuration. Nous avons à décider quelles tableaux feront partie du miroir et à le configurer sur les deux nœuds. Si vous regardez le README.md du projet Open Exchange associé à cet article, vous verrez que nous configurons et déployons deux applications que nous utilisons habituellement pour la formation. Ces applications sont déployées automatiquement lorsque nous démarrons les conteneurs Docker et que les NAMESPACES et les bases de données sont créés par défaut.

La première application est celle de l'entreprises COMPANY qui nous permet de sauvegarder les dossiers des entreprises et la seconde est PHONEBOOK qui nous permet d'ajouter des contacts personnels liés aux entreprises enregistrées, ainsi que des clients.

Ajoutons une entreprise :

Nous allons maintenant créer un contact personnel pour l'entreprise précédente :

Les données relatives à l'entreprise seront enregistrées dans la base de données COMPANY et les données relatives au contact dans PERSONAL, les deux bases de données étant mappées de manière à être accessibles à partir de l'espace de noms PHONEBOOK. Si nous vérifions les tableaux dans les deux nœuds, nous verrons que dans mirrorA nous avons les données de l'entreprise et du contact, mais que dans mirrorB il n'y a toujours rien, ce qui est logique.

Les entreprises enregistrées dans mirrorA:

Très bien, procédons à la configuration des bases de données sur notre miroir. Pour ce faire, depuis notre nœud actif (miroirA), nous accédons à l'écran d'administration des bases de données locales (Administrateur système --> Configuration --> Configuration du système --> Bases de données locales) et nous cliquons sur l'option Ajouter au miroir, nous devons sélectionner dans la liste toutes les bases de données que nous voulons ajouter et lire le message qui s'affiche à l'écran :

Une fois les bases de données ajoutées au miroir à partir du nœud actif, nous avons à faire une sauvegarde de celles-ci ou à copier les fichiers de base de données (IRIS.dat) et à les restaurer sur le nœud passif. Si vous décidez de faire une copie directe des fichiers IRIS.dat, gardez à l'esprit que vous devez figer les écritures dans la base de données à copier, vous pouvez voir les commandes nécessaires dans l'URL de la documentation. Dans notre exemple, il ne sera pas nécessaire de faire une pause, puisque personne d'autre que nous n'écrit dans la base de données.

Avant d'effectuer cette copie des fichiers de la base de données, vérifions l'état du miroir à partir du moniteur du nœud actif :

Examinons le nœud passif :

Comme nous pouvons le voir, depuis le nœud passif nous sommes informés que bien que nous ayons 3 bases de données configurées dans le miroir, la configuration n'a pas encore été faite. N'oublions pas que nous devons démonter les bases de données du nœud passif pour pouvoir effectuer la copie et pour cela nous accéderons depuis le portail de gestion à Configuration du système --> Bases de données et en accédant à chacune d'entre elles nous procéderons à leur démontage.

Parfait ! Bases de données démontées. Accédons au code du projet associé à l'article depuis Visual Studio Code et constatons que nous avons les dossiers où se trouvent les installations IRIS, sharedA pour mirrorA et sharedB pour mirrorB. Accédons aux dossiers où se trouvent les bases de données COMPANY, CUSTOMER et PERSONAL (/sharedA/durable/mgr) et procédons à la copie du fichier IRIS.dat de chaque base de données dans le miroir vers les répertoires appropriés du miroirB (/sharedB/durable/mgr).

Une fois la copie terminée, nous montons à nouveau les bases de données mirrorB et vérifions l'état des bases de données configurées à partir du moniteur du miroir mirrorB :

Bingo ! Notre miroir a reconnu les bases de données et il ne nous reste plus qu'à les activer et les mettre à jour. Pour ce faire, nous allons cliquer sur l'action Activer puis sur Catchup (Rattraper), qui apparaîtra après l'activation. Voyons ce qu'il en est :

PParfait, nos bases de données sont déjà correctement configurées en miroir, si nous consultons la base de données COMPANY nous devrions voir l'enregistrement que nous avons enregistré depuis mirrorA auparavant :

Il est évident que notre base de données COMPANY a l'enregistrement que nous avons saisi précédemment dans mirrorA, nous avons copié l'ensemble de la base de données après tout. Ajoutons une nouvelle société à partir de miroirA que nous appellerons "Une autre société" et interrogeons à nouveau le tableau de la base de données COMPANY :

Le voici. Nous aurons juste à nous assurer que nos bases de données configurées en miroir sont en mode lecture seule pour le nœud passif mirrorB :

Et les voici ! en mode R pour la lecture. Bon, nous avons déjà notre miroir configuré et nos bases de données synchronisées. Dans le cas où nous aurions des productions en cours, ce ne serait pas un problème puisque le miroir se charge automatiquement de les gérer, en les démarrant dans le nœud passif en cas de chute dans le nœud actif.

Merci beaucoup à tous ceux qui ont atteint ce stade ! C'était long, mais j'espère que cela vous sera utile.

0
0 176
Article Lorenzo Scalese · Juil 11, 2022 13m read

Historique

VersionDateChangements
V12022-02-08Version initiale
V1.12022-04-06Génération de certificats avec le fichier sh au lieu de pki-script
Utilisation de variables d'environnement dans des fichiers de configuration

Salut, communauté,

Avez-vous déjà mis en place un environnement miroir ? Dispose-t-il d'un réseau privé, d'une adresse IP virtuelle et d'une configuration SSL ? Après avoir fait cela plusieurs fois, je me suis rendu compte que c'est long, et qu'il y a beaucoup d'actions manuelles nécessaires pour générer des certificats et configurer chaque instance IRIS. C'est une vraie casse-tête pour les personnes qui ont souvent à le faire.

Par exemple, une équipe d'assurance qualité peut avoir besoin de créer un nouvel environnement pour chaque nouvelle version d'application à tester. L'équipe de support peut avoir besoin de créer un environnement pour reproduire un problème complex.

Il faut absolument des outils pour les créer rapidement.

Dans cet article, nous allons créer un exemple pour configurer un miroir avec :

  • Arbitre.
  • Membre primaire.
  • Membre de secours en cas de panne.
  • Membre asynchrone de rapport en lecture-écriture.
  • Configuration SSL pour les transferts de journaux entre les nœuds.
  • Réseau privé pour le miroir.
  • Adresse IP virtuelle.
  • Une base de données en miroir.

schéma du réseau

À première vue, cela semble un peu complexe et nécessite beaucoup de code, mais ne vous inquiétez pas. Il existe des bibliothèques hébergées sur OpenExchange pour effectuer facilement la plupart des opérations.

L'objectif de cet article est de fournir un exemple de manière à l'adapter à vos besoins, mais il ne s'agit pas d'un guide des meilleures pratiques en matière de sécurité. Donc, créons notre sample.

Outils et bibliothèques

  • config-api: Cette bibliothèque sera utilisée pour configurer IRIS. Elle supporte la configuration du mirroring depuis la version 1.1.0. Nous ne donnerons pas une description détaillée de l'utilisation de cette bibliothèque. Un ensemble d'articles existe déjà. ici. En bref, config-api sera utilisé pour créer des fichiers de configuration (format JSON) et les charger facilement.

  • ZPM.

  • Docker.

  • OpenSSL.

Page Github

Vous pouvez trouver tous les fichiers de ressources nécessaires sur iris-mirroring-samples repository.

Préparation de votre système

Clonez le référentiel existant :

clone git https://github.com/lscalese/iris-mirroring-samples
cd iris-mirroring-samples

Si vous préférez créer un échantillon à partir de zéro, au lieu de cloner le référentiel, créez simplement un nouveau répertoire avec des sous-répertoires : backup, et config-files. Télécharger irissession.sh :

mkdir -p iris-mirroring-samples/backup iris-mirroring-samples/config-files
cd  iris-mirroring-samples
wget -O session.sh https://raw.githubusercontent.com/lscalese/iris-mirroring-samples/master/session.sh

Pour éviter le problème "permission denied" plus tard, nous devons créer le groupe irisowner, l'utilisateur irisowner, et changer le groupe du répertoire backup en irisowner

sudo useradd --uid 51773 --user-group irisowner
sudo groupmod --gid 51773 irisowner
sudo chgrp irisowner ./backup

Ce répertoire sera utilisé comme volume pour partager une sauvegarde de la base de données après avoir configuré le premier membre miroir avec les autres nœuds.

Obtention d'une licence IRIS

La mise en miroir n'est pas disponible avec l'édition communautaire d'IRIS. Si vous ne disposez pas encore d'une licence conteneur IRIS valide, connectez-vous au Centre de réponse mondial Worldwide Response Center (WRC) avec vos informations d'identification. Cliquez sur "Actions" --> "Online distribtion" ("Actions" --> "Distribution en ligne"), puis sur le bouton "Evaluations" et sélectionnez "Evaluation License" ("Licence d'évaluation") ; remplissez le formulaire. Copiez votre fichier de licence iris.key dans ce répertoire.

Connexion au Registre des conteneurs d'Intersystems

Pour des raisons pratiques, nous utilisons le Registre des conteneurs d'Intersystems (Intersystems Containers Registry) (ICR) pour extraire les images docker. Si vous ne connaissez pas votre login/mot de passe docker, connectez-vous simplement à SSO.UI.User.ApplicationTokens.cls avec vos informations d'identification WRC, et vous pourrez récupérer votre Token ICR.

docker login -u="YourWRCLogin" -p="YourICRToken" containers.intersystems.com

Création de la base de données myappdata et d'un mapping global

Nous ne créons pas vraiment la base de données myappdata maintenant mais préparons une configuration pour la créer au moment de la construction l'image. Pour cela, nous créons juste un simple fichier au format JSON ; La bibliothèque config-api sera utilisée pour le charger dans les instances IRIS.

Creation du ficher config-files/simple-config.json

{
   "Defaults":{
       "DBDATADIR" : "${MGRDIR}myappdata/",
       "DBDATANAME" : "MYAPPDATA"

   },
   "SYS.Databases":{
       "${DBDATADIR}" : {}
   },
   "Databases":{
       "${DBDATANAME}" : {
           "Directory" : "${DBDATADIR}"
       }
   },
   "MapGlobals":{
       "USER": [{
           "Name" : "demo.*",
           "Database" : "${DBDATANAME}"
       }]
   },
   "Security.Services" : {
       "%Service_Mirror" : {                      /* Activer le service miroir sur cette instance */
           "Enabled" : true
       }
   }
}

Ce fichier de configuration vous permet de créer une nouvelle base de données avec les paramètres par défaut et de faire un global mapping demo.* dans l'espace de noms USER.

Pour plus d'informations sur les capacités du fichier de configuration config-api, consultez l'article ou la page github

Dockerfile

Le Dockerfile est basé sur le modèle existant docker template, mais nous devons faire quelques changements pour créer un répertoire de travail, installer les outils pour utiliser l'IP virtuelle, installer ZPM, etc…

Notre image IRIS est la même pour chaque membre du miroir. Le miroir sera mis en place sur le conteneur en commençant par la configuration correcte selon son rôle (primary, backup, ou report async r\w). Voir les commentaires sur le Dockerfile ci-dessous :

ARG IMAGE=containers.intersystems.com/intersystems/iris:2021.1.0.215.0
# Il n'est pas nécessaire de télécharger l'image depuis WRC. Elle sera tirée de l'ICR au moment de la construction.

FROM $IMAGE

USER root

COPY session.sh /
COPY iris.key /usr/irissys/mgr/iris.key

# /opt/demo sera notre répertoire de travail utilisé pour stocker nos fichiers de configuration et autres fichiers d'installation.
# Installez iputils-arping pour avoir une commande arping.  Nécessaire pour configurer l'IP virtuelle.
# Téléchargez la dernière version de ZPM (ZPM est inclus uniquement dans l'édition communautaire).
RUN mkdir /opt/demo && \
    chown ${ISC_PACKAGE_MGRUSER}:${ISC_PACKAGE_IRISGROUP} /opt/demo && \
    chmod 666 /usr/irissys/mgr/iris.key && \
    apt-get update && apt-get install iputils-arping gettext-base && \
    wget -O /opt/demo/zpm.xml https://pm.community.intersystems.com/packages/zpm/latest/installer

USER ${ISC_PACKAGE_MGRUSER}

WORKDIR /opt/demo

# Définissez le rôle du miroir par défaut comme assistant.
# La valeur sera remplacée dans le fichier docker-compose au moment de l'exécution.
ARG IRIS_MIRROR_ROLE=master

# Copiez le contenu du répertoire config-files dans /opt/demo.
# Actuellement, nous n'avons créé qu'un simple-config pour configurer notre base de données et le mapping global.
# Plus tard dans cet article, nous ajouterons d'autres fichiers de configuration pour mettre en place le miroir.
ADD config-files .

SHELL [ "/session.sh" ]

# Installez ZPM
# Utilisez ZPM pour installer config-api
# Chargez le fichier simple-config.json avec config-api pour :
# - créer la base de données "myappdata",
# - ajouter un mapping global dans l'espace de nom "USER" pour la globale "demo.*" sur la base de données "myappdata".
# Fondamentalement, le point d'entrée pour installer votre application ObjectScript est ici.
# Pour cet exemple, nous allons charger simple-config.json pour créer une base de données simple et un mapping global.
RUN \
Do $SYSTEM.OBJ.Load("/opt/demo/zpm.xml", "ck") \
zpm "install config-api" \
Set sc = ##class(Api.Config.Services.Loader).Load("/opt/demo/simple-config.json")

# Copiez le script d'initialisation du miroir.
COPY init_mirror.sh /

Construction de l'image IRIS

Le Dockerfile est prêt ; nous pouvons construire l'image :

docker build --no-cache --tag mirror-demo:latest .

Cette image sera utilisée pour exécuter les nœuds primary, backup et de report async.

The .env file

Les fichiers de configuration JSON et docker-compose utilisent des variables d'environnement.
Leurs valeurs sont stockées dans un fichier nommé .env, pour ce sample notre fichier env est :

APP_NET_SUBNET=172.16.238.0/24
MIRROR_NET_SUBNET=172.16.220.0/24

IRIS_HOST=172.16.238.100
IRIS_PORT=1972
IRIS_VIRTUAL_IP=172.16.238.100

ARBITER_IP=172.16.238.10

MASTER_APP_NET_IP=172.16.238.20
MASTER_MIRROR_NET_IP=172.16.220.20

BACKUP_APP_NET_IP=172.16.238.30
BACKUP_MIRROR_NET_IP=172.16.220.30

REPORT_APP_NET_IP=172.16.238.40
REPORT_MIRROR_NET_IP=172.16.220.40

Préparation du fichier de configuration du premier membre du miroir

La bibliothèque config-api permet de configurer un miroir, nous devons donc créer un fichier de configuration dédié au premier membre du miroir : config-files/mirror-master.json

Pour plus de commodité, les commentaires sont situés directement dans le JSON. Vous pouvez télécharger le fichier [mirror-master.json sans commentaire ici] (https://raw.githubusercontent.com/lscalese/iris-mirroring-samples/master/config-files/mirror-master.json).

{
    "Security.Services" : {
        "%Service_Mirror" : {
            "Enabled" : true
        }
    },
    "SYS.MirrorMaster" : {
        "Demo" : {
            "Config" : {
                "Name" : "Demo",                                /* Le nom de notre miroir */
                "SystemName" : "master",                        /* Le nom de cette instance dans le miroir */
                "UseSSL" : true,                
                "ArbiterNode" : "${ARBITER_IP}|2188",           /* L'adresse IP et port du nœud arbitre */
                "VirtualAddress" : "${IRIS_VIRTUAL_IP}/24",     /* L'adresse IP virtuelle */
                "VirtualAddressInterface" : "eth0",             /* L'interface réseau utilisée pour l'adresse IP virtuelle. */
                "MirrorAddress": "${MASTER_MIRROR_NET_IP}",     /* L'adresse IP de ce noeud dans le réseau miroir privé */
                "AgentAddress": "${MASTER_APP_NET_IP}"          /* L'adresse IP de ce nœud (l'agent est installé sur la même machine) */
            },
            "Databases" : [{                                    /* La liste des bases de données à ajouter au miroir */
                "Directory" : "/usr/irissys/mgr/myappdata/",
                "MirrorDBName" : "MYAPPDATA"
            }],
            "SSLInfo" : {                                       /* SSL Configuration */
                "CAFile" : "/certificates/CA_Server.cer",
                "CertificateFile" : "/certificates/master_server.cer",
                "PrivateKeyFile" : "/certificates/master_server.key",
                "PrivateKeyPassword" : "",
                "PrivateKeyType" : "2"
            }
        }
    }
}

Préparer le fichier de configuration du membre de basculement

Créer un fichier de configuration pour le membre backup (basculement) config-files/mirror-backup.json.

Le fichier est fort ressemblant au fichier de configuration du membre primary:

{
    "Security.Services" : {
        "%Service_Mirror" : {
            "Enabled" : true
        }
    },
    "SYS.MirrorFailOver" : {
        "Demo" : {                                          /* Le miroir à rejoindre */
            "Config": {
                "Name" : "Demo",
                "SystemName" : "backup",                    /* Le nom de cette instance dans le miroir */
                "InstanceName" : "IRIS",                    /* Le nom de l'instance IRIS du premier membre du miroir */
                "AgentAddress" : "${MASTER_APP_NET_IP}",    /* L'adresse IP de l'agent du premier membre du miroir */
                "AgentPort" : "2188",
                "AsyncMember" : false,
                "AsyncMemberType" : ""
            },  
            "Databases" : [{                                /* DB dans le miroir */
                 "Directory" : "/usr/irissys/mgr/myappdata/"    
            }],
            "LocalInfo" : {
                "VirtualAddressInterface" : "eth0",         /* L'interface réseau utilisée pour l'adresse IP virtuelle */
                "MirrorAddress": "${BACKUP_MIRROR_NET_IP}"  /* L'adresse IP de ce noeud dans le réseau miroir privé */
            },
            "SSLInfo" : {
                "CAFile" : "/certificates/CA_Server.cer",
                "CertificateFile" : "/certificates/backup_server.cer",
                "PrivateKeyFile" : "/certificates/backup_server.key",
                "PrivateKeyPassword" : "",
                "PrivateKeyType" : "2"
            }
        }
    }
}

Préparation du fichier de configuration des membres asynchrones en lecture-écriture

Il est assez similaire au fichier de configuration de basculement backup. Les différences sont les valeurs de AsyncMember, AsyncMemberType, et MirrorAddress. Créez le fichier ./config-files/mirror-report.json :

{
    "Security.Services" : {
        "%Service_Mirror" : {
            "Enabled" : true
        }
    },
    "SYS.MirrorFailOver" : {
        "Demo" : {
            "Config": {
                "Name" : "Demo",
                "SystemName" : "report",
                "InstanceName" : "IRIS",
                "AgentAddress" : "${MASTER_APP_NET_IP}",
                "AgentPort" : "2188",
                "AsyncMember" : true,
                "AsyncMemberType" : "rw"
            },
            "Databases" : [{
                 "Directory" : "/usr/irissys/mgr/myappdata/"
            }],
            "LocalInfo" : {
                "VirtualAddressInterface" : "eth0",
                "MirrorAddress": "${REPORT_MIRROR_NET_IP}"
            },
            "SSLInfo" : {
                "CAFile" : "/certificates/CA_Server.cer",
                "CertificateFile" : "/certificates/report_server.cer",
                "PrivateKeyFile" : "/certificates/report_server.key",
                "PrivateKeyPassword" : "",
                "PrivateKeyType" : "2"
            }
        }
    }
}

Génération des certificats et configuration des nœuds IRIS et

Tous les fichiers de configuration sont prêts !

Maintenant nous devons ajouter un script pour générer des certificats afin de sécuriser la communication entre chaque nœud. Un script prêt à l'emploi est disponible dans le repository gen-certificates.sh

# sudo est nécessaire en raison de l'utilisation de chown, chgrp chmod.
sudo ./gen-certificates.sh

Pour configurer chaque nœud, init_mirror.sh sera exécuté au démarrage des conteneurs. Il sera configuré plus tard dans docker-compose.yml dans la section commande command : ["-a", "/init_mirror.sh"] :

#!/bin/bash

# Base de données utilisée pour tester le miroir.
DATABASE=/usr/irissys/mgr/myappdata

# Répertoire contenant mes données d'application sauvegardées par l'assistant pour les restaurer sur les autres nœuds et en faire un miroir.
BACKUP_FOLDER=/opt/backup

# Fichier de configuration miroir au format json config-api pour le nœud d'assistant.
MASTER_CONFIG=/opt/demo/mirror-master.json

# Fichier de configuration miroir au format json config-api pour le nœud de sauvegarde.
BACKUP_CONFIG=/opt/demo/mirror-backup.json

# Fichier de configuration miroir au format json config-api pour le nœud asynchrone de rapport.
REPORT_CONFIG=/opt/demo/mirror-report.json

# Nom du miroir...
MIRROR_NAME=DEMO

# Liste des membres du miroir.
MIRROR_MEMBERS=BACKUP,REPORT

# Chargement de la configuration du miroir en utilisant config-api avec le fichier /opt/demo/simple-config.json.
# Démarrage d'une tâche Job pour accepter automatiquement d'autres membres nommés "backup" et "report" pour rejoindre le miroir (éviter la validation manuelle dans la gestion du portail).
master() {
rm -rf $BACKUP_FOLDER/IRIS.DAT
envsubst < ${MASTER_CONFIG} > ${MASTER_CONFIG}.resolved
iris session $ISC_PACKAGE_INSTANCENAME -U %SYS <<- END
Set sc = ##class(Api.Config.Services.Loader).Load("${MASTER_CONFIG}.resolved")
Set ^log.mirrorconfig(\$i(^log.mirrorconfig)) = \$SYSTEM.Status.GetOneErrorText(sc)
Job ##class(Api.Config.Services.SYS.MirrorMaster).AuthorizeNewMembers("${MIRROR_MEMBERS}","${MIRROR_NAME}",600)
Hang 2
Halt
END
}

make_backup() {
iris session $ISC_PACKAGE_INSTANCENAME -U %SYS "##class(SYS.Database).DismountDatabase(\"${DATABASE}\")"
md5sum ${DATABASE}/IRIS.DAT
cp ${DATABASE}/IRIS.DAT ${BACKUP_FOLDER}/IRIS.TMP
mv ${BACKUP_FOLDER}/IRIS.TMP ${BACKUP_FOLDER}/IRIS.DAT
chmod 777 ${BACKUP_FOLDER}/IRIS.DAT
iris session $ISC_PACKAGE_INSTANCENAME -U %SYS "##class(SYS.Database).MountDatabase(\"${DATABASE}\")"
}

# Restauration de la base de données miroir "myappdata".  Cette restauration est effectuée sur le noeud "backup" et "report".
restore_backup() {
sleep 5
while [ ! -f $BACKUP_FOLDER/IRIS.DAT ]; do sleep 1; done
sleep 2
iris session $ISC_PACKAGE_INSTANCENAME -U %SYS "##class(SYS.Database).DismountDatabase(\"${DATABASE}\")"
cp $BACKUP_FOLDER/IRIS.DAT $DATABASE/IRIS.DAT
md5sum $DATABASE/IRIS.DAT
iris session $ISC_PACKAGE_INSTANCENAME -U %SYS "##class(SYS.Database).MountDatabase(\"${DATABASE}\")"
}

# Configuration du membre "backup"
#  - Chargement du fichier de configuration /opt/demo/mirror-backup.json si cette instance est le backup ou
#    /opt/demo/mirror-report.json si cette instance est le rapport (nœud miroir asynchrone R\W).
other_node() {
sleep 5
envsubst < $1 > $1.resolved
iris session $ISC_PACKAGE_INSTANCENAME -U %SYS <<- END
Set sc = ##class(Api.Config.Services.Loader).Load("$1.resolved")
Halt
END
}

if [ "$IRIS_MIRROR_ROLE" == "master" ]
then
  master
  make_backup
elif [ "$IRIS_MIRROR_ROLE" == "backup" ]
then
  restore_backup
  other_node $BACKUP_CONFIG
else
  restore_backup
  other_node $REPORT_CONFIG
fi

exit 0

Fichier Docker-compose

Nous avons quatre conteneurs pour commencer. Un fichier Docker-compose est parfait pour orchestrer notre sample.

version: '3.7'

services:
  arbitre:
    image: containers.intersystems.com/intersystems/arbiter:2021.1.0.215.0
    init: true
    container_name: mirror-demo-arbiter
    commande:
      - /usr/local/etc/irissys/startISCAgent.sh 2188
    réseaux:
      app_net:
        ipv4_address: ${ARBITER_IP}
    extra_hosts:
      - "master:${MASTER_APP_NET_IP}"
      - "backup:${BACKUP_APP_NET_IP}"
      - "report:${REPORT_APP_NET_IP}"
    cap_add:
      - NET_ADMIN

  assistant:
    construction: .
    image: mirror-demo
    container_name: mirror-demo-master
    réseaux:
      app_net:
        ipv4_address: ${MASTER_APP_NET_IP}
      mirror_net:
        ipv4_address: ${MASTER_MIRROR_NET_IP}
    environnement:
      - IRIS_MIRROR_ROLE=master
      - WEBGATEWAY_IP=${WEBGATEWAY_IP}
      - MASTER_APP_NET_IP=${MASTER_APP_NET_IP}
      - MASTER_MIRROR_NET_IP=${MASTER_MIRROR_NET_IP}
      - ARBITER_IP=${ARBITER_IP}
      - IRIS_VIRTUAL_IP=${IRIS_VIRTUAL_IP}
    ports:
      - 81:52773
    volumes:
      - ./backup:/opt/backup
      - ./init_mirror.sh:/init_mirror.sh
      # Montage des certificats
      - ./certificates/master_server.cer:/certificates/master_server.cer
      - ./certificates/master_server.key:/certificates/master_server.key
      - ./certificates/CA_Server.cer:/certificates/CA_Server.cer
      #- ~/iris.key:/usr/irissys/mgr/iris.key
    nom de l'hôte: master
    extra_hosts:
      - "backup:${BACKUP_APP_NET_IP}"
      - "report:${REPORT_APP_NET_IP}"
    cap_add:
      - NET_ADMIN
    commande: ["-a", "/init_mirror.sh"]

  sauvegarde:
    image: mirror-demo
    container_name: mirror-demo-backup
    réseaux:
      app_net:
        ipv4_address: ${BACKUP_APP_NET_IP}
      mirror_net:
        ipv4_address: ${BACKUP_MIRROR_NET_IP}
    ports:
      - 82:52773
    environnement :
      - IRIS_MIRROR_ROLE=backup
      - WEBGATEWAY_IP=${WEBGATEWAY_IP}
      - BACKUP_MIRROR_NET_IP=${BACKUP_MIRROR_NET_IP}
      - MASTER_APP_NET_IP=${MASTER_APP_NET_IP}
      - BACKUP_APP_NET_IP=${BACKUP_APP_NET_IP}
    volumes:
      - ./backup:/opt/backup
      - ./init_mirror.sh:/init_mirror.sh
      # Montage des certificats
      - ./certificates/backup_server.cer:/certificates/backup_server.cer
      - ./certificates/backup_server.key:/certificates/backup_server.key
      - ./certificates/CA_Server.cer:/certificates/CA_Server.cer
      #- ~/iris.key:/usr/irissys/mgr/iris.key
    nom de l'hôte: backup
    extra_hosts:
      - "master:${MASTER_APP_NET_IP}"
      - "report:${REPORT_APP_NET_IP}"
    cap_add:
      - NET_ADMIN
    commande: ["-a", "/init_mirror.sh"]

  rapport :
    image: mirror-demo
    container_name: mirror-demo-report
    réseaux:
      app_net:
        ipv4_address: ${REPORT_APP_NET_IP}
      mirror_net:
        ipv4_address: ${REPORT_MIRROR_NET_IP}
    ports:
      - 83:52773
    environnement :
      - IRIS_MIRROR_ROLE=report
      - WEBGATEWAY_IP=${WEBGATEWAY_IP}
      - MASTER_APP_NET_IP=${MASTER_APP_NET_IP}
      - REPORT_MIRROR_NET_IP=${REPORT_MIRROR_NET_IP}
      - REPORT_APP_NET_IP=${REPORT_APP_NET_IP}
    volumes:
      - ./backup:/opt/backup
      - ./init_mirror.sh:/init_mirror.sh
      # Montage des certificats
      - ./certificates/report_server.cer:/certificates/report_server.cer
      - ./certificates/report_server.key:/certificates/report_server.key
      - ./certificates/CA_Server.cer:/certificates/CA_Server.cer
      #- ~/iris.key:/usr/irissys/mgr/iris.key
    nom de l'hôte: report
    extra_hosts:
      - "master:${MASTER_APP_NET_IP}"
      - "backup:${BACKUP_APP_NET_IP}"
    cap_add:
      - NET_ADMIN
    commande: ["-a", "/init_mirror.sh"]

réseaux:
  app_net:
    ipam:
      driver: default
      config:
        - subnet: "${APP_NET_SUBNET}"
  mirror_net:
    ipam:
      driver: default
      config:
        - subnet: "${MIRROR_NET_SUBNET}"

Le fichier docker-compose.yml contient beaucoup de variables d'environnement. Pour voir le fichier résolu, tapez dans le terminal :

docker-compose config

Exécuter des conteneurs

docker-compose up

Attendez que chaque instance ait un statut de miroir correct :

  • nœud primary avec le statut Primary.
  • nœud backup avec le statut Backup.
  • noeud report avec le statut Connected.

Enfin, vous devriez voir ces messages dans les journaux de docker :

mirror-demo-master | 01/09/22-11:02:08:227 (684) 1 [Utility.Event] Devient le serveur miroir primaire
...
mirror-demo-backup | 01/09/22-11:03:06:398 (801) 0 [Utility.Event] Trouver MASTER comme primaire, devenant sauvegarde
...
mirror-demo-report | 01/09/22-11:03:10:745 (736) 0 [Generic.Event] MirrorClient : Connecté au primaire : MASTER (ver 4)

Vous pouvez aussi vérifier l'état du miroir avec le portail http://localhost:81/csp/sys/utilhome.csp

État-miroir

Accès aux portails

Dans Docker-compose, nous mappons les ports 81, 82 et 83 pour avoir un accès à chaque portail de gestion. Il s'agit du login/mot de passe par défaut pour toutes les instances :

Test

Vérifiez le moniteur miroir (portail de gestion ; il s'agit de l'utilisateur et du mot de passe par défaut) : http://localhost:81/csp/sys/op/%25CSP.UI.Portal.Mirror.Monitor.zenMiroir-Moniteur

Vérifiez les paramètres du miroir : http://localhost:81/csp/sys/mgr/%25CSP.UI.Portal.Mirror.EditFailover.zen?$NAMESPACE=%25SYS

Miroir-Configuration

Nous pouvons démarrer un test en configurant simplement une globale commençant par demo. Rappelez-vous que nous avons configuré un mapping global demo.* sur l'espace de nom USER.

Ouvrez une session de terminal sur le serveur primaire :

docker exec -it mirror-demo-master irissession iris
Set ^demo.test = $zdt($h,3,1)

Vérifiez si les données sont disponibles sur le nœud de sauvegarde :

docker exec -it mirror-demo-backup irissession iris
Write ^demo.test

Vérifiez si les données sont disponibles sur le nœud de rapport ::

docker exec -it mirror-demo-report irissession iris
Write ^demo.test

Bien ! Nous avons un environnement miroir prêt, entièrement créé par programmation. Pour que ce soit un peu plus complet, il faudrait ajouter une passerelle web avec https et un cryptage entre la passerelle web et IRIS, mais nous allons laisser cela pour le prochain article.

Nous espérons que cet article vous sera utile si vous décidez de créer votre propre script

Source

Le contenu de cet article est inspiré par :

0
0 169