BLOG | NGINX

Choisir une stratégie de déploiement de microservices

NGINX-Partie-de-F5-horiz-black-type-RGB
Miniature de Chris Richardson
Chris Richardson
Publié le 10 février 2016

Rédacteur – Cette série d’articles en sept parties est désormais terminée :

  1. Introduction aux microservices
  2. Création de microservices : Utilisation d'une passerelle API
  3. Création de microservices : Communication interprocessus dans une architecture de microservices
  4. Découverte de services dans une architecture de microservices
  5. Gestion des données pilotée par les événements pour les microservices
  6. Choisir une stratégie de déploiement de microservices (cet article)
  7. Refactorisation d'un monolithe en microservices

Vous pouvez également télécharger l'ensemble complet des articles, ainsi que des informations sur la mise en œuvre de microservices à l'aide de NGINX Plus, sous forme d'ebook – Microservices : De la conception au déploiement . Et consultez notre série sur l’ architecture de référence des microservices et la page Solutions de microservices .

Il s'agit du sixième article d'une série sur la création d'applications avec des microservices. Le premier article présente le modèle d’architecture des microservices et discute des avantages et des inconvénients de l’utilisation des microservices. Les articles suivants traitent de différents aspects de l’architecture des microservices : l’utilisation d’une passerelle API , la communication interprocessus , la découverte de services et la gestion des données pilotée par les événements . Dans cet article, nous examinons les stratégies de déploiement de microservices.

Motivations

Le déploiement d’une application monolithique signifie l’exécution de plusieurs copies identiques d’une seule application, généralement volumineuse. Vous provisionnez généralement N serveurs (physiques ou virtuels) et exécutez M instances de l'application sur chacun d'eux. Le déploiement d’une application monolithique n’est pas toujours entièrement simple, mais il est beaucoup plus simple que le déploiement d’une application de microservices.

Une application de microservices regroupe des dizaines voire des centaines de services. Ces services sont développés dans différents langages et frameworks. Chacun fonctionne comme une mini-application avec des exigences spécifiques en matière de déploiement, de ressources, de scalabilité et de surveillance. Par exemple, vous devez exécuter un nombre précis d’instances de chaque service selon la demande. Chaque instance doit aussi bénéficier des ressources CPU, mémoire et E/S adaptées. Le plus complexe, c’est qu’en dépit de cette diversité, vous devez déployer ces services rapidement, de manière fiable et économique.

Il existe quelques modèles de déploiement de microservices différents. Examinons d’abord le modèle d’instances de service multiples par hôte.

Plusieurs instances de service par modèle d'hôte

Une façon de déployer vos microservices consiste à utiliser le modèle Plusieurs instances de service par hôte . Lorsque vous utilisez ce modèle, vous provisionnez un ou plusieurs hôtes physiques ou virtuels et exécutez plusieurs instances de service sur chacun d’eux. À bien des égards, il s’agit de l’approche traditionnelle du déploiement d’applications. Chaque instance de service s’exécute sur un port connu sur un ou plusieurs hôtes. Les machines hôtes sont généralement traitées comme des animaux de compagnie .

Le diagramme suivant montre la structure de ce modèle.

Le modèle d'instances de service multiples par hôte pour le déploiement d'applications basées sur une architecture de microservices

Il existe plusieurs variantes de ce modèle. Une variante consiste à ce que chaque instance de service soit un processus ou un groupe de processus. Par exemple, vous pouvez déployer une instance de service Java en tant qu’application Web sur un serveur Apache Tomcat . Une instance de service Node.js peut être constituée d'un processus parent et d'un ou plusieurs processus enfants.

L’autre variante de ce modèle consiste à exécuter plusieurs instances de service dans le même processus ou groupe de processus. Par exemple, vous pouvez déployer plusieurs applications Web Java sur le même serveur Apache Tomcat ou exécuter plusieurs bundles OSGI dans le même conteneur OSGI.

Le modèle d’instances multiples de services par hôte offre à la fois des avantages et des inconvénients. Son principal atout est une utilisation particulièrement efficace des ressources. Plusieurs instances de service partagent le serveur ainsi que son système d’exploitation. Nous gagnons encore en efficacité lorsque plusieurs instances de service s’exécutent dans un même processus ou groupe de processus, comme plusieurs applications web utilisant le même serveur Apache Tomcat et la même JVM.

