Service Fabric : Déployer sur un cluster multi-nodes

JUIN6


Lorsque vous créez des clusters Service Fabric il est possible de mettre en place plusieurs types de nœuds. Il y a plusieurs raisons pour lesquelles vous voulez faire ça qui peuvent être entre autre les suivantes :

  • Isoler les nœuds primaires contenant les services dédiées Service Fabric
  • Mettre en place une séparation réseau entre vos différents services
  • Avoir plusieurs configurations de serveurs : Beaucoup de CPU, Beaucoup de RAM, GPU,...


A partir du moment où vous avez créer plusieurs nodes types, il est fortement conseillé de mieux maitriser le déploiement de vos applications sur votre cluster afin qu’elles ne soient pas déployées n’importe où.

Prenons par exemple, un exemple de cluster respectant cette configuration suivante :

  • 2 nodes types
    • AdminNode : Nœuds uniquement pour les services fournis par Microsoft
    • AppNode : Nœuds  pour héberger les services que je développe
  • 1 point d’entrée par type de nœuds.


Passons à notre application, si je prends un service stateless issu du template Visual Studio et que je le déploie tel quel sur mon cluster, j’aurais une valeur d’instance count à –1, c’est-à-dire qu’il sera présent sur tous les noeuds de mon cluster comme on peut le voir ci dessous:

image

Si par ailleurs je provisionne uniquement 3 instances, je n’aurais pas la certitude que mon application soit présente uniquement sur les 3 serveurs qui m’intéressent dans ce cas précis.


Je vais donc rajouter des contraintes de placement à mon application afin d’être sûr qu’elle se déploie uniquement sur les noeuds de type AppNode, pour cela dans le fichier ApplicationManifest.xml, je rajoute la contrainte suivante :

    <Service Name="Web" ServicePackageActivationMode="ExclusiveProcess">
      <StatelessService ServiceTypeName="WebType" InstanceCount="[Web_InstanceCount]">
        <SingletonPartition />
        <PlacementConstraints>(NodeTypeName==AppNode)</PlacementConstraints>
      </StatelessService>
    </Service>

Grâce à cette contrainte de placement, je m’assure que mon service se déploiera uniquement sur mon nodetype AppNode, et je peux laisser sereinement mon InstanceCount à –1.

Ici j’ai décidé de me baser sur les noms des NodeTypes puisque j’ai la maitrise de ceux-ci. Cependant il est possible de se baser sur des métriques personnalisées, pour cela il faut les déclarer sur les différents nodetypes de votre cluster. Il est possible de faire cela de deux manières :

  • A la création de votre cluster, via votre template ARM (donc aussi via un update) en ajoutant ceci à la définition de votre type :

image

  • En mettant à jour le manifest de votre cluster Service Fabric :

image

  • Via le portail Azure comme on peut le voir ci-dessous :

image


Dans un prochain article je vous montrerai comment mettre en place des contraintes de placement sur votre cluster de développement.


Remonter

Service Fabric : Créer un cluster via un template ARM

MAI30

Le but de cet article est de décrypter la création d’un cluster Service Fabric via des templates ARM, et comment utiliser ceux-ci pour créer des cluster multi nodes. Et par ailleurs nous verrons comment mettre en place via ARM un cluster Service Fabric accessible uniquement par des IPs privées ce qui peut être utile si vous souhaitez héberger votre cluster Service Fabric dans un Virtual Network connecté à un site to site ou à un Express Route via du private peering.

Avant de voir le contenu du template ARM, voici les types de ressources dont nous avons besoin au minima pour créer un cluster Service Fabric

  • Virtual Network
  • Storage
  • Public IP Address (si besoin)
  • Load Balancer
  • Virtual Machine Scale Set
  • Service Fabric Cluster

Dans mon cas je veux créer un cluster qui aurait cette typologie réseau suivante :

service fabric multi subnet


Ici, nous allons écrire notre template ARM en partant du début. Et comme bien souvent le début, c’est la création des couches réseaux, c’est souvent elle qui est construite en premier, car la conception de celle-ci, notamment en terme d’adressage IP doit être prévue dans le cas par exemple où on connecte ce VNET via un VPN ou via ExpressRoute, voici ci-dessous la déclaration de mon VNET :

