
Présentation
Bonne journée à tous. Je suis développeur Python dans une entreprise qui s'occupe de solutions complexes pour automatiser les processus métier, développer pour résoudre des tâches uniques, des analyses et du conseil. Mes responsabilités incluent le développement et la maintenance d'une architecture de microservices. Et aujourd'hui, je voudrais dire comment nous luttons avec les microservices et pourquoi l'unification est si importante pour eux.
Ce n'est un secret pour personne que cette approche du développement de produits séduit de plus en plus le marché. Et plus on s'y plonge, plus il faut ne pas oublier les règles de base pour travailler avec eux. Afin de structurer notre expérience dans l'écriture de produits de microservices, il a été décidé d'écrire une série d'articles sur la manière de généraliser certains aspects du développement à tous les services.
L'une de ces règles est l'unification. Dans notre entreprise, la plupart des produits se composent d'un tas de langages et de technologies hétéroclites. Dans tout ce stand, vous devez réfléchir à la façon de généraliser les principes de base à tous les microservices pour leur support, leur configuration et leur développement pratiques. Ceci sera discuté dans la série de ces articles.
Je demande à tout le monde intéressé par cat.
Le problème
La première chose que vous rencontrez lors du développement d'un service est peut-être ses méthodes de configuration. Dans l'architecture de microservices, ce problème devient encore plus aigu.
Imaginez que vous disposez de deux douzaines de services et que vous devez modifier un paramètre dans chacun. Par exemple, désactivez l'utilisation de CORS. Étant donné que le système est multicomposant et construit sur des microservices, pour une gestion pratique, il est préférable d'utiliser une approche uniforme de la configuration de tous les modules. Par conséquent, vous devez utiliser la même approche lors de la configuration de chaque module.
Vous pouvez dire que le développeur de chaque service devrait le faire, mais que se passe-t-il si toutes vos configurations sont stockées dans le même Kubernetes, où ne peut-on pas donner à tous les développeurs? Les pauvres DevOps seront obligés de passer beaucoup de temps à apprendre les services et leurs méthodes de configuration. Et cette procédure sera répétée avec la mise à jour des services, surtout si quelqu'un veut essayer quelque chose de nouveau dans les paramètres de service. Avec cette approche, l'équipe passera constamment une partie du temps à travailler avec les configurations, sans développer de nouvelles fonctionnalités, corriger les bugs, etc.
Juste pour ce cas, une méthode de configuration générale est requise qui ne sera pas liée à un langage ou une technologie spécifique et vous permettra de configurer tous les services avec des différences minimales dans la structure générale de la configuration. Pour cette tâche, nous avons développé un système de mise en place de «modules» (services) à l'aide de fichiers yaml, la possibilité de stocker des configurations pour différentes étapes (dev / prod / local etc.) et de diviser le tout en différents blocs liés à certaines choses.
Spécification
Vous pouvez parler beaucoup de l'endroit et de la façon de l'utiliser, mais je propose d'aller directement aux spécifications de cette méthode de configuration. Comme on dit, la théorie est bonne et la pratique est encore meilleure.
Configuration requise
Commençons par définir notre système et ses exigences.
- Chaque module est un composant indépendant du conteneur
- Nous pouvons passer des variables d'environnement au conteneur
- Nous ne pouvons pas modifier la configuration à la volée sans redémarrer le service (création d'un nouveau conteneur).
- Toutes les actions de secours (comme le basculement vers la base de données de sauvegarde) sont effectuées en dehors du composant et lui sont transparentes.
Configuration requise pour la méthode de configuration
Décidons maintenant ce que nous voulons voir de notre méthode de configuration afin de satisfaire toutes les exigences.
- Le type du fichier de configuration est le YAML de la structure spécifiée. YAML a été choisi par nous pour plusieurs raisons:
- Possibilité d'écrire des commentaires et une structure pratique, contrairement à JSON
- Capacité à décrire des tableaux contrairement à ENV
- Hors de la boîte peut être utilisé pour l'inclusion de values.yaml dans la barre (Kubernetes)
- Les fichiers de configuration doivent fusionner dans l'arborescence de configuration
- La configuration doit être spécifique à l'étape. Chaque étape a son propre ensemble complet. Ici, il convient de faire quelques réserves pour clarifier:
- Vous ne pouvez pas réutiliser les valeurs des variables d'une autre étape , à l'exception de l'étape par défaut , qui est réservée aux valeurs par défaut.
- Lors du chargement de la configuration, vous devez effectuer une fusion récursive de la couche de configuration à partir de l'étape spécifiée au-dessus des valeurs par défaut avec la priorité de couche de l'étape spécifiée. Les valeurs (tableaux, etc.) ne doivent pas être combinées.
- S'il existe plusieurs fichiers de configuration pour une étape, les clés qu'ils contiennent doivent être fusionnées et, par conséquent, doivent être uniques les unes par rapport aux autres.
- L'étape actuelle utilisée doit être déterminée par la valeur de la variable d'environnement «STAGE». La modification d'une variable dans une instance en cours d'exécution d'un service n'est pas prévue.
- Le chemin absolu vers le répertoire de configuration doit être déterminé par la valeur de la variable d'environnement "CONFIG_PATH". Pour plus de commodité, un repli est possible s'il n'y a pas de variable dans un certain chemin par défaut, ce qui devrait être indiqué dans la documentation du module. Dans ce cas, le chemin spécifié doit être relatif à la racine du répertoire d'application.
Exemples de configuration
Supposons que nous ayons un service qui doit stocker les paramètres de connexion à Postgres, ainsi que certaines informations sur nous-mêmes
Vous devez d'abord définir une configuration pour STAGE = defaults. Nous y décrirons la structure générale et rendrons les données indépendantes du stade.
par défaut
# configuration/defaults/service.yaml defaults: version: 1.0.0 name: "config-example" # configuration/defaults/redis.yaml defaults: redis: host: "host" db: 0 port: 6379 password: "password"
dev
# configuration/dev/redis.yaml dev: redis: host: "localhost" password: "hard_pwd"
Configuration résultante
version: 1.0.0 name: "config-example" redis: host: "localhost" db: 0 port: 6379 password: "hard_pwd"
Conclusions
D'une manière si astucieuse, nous avons résolu le problème de la configuration des services dans notre zoo et avons tout mis en commun. Cet exemple n'est qu'un point de départ et peut être modifié selon les spécificités de votre projet.
Pour ceux qui sont intéressés par cette méthode de configuration sous une forme «nue»:
Nos packages pour différents langages de programmation Pour l'aide à l'écriture devenir un merci spécial à
Roque ,
SMGladkovskiy