Un autre avantage de ce modèle, c'est que vous déployez une instance de service rapidement. Il suffit de copier le service sur un hôte et de le lancer. Pour un service écrit en Java, copiez un fichier JAR ou WAR. Pour d’autres langages, comme Node.js ou Ruby, copiez le code source. Dans tous les cas, le volume de données transféré sur le réseau reste faible.

De plus, en raison de l’absence de frais généraux, le démarrage d’un service est généralement très rapide. Si le service est un processus propre, il vous suffit de le démarrer. Sinon, si le service est l’une des nombreuses instances exécutées dans le même processus de conteneur ou groupe de processus, vous pouvez soit le déployer dynamiquement dans le conteneur, soit redémarrer le conteneur.

Le modèle « Instances multiples de services par hôte » présente des inconvénients importants, malgré son attrait. Un des principaux problèmes est le manque d’isolation entre les instances de service, sauf si chaque instance fonctionne dans un processus séparé. Vous pouvez suivre précisément l’utilisation des ressources de chaque instance, mais vous ne pouvez pas en restreindre la consommation. Une instance mal maîtrisée peut alors monopoliser toute la mémoire ou la CPU de l’hôte.

Aucune isolation n’existe lorsque plusieurs instances de service tournent dans le même processus. Par exemple, toutes ces instances peuvent partager un même tas JVM. Si une instance de service se comporte mal, elle peut rapidement compromettre les autres services dans ce processus. Vous ne pouvez même pas suivre les ressources consommées par chaque instance de service.

Un autre problème important avec cette approche est que l’équipe d’exploitation qui déploie un service doit connaître les détails spécifiques de la manière de le faire. Les services peuvent être écrits dans une variété de langages et de frameworks, il y a donc de nombreux détails que l'équipe de développement doit partager avec les opérations. Cette complexité augmente le risque d’erreurs lors du déploiement.

Comme vous pouvez le constater, malgré sa familiarité, le modèle d’instances de service multiples par hôte présente quelques inconvénients importants. Voyons maintenant d’autres façons de déployer des microservices qui évitent ces problèmes.

Instance de service par modèle d'hôte

Une autre façon de déployer vos microservices est le modèle d’instance de service par hôte . Lorsque vous utilisez ce modèle, vous exécutez chaque instance de service de manière isolée sur son propre hôte. Il existe deux spécialisations différentes de ce modèle : Instance de service par machine virtuelle et instance de service par conteneur.

Instance de service par modèle de machine virtuelle

Lorsque vous utilisez le modèle Instance de service par machine virtuelle , vous regroupez chaque service sous forme d'image de machine virtuelle (VM), telle qu'une AMI Amazon EC2 . Chaque instance de service est une machine virtuelle (par exemple, une instance EC2) lancée à l'aide de cette image de machine virtuelle. Le diagramme suivant montre la structure de ce modèle :

Le modèle d'instance de service par machine virtuelle pour le déploiement d'applications basées sur une architecture de microservices

Il s’agit de l’approche principale utilisée par Netflix pour déployer son service de streaming vidéo. Netflix regroupe chacun de ses services sous forme d'AMI EC2 à l'aide d'Aminator . Chaque instance de service en cours d’exécution est une instance EC2.

Il existe de nombreux outils que vous pouvez utiliser pour créer vos propres machines virtuelles. Vous pouvez configurer votre serveur d'intégration continue (CI) (par exemple, Jenkins ) pour appeler Aminator afin de regrouper vos services sous forme d'AMI EC2. Packer.io est une autre option pour la création automatisée d'images de machines virtuelles. Contrairement à Aminator, il prend en charge une variété de technologies de virtualisation, notamment EC2, DigitalOcean, VirtualBox et VMware.

La société Boxfuse dispose d’un moyen convaincant de créer des images de machines virtuelles, qui surmonte les inconvénients des machines virtuelles que je décris ci-dessous. Boxfuse conditionne votre application Java sous la forme d'une image de machine virtuelle minimale. Ces images sont rapides à créer, démarrent rapidement et sont plus sécurisées car elles exposent une surface d’attaque limitée.