Paramètres :

    "virtualNetwork": {
       "type": "object",
       "defaultValue": {
         "name": "",
         "addressPrefix": "",
         "subnets": [
           {
             "name": "",
             "addressPrefix": ""
           }
         ]
       },
       "metadata": {
         "description": "Virtual Network object"
       }
     },

Par convention, je remets la définition de tous mes paramètres dans les variables, ce qui me permet de faire du contrôle dessus si besoin, ici je fais juste une recopie de ceux-là, la définition de ma source sera la suivante :

    {
       "apiVersion": "2017-10-01",
       "type": "Microsoft.Network/virtualNetworks",
       "name": "[variables('virtualNetwork').name]",
       "location": "[resourceGroup().location]",
       "tags": {
         "displayName": "Virtual Network"
       },
       "properties": {
         "addressSpace": {
           "addressPrefixes": [
             "[variables('virtualNetwork').addressPrefix]"
           ]
         },
         "copy": [
           {
             "name": "subnets",
             "count": "[length(variables('virtualNetwork').subnets)]",
             "input": {
               "name": "[variables('virtualNetwork').subnets[copyIndex('subnets')].name]",
               "properties": {
                 "addressPrefix": "[variables('virtualNetwork').subnets[copyIndex('subnets')].addressPrefix]"
               }
             }
           }
         ]
       }
     },

Si vous avez lu mes derniers articles rien de bien nouveau, à part que j’ai mis les propriétés de mon Virtual Network dans un objet.

Alors bien entendu il est toujours possible d’ajouter dans ce template des définitions de NSG, des déclarations de VNet peering ou même des routes tables, mais pour cet article je n’ai pas besoin de tout ceci.

Dans mon cas d’usage je vais prendre ces paramètres pour exécuter mon script :

    "virtualNetwork": {
       "value": {
         "name": "demo-blog-arm",
         "addressPrefix": "16.0.0.0/20",
         "subnets": [
           {
             "name": "FrontSubnet",
             "addressPrefix": "16.0.0.0/24"
           },
           {
             "name": "MiddleSubnet",
             "addressPrefix": "16.0.1.0/24"
           },
           {
             "name": "BackSubnet",
             "addressPrefix": "16.0.2.0/24"
           },
           {
             "name": "AdminSubnet",
             "addressPrefix": "16.0.3.0/24"
           },
           {
             "name": "GatewaySubnet",
             "addressPrefix": "16.0.15.224/27"
           }
         ]
       }
     },

Rien de bien étonnant dans ce cas-ci, mais on notera tout de même que d’avoir mis un exemple json vide dans la defaultValue de mes objets virtualNetwork et subnets me permet facilement de compléter ce fichier quand je souhaite déployer par exemple depuis Visual Studio. Bien entendu cela peut poser des soucis si on n’est pas assez consciencieux lorsqu’on déploie nos ressources, il serait dommage de laisser une defaultValue contenant notre pseudo schéma, mais bon il s’agit là d’un palliatif au manque de ressource de type jsonObject avec un schéma..


Continuons à déclarer nos ressources, pour cela créons nos comptes de stockage. Pour Service Fabric, je vous conseille de créer au moins 2 comptes de stockage qui ont pour rôle les suivants :

  • Compte de stockage des logs Service Fabric, utile en cas de contact avec le support Microsoft
  • Compte de stockage pour les données issues d’Azure Diagnostics

Rien ne vous en empêche d’en créer plus si cela vous le dit, donc en terme de paramètres nous avons cela :

"storageAccounts": {
   "type": "array",
   "defaultValue": [
     {
       "name": ""
     }
   ],
   "metadata": {
     "description": "Storage Account list"
   }
},
"globalStorageAccountSku": {
   "type": "string",
   "allowedValues": [
     "Standard_LRS",
     "Standard_GRS"
   ],
   "metadata": {
     "description": "Sku for all storage accounts"
   }
}

