Les microservices sont amenés à s’exécuter dans des contextes différents : ils communiquent avec d’autres services, des bases de données ou middlewares qui peuvent varier ou évoluer. Les comportements mêmes des microservices peuvent également différer ou être étendus selon ses paramétrages : c’est la variabilité logicielle.
Les combinaisons de configurations possibles peuvent d’ailleurs croitre rapidement selon les besoins des développeurs ou bien ceux du client. La variabilité est une affaire d’anticipation et il convient de mettre en place de bonnes pratiques pour adresser cette complexité.
Une mauvaise pratique serait de créer une base de code différente par environnements avec des constantes dans le code ou encore de compiler l’application ou une image Docker spécifique à chaque environnement. Ce pattern trouve très vite ses limites à l’échelle notamment dès que l’on souhaite créer une nouvelle configuration.
Une amélioration consiste à utiliser un fichier de configuration (type « project.properties » ou « settings-integ.json »). Mais ces fichiers pourraient être inclus dans un commit par mégarde et leur format est en général fortement lié au framework que vous utilisez. Le risque serait alors de faire fuiter des données sensibles.
Les bonnes pratiques de conception cloud-native encouragent à stocker si possible la configuration dans des variables d’environnement. C’est en effet un standard agnostique au langage ou au système d’exploitation.
Une limite de cette pratique vient de la nature des variables d’environnement : une chaîne de caractère de taille limitée. On pourra alors si besoin utiliser des fichiers de configuration ou au mieux isoler un élément de la configuration concernée dans une variable d’environnement.
Figure 11 – Comparaison entre des configurations « internalisées » et « externalisées »
On pourra aussi étendre l’externalisation en centralisant une ou plusieurs parties de la configuration, en utilisant un serveur de configuration, en montant des volumes, un dépôt git contenant des configurations, ou un Vault pour les valeurs qui doivent être protégées, tout en conservant une base générique.
Les variables d’environnement sont gérées de manière standardisée et peuvent profiter de nombreuses intégrations, telles que les systèmes de CI/CD ou encore les conteneurs ou orchestrateurs comme Kubernetes qui proposent des mécanismes de configuration externalisée : Secrets et ConfigMaps. Notre chaine de facturation BillingLabs tire parti de ce pattern : notre base de code est partagée par plusieurs clients et la configuration externalisée permet de faire varier le comportement et les interconnections avec les services externes en fonction du besoin client. D’autre part, les notions métier sont également configurées de manière externe à travers des bases de données : comptes, taux de TVA, formules... Ces réglages sont utilisés en tant que configuration pour le microservice de calcul de facturation par exemple. Avec ce pattern, nous réduisons le temps d’intégration de BillingLabs à un nouveau S.I. puisque dans de nombreux cas, il suffit de changer la configuration, permettant ainsi aux nouveaux clients d’atteindre plus vite un marché (réduction du Time-To-Market).