La société CloudNative propose Bakery, une offre SaaS permettant de créer des AMI EC2. Vous pouvez configurer votre serveur CI pour invoquer Bakery après la réussite des tests de votre microservice. The Bakery regroupe ensuite votre service sous forme d'AMI. L'utilisation d'une offre SaaS telle que The Bakery signifie que vous n'avez pas à perdre de temps précieux à configurer l'infrastructure de création d'AMI.

Le modèle d'instance de service par machine virtuelle offre plusieurs avantages. Chaque instance de service fonctionne en totale isolation, ce qui constitue un atout majeur des machines virtuelles. Elle dispose d’un nombre fixé de CPU et de mémoire, sans jamais puiser dans les ressources des autres services.

Un autre avantage du déploiement de vos microservices en tant que machines virtuelles est que vous pouvez tirer parti d’une infrastructure cloud mature. Les clouds tels qu'AWS offrent des fonctionnalités utiles telles que l'équilibrage de charge et la mise à l'échelle automatique.

Un autre grand avantage du déploiement de votre service en tant que machine virtuelle est qu’il encapsule la technologie d’implémentation de votre service. Une fois qu’un service a été empaqueté sous forme de VM, il devient une boîte noire. L’API de gestion de la VM devient l’API de déploiement du service. Le déploiement devient beaucoup plus simple et plus fiable.

Le modèle d'instance de service par machine virtuelle présente toutefois certains inconvénients. L’un d’eux concerne une utilisation des ressources moins efficace. Chaque instance de service requiert une machine virtuelle entière, avec son système d'exploitation, ce qui alourdit significativement la charge. De plus, dans un IaaS public typique, les machines virtuelles ont des tailles fixes, ce qui peut entraîner une sous-utilisation.

De plus, un IaaS public facture généralement les machines virtuelles, qu’elles soient occupées ou inactives. Un IaaS tel qu’AWS offre une mise à l’échelle automatique, mais il est difficile de réagir rapidement aux changements de la demande . Par conséquent, vous devez souvent surprovisionner les machines virtuelles, ce qui augmente le coût du déploiement.

Un autre inconvénient de cette approche est que le déploiement d’une nouvelle version d’un service est généralement lent. Les images de VM sont généralement lentes à créer en raison de leur taille. De plus, les machines virtuelles sont généralement lentes à s’instancier, encore une fois en raison de leur taille. De plus, un système d’exploitation prend généralement un certain temps à démarrer. Notez cependant que cela n’est pas universellement vrai, car des machines virtuelles légères telles que celles construites par Boxfuse existent.

Un autre inconvénient du modèle d’instance de service par machine virtuelle est que vous (ou quelqu’un d’autre dans votre organisation) êtes généralement responsable d’une grande quantité de tâches lourdes et indifférenciées. À moins que vous n'utilisiez un outil tel que Boxfuse qui gère la charge de travail liée à la création et à la gestion des machines virtuelles, cela relève de votre responsabilité. Cette activité nécessaire mais chronophage vous détourne de votre activité principale.

Voyons maintenant une autre façon de déployer des microservices, plus légère mais qui présente néanmoins de nombreux avantages des machines virtuelles.

Instance de service par modèle de conteneur

Quand vous appliquez le modèle Instance de service par conteneur, chaque instance s’exécute dans son propre conteneur. Les conteneurs représentent un mécanisme de virtualisation au niveau du système d’exploitation. Un conteneur regroupe un ou plusieurs processus fonctionnant dans un environnement isolé. Ces processus disposent de leur propre espace de noms pour les ports et leur propre système de fichiers racine. Vous pouvez restreindre la mémoire et les ressources CPU attribuées à un conteneur. Certaines implémentations limitent aussi le débit des opérations d’E/S. Parmi les technologies de conteneurs, on trouve Docker et Solaris Zones.

Le diagramme suivant montre la structure de ce modèle :

Le modèle d'instance de service par conteneur pour le déploiement d'applications basées sur une architecture de microservices