Rien de bien spécifique dans notre cas, passons maintenant à la déclaration des ressources :

{
   "apiVersion": "2017-10-01",
   "type": "Microsoft.Storage/storageAccounts",
   "name": "[variables('storageAccount')[copyIndex('storageLoop')].name]",
   "location": "[resourceGroup().location]",
   "properties": {
     "encryption": {
       "keySource": "Microsoft.Storage",
       "services": {
         "blob": {
           "enabled": true
         }
       }
     },
     "supportsHttpsTrafficOnly": true
   },
   "kind": "StorageV2",
   "sku": {
     "name": "[variables('globalStorageAccountSku')]"
   },
   "copy": {
     "name": "storageLoop",
     "count": "[length(variables('storageAccount'))]"
   }
}

Comme vous pouvez le voir, par défaut j’active l’encryption rest, et bien entendu j’autorise que les appels via https. Je pourrais bien entendu rajouter des ACL pour n’autoriser que mon Virtual Network déjà créé, mais dans mon cas il faudrait que je rajoute les ips depuis lesquelles je me connecte pour pouvoir accéder à ce Storage.

Pour mon exemple, je vais uniquement créer 2 storage account, le premier pour les Azure Diagnostics, et le deuxième pour les logs Service Fabric, très utile en cas de debug bien avancé sur l’état de santé d’un cluster Service Fabric.

Pour la partie Load Balancer, je vous propose de lire un autre de mes articles qui en parle : http://blog.woivre.fr/blog/2018/2/tips-creation-de-differents-load-balancers-via-des-templates-arm 

Maintenant que les éléments liés au réseau sont créés, on va pouvoir s’attaquer à la définition de notre cluster Service Fabric. Dans mon cas, je ne vais pas créer un template ARM qui peut répondre à toutes les possibilités qu’offre Service Fabric, je vais donc partir sur les éléments suivants :

  • Cluster Windows
  • Sécurité : Utilisation de certificat et de connexion via Azure Active Directory, ce qui suppose que celui-ci soit déjà présent dans le keyvault et que les applications soient déclarées dans l’Active Directory
  • Différents types de noeuds, chaque type de noeud a son sous réseau associé