Pour utiliser ce modèle, vous empaquetez votre service sous forme d’image de conteneur. Une image de conteneur est une image de système de fichiers composée des applications et des bibliothèques requises pour exécuter le service. Certaines images de conteneur sont constituées d'un système de fichiers racine Linux complet. D'autres sont plus légers. Pour déployer un service Java, par exemple, vous créez une image de conteneur contenant l’environnement d’exécution Java, peut-être un serveur Apache Tomcat et votre application Java compilée.

Après avoir emballé votre service sous forme d’image logicielle virtuelle, lancez ensuite un ou plusieurs conteneurs. Vous exécutez généralement plusieurs conteneurs sur chaque hôte physique ou virtuel. Vous pouvez utiliser un gestionnaire de cluster comme Kubernetes ou Marathon pour piloter vos conteneurs. Un gestionnaire de cluster considère les hôtes comme un ensemble de ressources. Il détermine où placer chaque conteneur en fonction des ressources nécessaires et de la disponibilité sur chaque hôte.

Le modèle Instance de service par conteneur présente des avantages et des limites. Les conteneurs offrent des bénéfices comparables à ceux des machines virtuelles, en isolant vos instances de service. Vous pouvez facilement suivre les ressources utilisées par chaque conteneur. Comme les machines virtuelles, les conteneurs encapsulent la technologie nécessaire à vos services. L'API de gestion de conteneurs sert aussi pour la gestion de vos services.

Cependant, contrairement aux machines virtuelles, les conteneurs sont une technologie légère. Les images de conteneurs sont généralement très rapides à créer. Par exemple, sur mon ordinateur portable, il ne faut que 5 secondes pour empaqueter une application Spring Boot sous forme de conteneur Docker. Les conteneurs démarrent également très rapidement car il n’y a pas de long mécanisme de démarrage du système d’exploitation. Lorsqu'un conteneur démarre, c'est le service qui s'exécute.

L’utilisation de conteneurs présente certains inconvénients. Bien que l'infrastructure des conteneurs soit en pleine évolution, elle n'est pas aussi mature que celle des machines virtuelles. De plus, les conteneurs ne sont pas aussi sécurisés que les machines virtuelles, car ils partagent le noyau du système d'exploitation hôte.

Un autre inconvénient des conteneurs est que vous êtes responsable de la lourde tâche indifférenciée consistant à administrer les images du conteneur. De plus, à moins que vous n’utilisiez une solution de conteneur hébergée telle que Google Container Engine ou Amazon EC2 Container Service (ECS), vous devez administrer l’infrastructure du conteneur et éventuellement l’infrastructure de machine virtuelle sur laquelle elle s’exécute.

De plus, les conteneurs sont souvent déployés sur une infrastructure avec une tarification par machine virtuelle. Par conséquent, comme décrit précédemment, vous devrez probablement supporter le coût supplémentaire lié au surprovisionnement des machines virtuelles afin de gérer les pics de charge.

Il est fascinant de constater que la frontière entre conteneurs et machines virtuelles tend à s’estomper. Comme indiqué plus tôt, nous construisons et lançons rapidement les machines virtuelles Boxfuse. Le projet Clear Containers crée des machines virtuelles légères. [Éditeur – Début décembre 2017, le développement de Clear Containers s’est poursuivi dans le projet open source Kata Containers.] Vous remarquerez aussi un intérêt croissant pour les unikernels. Docker, Inc. a récemment pris le contrôle de Unikernel Systems.

Il existe également le concept plus récent et de plus en plus populaire du déploiement sans serveur, qui est une approche qui évite le problème du choix entre le déploiement de services dans des conteneurs ou des machines virtuelles. Examinons-le maintenant.

Déploiement sans serveur

AWS Lambda est un exemple de technologie de déploiement sans serveur. Il prend en charge les services Java, Node.js et Python. Pour déployer un microservice, vous le conditionnez sous forme de fichier ZIP et le téléchargez sur AWS Lambda. Vous fournissez également des métadonnées, qui spécifient entre autres le nom de la fonction invoquée pour gérer une demande (également appelée événement). AWS Lambda exécute automatiquement suffisamment d’instances de votre microservice pour gérer les demandes. Vous êtes simplement facturé pour chaque requête en fonction du temps pris et de la mémoire consommée. Bien sûr, le diable est dans les détails et vous verrez bientôt qu’AWS Lambda a des limites. Mais l’idée que ni vous, en tant que développeur, ni personne dans votre organisation n’avez à vous soucier d’un quelconque aspect des serveurs, des machines virtuelles ou des conteneurs est incroyablement attrayante.