Commençons par la définition des paramètres :

    "sfCluster": {
       "type": "object",
       "defaultValue": {
         "name": "",
         "security": {
           "osAdminUserName": "",
           "level": "EncryptAndSign",
           "thumbprint": "",
           "store": "",
           "vaultUrl": "",
           "vaultResourceId": "",
           "aad": {
             "tenantId": "",
             "clusterAppId": "",
             "clientAppId": ""
           }
         },
         "managementEndpoint": {
           "Port": "19080",
           "type": "public|private",
           "public": {
             "name": ""
           },
           "private": {
             "ipAddress": ""
           }
         },
         "nodes": [
           {
             "name": "",
             "os": {
               "publisher": "",
               "offer": "",
               "sku": "",
               "version": ""
             },
             "instance": {
               "size": "",
               "count": "",
               "tier": ""
             },
             "applicationPorts": {
               "startPort": "",
               "endPort": ""
             },
             "ephemeralPorts": {
               "startPort": "",
               "endPort": ""
             },
             "fabric": {
               "tcpGatewayPort": "",
               "httpGatewayPort": ""
             },
             "isPrimary": false,
             "instanceCount": "",
             "subnetName": "",
             "loadBalancerName": ""
           }
         ],
         "diagnosticsStoreName": "",
         "supportStoreName": ""
       },
       "metadata": {
         "description": "Service Fabric definition"
       }
     },
     "osAdminPassword": {

       "type": "securestring",
       "metadata": { "description": "Admin password for VMSS"

On notera par ailleurs que j’ai mis la mot de passe dans un champs à part afin de bénéficier de la sécurité mise en place par les paramètres de type securestring.

Le template ARM quant à lui correspond à celui-ci :

    {
       "apiVersion": "2017-07-01-preview",
       "type": "Microsoft.ServiceFabric/clusters",
       "name": "[variables('sfCluster').name]",
       "location": "[resourceGroup().location]",
       "tags": {
         "displayName": "Cluster Service Fabric"
       },
       "dependsOn": [
         "storageLoop",
       ],
       "properties": {
         "addOnFeatures": [
           "DnsService",
           "RepairManager"
         ],
         "certificate": {
           "thumbprint": "[variables('sfCluster').security.thumbprint]",
           "x509StoreName": "[variables('sfCluster').security.store]"
         },
         "azureActiveDirectory": {
           "tenantId": "[variables('sfCluster').security.aad.tenantId]",
           "clusterApplication": "[variables('sfCluster').security.aad.clusterAppId]",
           "clientApplication": "[variables('sfCluster').security.aad.clientAppId]"
         },
         "diagnosticsStorageAccountConfig": {
           "storageAccountName": "[variables('sfCluster').diagnosticsStoreName]",
           "protectedAccountKeyName": "StorageAccountKey1",
           "blobEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', variables('sfCluster').diagnosticsStoreName), '2017-10-01').primaryEndpoints.blob]" ,
           "queueEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', variables('sfCluster').diagnosticsStoreName), '2017-10-01').primaryEndpoints.queue]" ,
           "tableEndpoint": "[reference(concat('Microsoft.Storage/storageAccounts/', variables('sfCluster').diagnosticsStoreName), '2017-10-01').primaryEndpoints.table]"
         },
         "fabricSettings": [
           {
             "parameters": [
               {
                 "name": "ClusterProtectionLevel",
                 "value": "[variables('sfCluster').security.level]"
               }
             ],
             "name": "Security"
           }
         ],
         "managementEndpoint": "[concat('https://', if(equals(variables('sfCluster').managementEndpoint.type, 'public'), reference(concat('Microsoft.Network/publicIPAddresses/', variables('sfCluster').managementEndpoint.public.name, variables('suffix').publicIPAddress), '2017-10-01').dnsSettings.fqdn, variables('sfCluster').managementEndpoint.private.ipAddress), ':', variables('sfCluster').managementEndpoint.port)]",
         "copy": [
           {
             "name": "nodeTypes",
             "count": "[length(variables('sfCluster').nodes)]",
             "input": {
               "name": "[variables('sfCluster').nodes[copyIndex('nodeTypes')].name]",
               "applicationPorts": {
                 "endPort": "[variables('sfCluster').nodes[copyIndex('nodeTypes')].applicationPorts.endPort]",
                 "startPort": "[variables('sfCluster').nodes[copyIndex('nodeTypes')].applicationPorts.startPort]"
               },
               "clientConnectionEndpointPort": "[variables('sfCluster').nodes[copyIndex('nodeTypes')].fabric.tcpGatewayPort]",
               "durabilityLevel": "Bronze",
               "ephemeralPorts": {
                 "endPort": "[variables('sfCluster').nodes[copyIndex('nodeTypes')].ephemeralPorts.endPort]",
                 "startPort": "[variables('sfCluster').nodes[copyIndex('nodeTypes')].ephemeralPorts.startPort]"
               },
               "httpGatewayEndpointPort": "[variables('sfCluster').nodes[copyIndex('nodeTypes')].fabric.httpGatewayPort]",
               "isPrimary": "[variables('sfCluster').nodes[copyIndex('nodeTypes')].isPrimary]",
               "vmInstanceCount": "[variables('sfCluster').nodes[copyIndex('nodeTypes')].instance.count]"
             }
           }
         ],
         "reliabilityLevel": "Bronze",
         "upgradeMode": "Automatic",
         "vmImage": "Windows"
       }
     }

On peut voir que j’utilise le nom de la boucle sur mes comptes de stockage au sein de mes dépendances.

Ici dans mon cas, j’ai choisi de passer les paramètres suivants :

    "sfCluster": {
       "value": {
         "name": "democluster",
         "security": {
           "osAdminUserName": "admin",
           "level": "EncryptAndSign",
           "thumbprint": "### Thumbprint de mon certificat ###",
           "store": "My",
           "vaultUrl": "### URL de mon certificat dans le Keyvault ###",
           "vaultResourceId": "### Resource ID du Vault utilisé ###",
           "aad": {
             "tenantId": "### Mon tenant Id ###",
             "clusterAppId": "### Application Id de l’application native ###",
             "clientAppId": "### Application Id de l’application Web API ###"
           }
         },
         "managementEndpoint": {
           "Port": 19080,
           "type": "private",
           "private": {
             "ipAddress": "16.3.0.4"
           }
         },
         "nodes": [
           {
             "name": "AdminNode",
             "os": {
               "publisher": "MicrosoftWindowsServer",
               "offer": "WindowsServer",
               "sku": "2012-R2-Datacenter",
               "version": "latest"
             },
             "instance": {
               "size": "Standard_D2_V2",
               "count": 3,
               "tier": "Standard"
             },
             "applicationPorts": {
               "startPort": 20000,
               "endPort": 30000
             },
             "ephemeralPorts": {
               "startPort": 49152,
               "endPort": 65534
             },
             "fabric": {
               "tcpGatewayPort": 19000,
               "httpGatewayPort": 19080
             },
             "isPrimary": true,
             "subnetName": "AdminSubnet",
             "loadBalancerName": "admin-private-lb"
           },
           {
             "name": "BackNode",
             "os": {
               "publisher": "MicrosoftWindowsServer",
               "offer": "WindowsServer",
               "sku": "2012-R2-Datacenter",
               "version": "latest"
             },
             "instance": {
               "size": "Standard_D2_V2",
               "count": 3,
               "tier": "Standard"
             },
             "applicationPorts": {
               "startPort": 20000,
               "endPort": 30000
             },
             "ephemeralPorts": {
               "startPort": 49152,
               "endPort": 65534
             },
             "fabric": {
               "tcpGatewayPort": 19000,
               "httpGatewayPort": 19080
             },
             "isPrimary": false,
             "subnetName": "BackSubnet",
             "loadBalancerName": "back-private-lb"
           },
           {
             "name": "MidNode",
             "os": {
               "publisher": "MicrosoftWindowsServer",
               "offer": "WindowsServer",
               "sku": "2012-R2-Datacenter",
               "version": "latest"
             },
             "instance": {
               "size": "Standard_D2_V2",
               "count": 3,
               "tier": "Standard"
             },
             "applicationPorts": {
               "startPort": 20000,
               "endPort": 30000
             },
             "ephemeralPorts": {
               "startPort": 49152,
               "endPort": 65534
             },
             "fabric": {
               "tcpGatewayPort": 19000,
               "httpGatewayPort": 19080
             },
             "isPrimary": false,
             "subnetName": "MiddleSubnet",
             "loadBalancerName": "middle-private-lb"
           },
           {
             "name": "FrontNode",
             "os": {
               "publisher": "MicrosoftWindowsServer",
               "offer": "WindowsServer",
               "sku": "2012-R2-Datacenter",
               "version": "latest"
             },
             "instance": {
               "size": "Standard_D2_V2",
               "count": 3,
               "tier": "Standard"
             },
             "applicationPorts": {
               "startPort": 20000,
               "endPort": 30000
             },
             "ephemeralPorts": {
               "startPort": 49152,
               "endPort": 65534
             },
             "fabric": {
               "tcpGatewayPort": 19000,
               "httpGatewayPort": 19080
             },
             "isPrimary": false,
             "subnetName": "FrontSubnet",
             "loadBalancerName": "front-public-lb"
           }
         ],
         "diagnosticsStoreName": "diagsfdemoblog",
         "supportStoreName": "logssfdemoblog"
       }
     }


Pour le reste, je vous renvoie vers mon Github qui contient ce template ARM, ainsi qu’un exemple de paramètres si vous souhaitez le réutiliser : https://github.com/wilfriedwoivre/demo-blog/tree/master/ARM/servicefabric-complexcluster


Remonter

Bonne résolution : Prendre soin de son cluster Service Fabric

JANV23

Pour ceux qui ne connaissent pas Service Fabric, il s’agit d’un produit fourni par Microsoft qui permet de mettre en place des architectures micro-services basées soit sur des “Guest Exe”, des containers ou des “reliable service” qui sont dans ce cas présent, des applications développées avec un SDK fourni par l’éditeur.


Ceux qui ont déjà testé Service Fabric dans un cadre projet ont pu voir qu’il est assez magique et rapide de mettre en place des solutions qui fonctionnent toutes seules. Par toutes seules, je veux bien entendu parler de toutes les fonctionnalités “automagiques” qu’offre Service Fabric, comme la répartition automatique des micro-services au sein du cluster, l’auto-healing du cluster, ou encore la gestion des données des différents services stateful.


Maintenant rien n’est vraiment magique si on creuse vraiment comment cela marche, mais ce n’est pas le but de cet article, nous allons voir comment faire en sorte de bien prendre soin de son cluster pour qu’il n’arrive rien d’irrémédiable à celui-ci. Et quand je veux dire rien d’irrémédiable, je parle du moment où vous vous dîtes : “Autant créer un nouveau cluster et rattraper mes données, car l’actuel est bon pour la casse”, bon après vous me direz que cette méthode marche et elle a souvent été éprouvée, mais bon ça n’arrive jamais au bon moment.


Laissez lui de l’air pour que votre cluster s’épanouisse :

A part le fait que cette phrase marche aussi avec un adolescent, il est nécessaire de laisser de l’espace disque sur les différents nœuds de votre cluster pour qu’il puisse effectuer ses opérations sans aucun soucis. Alors grand scoop, Service Fabric a beau être présenté comme du PaaS sur Azure, derrière, vous allez monter un cluster de Virtual Machine Scale Set (moi j’appelle ça du IaaS), le côté PaaS offert par Azure sur votre cluster SF concerne surtout les updates des versions de Service Fabric, les autres fonctionnalités qui sont présentées avec le produit sont les mêmes pour un cluster on premise ou créer à la main sur des Virtual Machine Azure ou AWS ou autre ... Donc ce cluster Scale Set, il faut le bichonner c’est grâce à lui que votre Service Fabric fonctionne, un des éléments à prendre en compte c’est l’espace disque disponible pour vos applications.

Bon vous me direz un disque dur ça ne se remplit pas tout seul, et bien je suis d’accord, tout dépend de votre utilisation de votre cluster. Si on exclu les erreurs courantes d’occupation d’espace disque, comme la génération de fichiers de logs sur le disque local sans mettre en place de politique de purge. Service Fabric peut utiliser l’espace disque pour stocker l’état des services stateful que ce soit vos acteurs ou vos “reliable service”, donc si vous ne supprimez jamais les données locales, il est possible de ne plus avoir d’espace disque si vous avez des acteurs qui gèrent beaucoup de données en disque.

Pour éviter ce problème, il est possible de faire les actions suivantes :

- Supprimer vos acteurs qui ne sont plus utilisés, par exemple ceux qui font des actions temporaires dans un traitement

- Mettre en place une politique de stockage à double niveau, à la fois basée sur le cluster, puis un déchargement sur un Blob Storage (ou autre).

- Mettre en place des alertes sur l’espace disque utilisé afin d’éviter les mauvaises surprises le jour où cela pose problème.


Les disques à monitorer dépendent de l’installation de votre cluster, si vous êtes passé par un template ARM comme celui disponible sur le GitHub de Microsoft (https://github.com/Azure/azure-quickstart-templates/blob/master/service-fabric-secure-cluster-5-node-1-nodetype/azuredeploy.json), vous pouvez voir qu’il y a une propriété nodeDataDrive qui vous permet de positionner les données de votre cluster sur le disque OS ou sur le disque Temp. A noter qu’il est possible de mettre vos données sur le disque Temp sans risque majeur si vos applications sont bien conçues elles sont redondées sur différents nœuds du cluster.


Dans l’hypothèse ou il est trop tard, et que votre cluster est chargé de beaucoup de données, il est parfois possible de supprimer des applications via les API Service Fabric. Cependant, cette opération ne marche pas toujours si votre cluster est vraiment plein. La dernière chance est souvent celle de se connecter au cluster via RDP (ou SSH si c’est un cluster Linux) et de supprimer les dossiers contenant les données liées à la persistance de vos services. J’espère par ailleurs que vous n’arriverez pas à cette solution ultime et brutale.


Les clusters adoptent une démarche démocratique :

Si vous vous êtes intéressé un peu à la notion de cluster, notamment celui de Service Fabric, vous devez savoir qu’il y des nœuds et des composants qu’on ne peut pas supprimer sans y prendre une attention toute particulière. Au sein de Service Fabric, il y a une notion de “Seed Node” que ce soit on-premise ou sur Azure, ces nœuds particuliers hébergent entre autre les applications systèmes servant au bon fonctionnement du cluster, il est donc fortement conseillé de faire en sorte que ces nœuds soient toujours opérationnels. Vous allez me dire que vu que c’est du Service Fabric managé, et que c’est automagique, vous n’avez rien à craindre pour ces nœuds. Et bien non, ce n’est pas le cas, derrière votre cluster il y a un cluster de Virtual Machine Scale Set, et la mauvaise nouvelle c’est que vous y avez accès, donc c’est à vous de le manager et de s’assurer qu’il se porte bien. Vous pouvez voir la liste de vos “Seed Node” dans le cluster manifest, comme on peut le voir ci dessous :

image


A noter que le XML de déclaration de l’infrastructure change entre un cluster “on premise” et un cluster Azure. De même selon le niveau de durabilité de votre cluster, le nombre de vos seed nodes est différents.


Alors je parle de démocratie, puisque toute opération d’infrastructure doit être votée par l’ensemble du chorum que forme l’ensemble de ses Seed Nodes. Un cas concret, si par exemple vous avez perdu un de vos seeds node, et que vous souhaitez mettre à jour votre cluster, celle-ci ne se fera pas.


Alors ce cas là arrive uniquement quand vous faites les opérations suivantes :

- Supprimer un nœud de votre cluster ScaleSet (oui la ressource n’est pas verrouillée par Service Fabric)

- Scale Up / Scale down, il est possible que les nœuds du chorum soient supprimés

- Créer votre cluster Scale Set avec le paramètre overProvision à true, dans ce cas précis lors de la création il crée plus de serveurs que nécessaire, et après il supprime ceux qu’il juge en trop, donc peut être vos nœuds de chorum

- Maltraiter les fichiers Service Fabric situés sur votre cluster, bon là ça devient intentionnel....


Si par hasard, c’est trop tard et que vos “Seed Nodes” sont cassés, vous pouvez envoyer un mail au support Microsoft Azure qui vous dira quasiment à chaque fois qu’il faut recréer votre cluster, ce qui peut être problématique dans le cas où vous vous êtes basé sur un cluster appartenant à un Virtual Network un peu petit et ayant des contraintes d’adressage IP, comme pour un cluster privé.


Pour éviter cela, c’est très simple, il suffit soit de faire grandement attention lorsque vous touchez l’infrastructure sous jacente à votre cluster. Il est possible de totalement protéger votre cluster Scale Set Service Fabric si vous prenez la peine de créer 2 types de nœuds lors de la création de votre cluster, le premier type contiendra les services “systèmes” et le deuxième vos services applicatifs, il faudra bien entendu prendre ceci en compte lors de vos déploiements.


Via le portail Azure, lorsque vous créer votre cluster, vous pouvez faire comme cela :


image


Il est bien entendu possible de faire tout cela en ARM (car après tout qui déploie des ressources Azure depuis le portail Azure ....) Bref à la création, vous aurez 2 clusters Scale Set, à vous de mettre des droits restreints sur le scale set sysnode dans mon cas, et pour preuve :


image

Si vous creusez un peu plus le cluster, vous pourrez voir que les applications systèmes sont toutes dans le scale set “sysnode” à l’exception du DnsService qui est présent sur tous les nœuds.


Bref prenez soin de vos clusters avant que les problèmes surviennent, car ils n’arrivent jamais au bon moment et les résolutions sont soit pas simples à mettre en œuvre, soit assez destructives pour le cluster.


Remonter

© Wilfried Woivré, tous droits réservés juin 2018