Une fonction Lambda est un service sans état. Il gère généralement les demandes en appelant les services AWS. Par exemple, une fonction Lambda appelée lorsqu'une image est téléchargée dans un bucket S3 peut insérer un élément dans une table d'images DynamoDB et publier un message dans un flux Kinesis pour déclencher le traitement de l'image. Une fonction Lambda peut également appeler des services Web tiers.

Il existe quatre façons d'appeler une fonction Lambda :

  1. Directement, en utilisant une demande de service Web
  2. Automatiquement, en réponse à un événement généré par un service AWS tel que S3, DynamoDB, Kinesis ou Simple Email Service
  3. Automatiquement, via une passerelle API AWS pour gérer les requêtes HTTP des clients de l'application
  4. Périodiquement, selon un calendrier de type cron

Comme vous pouvez le constater, AWS Lambda est un moyen pratique de déployer des microservices. La tarification basée sur la demande signifie que vous ne payez que pour le travail que vos services effectuent réellement. De plus, comme vous n’êtes pas responsable de l’infrastructure informatique, vous pouvez vous concentrer sur le développement de votre application.

Il existe cependant quelques limitations importantes. Il n’est pas destiné à être utilisé pour déployer des services de longue durée, tels qu’un service qui consomme des messages provenant d’un courtier de messages tiers. Les demandes doivent être traitées dans un délai de 300 secondes. Les services doivent être sans état, car en théorie, AWS Lambda peut exécuter une instance distincte pour chaque demande. Ils doivent être rédigés dans l’une des langues prises en charge. Les services doivent également démarrer rapidement, sinon ils risquent d'être interrompus et interrompus.

Résumé

Déployer une application en microservices représente un véritable défi. Vous devez gérer des dizaines, voire des centaines de services, développés dans divers langages et frameworks. Chacun constitue une mini-application avec ses propres exigences de déploiement, ressources, scalabilité et surveillance. Plusieurs modèles de déploiement de microservices existent, notamment l’instance de service par machine virtuelle et par conteneur. Une autre option séduisante pour déployer des microservices est AWS Lambda, qui adopte une approche sans serveur. Dans la dernière partie de cette série, nous vous expliquerons comment migrer une application monolithique vers une architecture de microservices.

Rédacteur – Cette série d’articles en sept parties est désormais terminée :

  1. Introduction aux microservices
  2. Création de microservices : Utilisation d'une passerelle API
  3. Création de microservices : Communication interprocessus dans une architecture de microservices
  4. Découverte de services dans une architecture de microservices
  5. Gestion des données pilotée par les événements pour les microservices
  6. Choisir une stratégie de déploiement de microservices (cet article)
  7. Refactorisation d'un monolithe en microservices

Vous pouvez également télécharger l'ensemble complet des articles, ainsi que des informations sur la mise en œuvre de microservices à l'aide de NGINX Plus, sous forme d'ebook – Microservices : De la conception au déploiement . Et consultez notre série sur l’ architecture de référence des microservices et la page Solutions de microservices .

Le blogueur invité Chris Richardson est le fondateur du CloudFoundry.com original, un PaaS (Platform as a Service) Java précoce pour Amazon EC2. Il conseille désormais les organisations pour améliorer la manière dont elles développent et déploient des applications. Il blogue également régulièrement sur les microservices sur https://microservices.io .


« Cet article de blog peut faire référence à des produits qui ne sont plus disponibles et/ou qui ne sont plus pris en charge. Pour obtenir les informations les plus récentes sur les produits et solutions F5 NGINX disponibles, explorez notre famille de produits NGINX . NGINX fait désormais partie de F5. Tous les liens NGINX.com précédents redirigeront vers un contenu NGINX similaire sur F5.com."