Académique Documents
Professionnel Documents
Culture Documents
Cloud native
avec Azure
Création et gestion
d'applications Cloud
natives
9 781492 090960
Infrastructure Cloud native
avec Azure
Création et gestion
d'applications Cloud natives
Le logo O’Reilly est une marque déposée d’O’Reilly Media, Inc. Infrastructure Cloud native avec Azure, l’im-
age de couverture et l'habillage commercial associé sont des marques déposées d’O’Reilly Media, Inc.
Les opinions exprimées dans cet ouvrage sont celles des auteurs et ne représentent pas celles de l'éditeur. Bien
que l'éditeur et les auteurs se soient efforcés, en toute bonne volonté, de s'assurer que les informations et les
instructions contenues dans ce travail sont exactes, l'éditeur et les auteurs déclinent toute responsabilité en
cas d'erreurs ou d'omissions, y compris, entre autres, la responsabilité des dommages résultant de l'utilisation
ou de la confiance accordée à cet ouvrage. L’utilisation des informations et des instructions contenues dans
cet ouvrage se fait à vos propres risques. Si des exemples de code ou d’autres technologies que ce travail
contient ou décrit sont soumis à des licences open source ou à des droits de propriété intellectuelle de tiers,
il est de votre responsabilité de vous assurer que votre utilisation est conforme à ces licences et/ou droits.
978-1-492-09096-0
[LSI]
Table des matières
Préface . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . xi
iii
Primitives de conteneur basique 37
Cgroups38
Espaces de noms 39
Copie en écriture 40
Capacités40
Seccomp-BPF40
Composants de l’exécution d’un conteneur 40
Orchestrateurs de conteneur 41
Logiciel de conteneur 41
Runtimes de conteneur 42
Conteneurs43
Système d’exploitation 43
Spécification Open Container Initiative (OCI) 43
Spécification d’image OCI 44
Spécification de runtime OCI 45
Docker46
Création de votre première image Docker 46
Bonnes pratiques appliquées à l’utilisation de Docker 48
Autres plateformes de conteneurs 49
Containers Kata 49
LXC et LXD 49
Registres de conteneurs 50
Stockage d'images sécurisé avec Harbor 51
Stockage d'images sécurisé avec Azure Container Registry 55
Stockage d'images Docker dans un registre 59
Exécution de Docker sur Azure 60
Azure Container Instances 60
Déploiement d’Azure Container Instance 61
Exécution de Docker Container Engine 65
Résumé66
Index. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . 289
Le cloud computing a été largement adopté par les entreprises comme un modèle de
transformation numérique de nouvelle génération qui stimule la croissance et l’innovation.
Aujourd’hui, les clients recherchent un écosystème et une expérience rapides, qui s’intègrent
parfaitement à leurs services existants. Du point de vue de l’entreprise, le Cloud propose des
services évolutifs, très fiables et hautement disponibles aux clients et aux entreprises. Du
point de vue de l’utilisateur, le Cloud fournit un modèle simple pour acquérir des services
informatiques sans avoir besoin de comprendre pleinement l’infrastructure et la technologie
sous-jacentes.
Pour tirer pleinement parti de la rapidité et de l’agilité des services Cloud, de nombreuses
applications existantes ont été transformées en applications Cloud natives, et de nouvelles
solutions axées sur le Cloud sont en cours de conception. Les applications Cloud natives
sont conçues à partir de zéro en vue d'adopter des changements rapides, tout en présentant
de grandes évolutivité et résilience. Par défaut, l’infrastructure sous-jacente des applications
Cloud natives joue un rôle essentiel pour répondre efficacement aux besoins d’une
entreprise. Si l’infrastructure sous-jacente n’est pas conçue avec les bonnes pratiques, même
les meilleures applications Cloud natives s'avéreront défaillantes dans les environnements
de production.
Cet ouvrage explore la façon dont les infrastructures Cloud natives modernes sur Azure
peuvent être créées et gérées dans un environnement de production, ainsi que diverses
exigences et considérations de conception des applications Cloud natives.
xi
Ce manuel suppose que vous possédez des connaissances de base sur le Cloud et la culture
DevOps en général. Même si ce n’est pas le cas, et si vous souhaitez mieux comprendre l'en-
gouement autour du Cloud natif et d’autres technologies sophistiquées, cet ouvrage vous est
également destiné.
Objectifs de ce manuel
Une fois que vous aurez lu ce manuel, vous serez en mesure de suivre et de créer votre
propre infrastructure sur Microsoft Azure. Nous présentons une introduction séquentielle
aux principaux composants du monde Cloud natif et comment les utiliser, les déployer et
les maintenir sur Azure. Vous découvrirez également la nécessité d'adopter des technologies
Cloud natives dans le nouveau monde d’aujourd’hui, les problèmes qu’elles résolvent et les
bonnes pratiques concrètes.
Grâce à cet ouvrage, vous pourrez :
• Découvrir comment créer une infrastructure Cloud native sur Azure en suivant le par-
cours du paysage Cloud natif de la Cloud Native Computing Foundation
• Déterminer quelles technologies utiliser à différentes étapes de la conception
•
Découvrir comment résoudre les problèmes rencontrés lors de la gestion et de
l’exploitation de l’infrastructure Cloud native, ainsi que les technologies nécessaires
pour y remédier
xii Préface
• Le chapitre 8 couvre la gestion des réseaux et des stratégies, y compris Calico, Flannel,
Cilium, la stratégie Azure et les interfaces de mise en réseau de conteneurs Open Policy
Agent.
• Le chapitre 9 explique comment les systèmes de stockage persistants sont déployés sur
l’infrastructure Cloud native, en mettant l’accent sur Azure Storage, Vitess, Rook, TiKV,
et etcd.
• Le chapitre 10 se concentre principalement sur les plateformes de messagerie et de
streaming, telles que NATS et les services de messagerie Azure.
• Le chapitre 11 est une simple introduction au principe du sans serveur dans le paysage
Cloud natif.
• Le chapitre 12 synthétise tous les éléments abordés dans les chapitres précédents.
Préface xiii
Utilisation d’exemples de code
Le matériel supplémentaire (exemples de code, exercices, etc.) peut être téléchargé à l’adres-
se https://github.com/stormic-nomad-nishant/cloud_native_azure.
Si vous avez une question technique ou un problème concernant les exemples de code,
veuillez envoyer un e-mail à l'adresse bookquestions@oreilly.com.
Ce manuel est conçu pour vous aider dans votre travail. Les exemples de code proposés
dans cet ouvrage peuvent généralement être utilisés dans vos programmes et votre
documentation. Vous n’avez pas besoin de nous contacter pour obtenir une autorisation, à
moins que vous ne reproduisez une partie importante du code. L’écriture d’un programme
qui utilise plusieurs segments de code de ce manuel ne nécessite aucune autorisation.
La vente ou la distribution d’exemples des ouvrages O’Reilly nécessite une autorisation.
Aucune autorisation n'est nécessaire pour répondre à une question en citant cet ouvrage et
un exemple de code. L’intégration d'une quantité importante d’exemple de code tiré de ce
manuel dans la documentation de votre produit nécessite une autorisation.
Même si nous apprécions l'attribution, nous le l'exigeons généralement pas. Une attribution
inclut généralement le titre, l’auteur, l’éditeur et l’ISBN. Par exemple : « Infrastructure Cloud
native avec Azure par Nishant Singh et Michael Kehoe (O’Reilly). Copyright 2022 Nishant
Singh et Michael Kehoe, 978-1-492-09096-0 ».
Si vous estimez que votre utilisation d’exemples de code ne peut être qualifiée d'utilisation
raisonnable ou ne respecte pas les conditions des autorisations susmentionnées, n’hésitez
pas à nous contacter à l'adresse permissions@oreilly.com.
Notre réseau unique d’experts et d’innovateurs partage ces connaissances et ces compétences
grâce à des livres, des articles et notre plateforme d’apprentissage en ligne. La plateforme
d’apprentissage en ligne d'O’reilly offre un accès à la demande à des cours de formation en
direct, des parcours d’apprentissage détaillés, des environnements de codage interactifs et
une vaste collection de textes et de vidéos d’O’Reilly, ainsi que ceux de plus de 200 autres
éditeurs. Pour en savoir plus, consultez l'adresse http://oreilly.com.
xiv Préface
Comment nous contacter
Veuillez adresser vos commentaires et vos questions concernant cet ouvrage à l’éditeur :
Nous proposons une page Web dédiée à cet ouvrage, où nous répertorions les erreurs, les
exemples et toutes les informations supplémentaires. Vous pouvez accéder à cette page
à l’adresse https://oreil.ly/cloud-native-azure.
E-mail bookquestions@oreilly.com pour commenter ou poser des questions techniques sur
cet ouvrage.
Pour connaître les actualités et en savoir plus sur nos manuels et cours, consultez la page
http://oreilly.com.
Suivez-nous sur Facebook : http://facebook.com/oreilly.
Suivez-nous sur Twitter : http://twitter.com/oreillymedia.
Suivez-nous sur YouTube : http://youtube.com/oreillymedia.
Remerciements
Nous tenons à remercier Rita Fernando, Nicole Taché et Jennifer Pollock, nos éditrices
chez O’Reilly qui nous ont beaucoup soutenu en nous aidant considérablement dans le
processus d’écriture. Nous tenons également à remercier nos réviseurs techniques pour
leurs précieuses contributions à ce manuel. La rédaction de cet ouvrage n’aurait pas été
possible sans les révisions minutieuses et précieuses de Matt Franz, Peter Jausovec, Liudmila
Sinkevich, Steve Machacz et Alexander Kabonov.
En outre, nous tenons à remercier Matt Franz pour ses évaluations, suggestions et contributions
approfondies qui ont permis d'améliorer la qualité de cet ouvrage. Matt a apporté des
commentaires détaillés sur les chapitres et a contribué à la rédaction du chapitre 10.
Nishant souhaite remercier sa mère, son père et son épouse, Mahek, pour leur patience et
leur soutien alors qu'il travaillait sur ce manuel. Il aimerait également remercier l’équipe
d'O’Reilly et ses pairs de LinkedIn qui ont soutenu cette idée dès le début.
Michael aimerait remercier sa famille, qui l’a encouragé à suivre ses rêves et à ne jamais
abandonner. Il aimerait également remercier sa meilleure amie, Jennifer, pour son soutien
et sa patience pendant qu’il travaillait sur ce livre, le personnel d'O’Reilly pour l'avoir aidé
à concrétiser son idée en rédigeant cet ouvrage, et tous les réviseurs pour leur contribution.
Préface xv
CHAPITRE 1
Introduction : Pourquoi opter pour
une option Cloud native ?
1
application et vous deviez toujours payer les frais généraux liés à l’exécution de votre datacenter.
Cette situation a induit la nécessité d’exécuter une infrastructure en tant que service (IaaS),
où les serveurs appartiennent à des tiers qui sont responsables de l’infrastructure sous-jacente
de vos applications. Cette période à marqué l’avènement de l’ère du cloud computing. Les
entreprises ont ainsi pu se concentrer sur leurs applications et leurs environnements sous-
jacents sans se soucier des problèmes liés au matériel, aux frais généraux ou à la configuration.
Les solutions IaaS ont été suivies par la plateforme en tant que service (PaaS), qui visait à réduire
davantage le fardeau en séparant l’environnement logiciel sous-jacent et le runtime. Ainsi,
les développeurs devaient uniquement se concentrer sur l’écriture de leurs applications et la
définition des dépendances. La plateforme de service était quant à elle entièrement responsable
de l’hébergement, de l’exécution, de la gestion et de l’exposition des applications. Les solutions
PaaS ont ouvert la voie à des services Cloud entièrement gérés avec l’avènement du logiciel
en tant que service (SaaS), populairement connu sous le nom de « logiciel à la demande ». Ce
dernier propose aux clients l’application en tant que service basée sur leur consommation.
À mesure que le cloud computing gagnait en popularité, l’idée de disposer de technologies
Cloud natives qui utiliseraient le Cloud de manière plus efficace, tout en exploitant
pleinement le potentiel de l’infrastructure Cloud et de ses diverses offres a également séduit
de nombreux individus. C'est ainsi que l’infrastructure et les applications Cloud native sont
nées. L'infrastructure Cloud native crée une abstraction sur l’infrastructure sous-jacente
du fournisseur Cloud et expose l’infrastructure avec des API. Cette philosophie de gestion
d’infrastructure facilite énormément la mise à l’échelle, tout en réduisant la complexité sous-
jacente, en vue d'améliorer indirectement la disponibilité, la résilience et la maintenabilité. De
même, les applications Cloud natives renforcent le lien entre l’application et l’infrastructure
en intégrant des fonctions de prise en charge, telles que les contrôles d’intégrité, la télémétrie
et les métriques, la résilience, un environnement de microservices et la réparation spontanée.
Abordons désormais les défis de l’environnement de cloud computing.
Les technologies Cloud natives permettent aux entreprises de créer et d’exécuter des
applications évolutives dans des environnements modernes et dynamiques, tels que
les Clouds publics, privés et hybrides. Les conteneurs, les maillages de services, les
microservices, l’infrastructure immuable et les API déclaratives illustrent cette approche.
Ces techniques permettent d'utiliser des systèmes associés librement qui sont résilients,
gérables et observables. Combinés avec une automatisation robuste, ils permettent
aux ingénieurs d’effectuer fréquemment des changements à forte incidence et de façon
prévisible avec un minimum d'efforts.
La Cloud Native Computing Foundation vise à faciliter l’adoption de ce paradigme en favorisant
et en soutenant un écosystème de projets open source et non rattachés à un fournisseur. Nous
démocratisons les modèles de pointe pour rendre ces innovations accessibles à tous.
La CNCF a compilé un paysage Cloud natif interactif qui montre toute l’étendue des solutions
Cloud natives d'aujourd’hui. Le paysage CNCF agit comme une carte des technologies Cloud
natives et fournit des directives pour la création d’applications Cloud natives performantes.
Bien que le paysage Cloud natif fournisse beaucoup d’informations sur la conception des
services, celle-ci peut s'avérer délicate, en particulier pour les personnes inexpérimentées,
car elle comprend un certain nombre de services qui sont utilisés ensemble. Dans cet
ouvrage, nous avons choisi la meilleure technologie disponible, tout en suivant les directives
de la CNCF pour mieux naviguer dans le monde Cloud natif.
Résumé
Dans ce chapitre d'introduction, nous avons brièvement expliqué ce que représente le cloud
computing et la façon dont les technologies Cloud natives permettent d'améliorer l’adoption
du Cloud. Vous avez découvert comment le Cloud est devenu populaire et comment le
cloud computing a évolué du matériel physique à un environnement sans serveur. Vous
avez également découvert les défis liés au cloud computing et à la nécessité croissante de
s’adapter aux technologies Cloud natives. Nous avons expliqué la signification du terme
Cloud natif et la façon dont le reste du manuel abordera le parcours vers le Cloud natif
sur Azure. Nous espérons que vous trouverez ce parcours intéressant et que cet effort vous
permettra d'adapter plus efficacement les technologies Cloud natives.
1 Azure fournit également de nombreuses directives architecturales, qui présentent les bonnes pratiques
en matière de création de services sur Azure : consultez les adresses https://docs.microsoft.com/azure/
architecture et https://azure.microsoft.com/blog/azure-application-architecture-guide.
Résumé 5
CHAPITRE 2
Infrastructure en tant que code :
Configuration de la passerelle
Le Cloud, qui propose un riche assortiment de solutions complètes (mise en réseau aisée,
informatique à l’échelle mondiale etc.) devient la destination incontournable pour la plupart
des organisations, quelle que soit leur taille. L’écosystème de la plupart des fournisseurs
Cloud est désormais plus important que jamais et comprend des machines virtuelles
simples, des clusters gérés complexes et même une infrastructure hautement sophistiquée.
Microsoft Azure, par exemple, propose une variété de services bien conçus aux utilisateurs.
Ces solutions s’intègrent à une infrastructure résiliente par nature. Elles présentent des
contrats de niveau de service (SLA) bien définis1 en vue de répondre aux besoins de tous les
clients, qu'il s'agisse de petites start-ups ou de grandes entreprises.
Bien que la nature dynamique du cloud computing soit une aubaine pour les entreprises, il
peut être difficile de maintenir des services dans des environnements Cloud à mesure que
votre entreprise se développe. À mesure que vous exploitez de plus en plus de services basés
dans le Cloud pour répondre aux besoins croissants de votre entreprise, vous réaliserez
rapidement que vous ne pourrez plus maintenir vos applications et votre infrastructure
sous-jacente en cliquant simplement sur la console Web chaque fois que vous souhaitez
effectuer une nouvelle action. La conception évolutive du Cloud a été fondée sur les
générations précédentes de matériel et d’infrastructure virtualisée associés à un plan de
contrôle programmable qui fournit une certaine flexibilité, sous la forme de couches d'API.
Ces API sont exploitées par des outils d’infrastructure en tant que code (IaC) pour permettre
aux utilisateurs du Cloud de maintenir facilement leur environnement.
Lorsque vous souhaitez créer une infrastructure dédiée à la production à partir de zéro, vous
devez commencer à traiter vos définitions d’infrastructure de la même manière que vous traitez
1 Un SLA est un accord entre le fournisseur Cloud et le client (vous) sur des métriques mesurables, telles que
la disponibilité, la réactivité et les responsabilités.
7
votre code. La configuration et la mise à l’échelle manuelle de votre infrastructure ne sont pas
seulement fastidieuses, il s’agit également d’un processus sujet aux erreurs : vous ne pouvez pas
créer la même infrastructure deux fois avec le même niveau de confiance. Lorsque vous traitez
votre infrastructure en tant que code, vous héritez également des principes d’ingénierie logicielle,
tels que le contrôle de version, la testabilité, l’automatisation et la vitesse de développement
dans le cadre de la stratégie DevOps. L'IaC garantit que votre infrastructure peut être conçue
de manière cohérente et reproductible. À mesure que les équipes de développement logiciel ont
adopté les méthodologies agiles, elles ont été confrontées à la nécessité de déplacer davantage
de fonctions et de solutions plus fréquemment et plus rapidement vers le Cloud. À ce titre,
l’infrastructure est devenue étroitement liée aux applications, et les équipes sont tenues de
gérer les applications et l’infrastructure à l’aide d’un processus transparent. En outre, les équipes
doivent itérer et déployer à plusieurs reprises de nouvelles fonctions et une infrastructure sous-
jacente plus fréquemment. Les modèles prédéfinis offerts par les fournisseurs de Cloud, qui
fournissent des instructions sur la création d’une infrastructure, permette d'accélérer la mise
en œuvre de l'IaC. Azure prend en charge nativement les modèles Azure Resource Manager
(ARM), qui sont utilisés pour définir et créer des ressources d’infrastructure directement
associées à la philosophie de l’IaC. Cette combinaison du Cloud et de l'IaC permet aux
entreprises d’introduire des changements plus rapidement et plus efficacement.
Ce chapitre pose les fondements d'une compréhension approfondie de l'IaC et d’Azure.
Nous allons commencer par introduire le concept d'IaC et son importance dans la création
d’une infrastructure Cloud native. Nous présenterons ensuite Microsoft Azure, qui est le
fournisseur de Cloud que nous utiliserons tout au long de cet ouvrage.
Nous étudierons ensuite Terraform, qui nous servira d'outil pour la mise en œuvre de
l’IaC. Nous aborderons également Packer, qui est principalement un outil de création
d’images de machine et Ansible, afin de vous présenter la gestion de la configuration, tout
en développant des applications Cloud natives. Enfin, nous étudierons Azure DevOps avant
de clore le chapitre. Commençons dès maintenant.
Avec les avantages de l’IaC, il devient évident que ces outils jouent un rôle important dans
les environnements Cloud natifs modernes où les applications doivent être modifiées à
la volée. Les modifications peuvent être mineures, telles que l’ajout d’une nouvelle balise
de configuration ou importantes, comme l’ajout de nouveaux clusters pour répondre aux
exigences de capacité. Une stratégie IaC fiable permet aux développeurs de gérer facilement
ces changements, sans compromettre la rapidité du processus de développement logiciel.
Une fois que l'IaC a été intégré au cœur de votre processus de création d’infrastructure, il
contribue également à la conception d’une infrastructure anti-fragile.
Infrastructure anti-fragile
Les infrastructures anti-fragiles sont des systèmes capables de résister
au stress, tout en démontrant de l’élasticité, ainsi que de la résilience. Le
principe anti-fragile vise à créer une infrastructure capable de gérer des
événements imprévisibles et irréguliers, tout en renforçant la croissance.
L’infrastructure en tant que code et son importance dans le monde Cloud natif 9
Les applications Cloud natives actuelles sont considérées comme des applications en
mouvement, car l’infrastructure sous-jacente continue d'évoluer et de se mettre à niveau. Le
Cloud vous permet de traiter vos infrastructures comme des entités éphémères, plutôt que
des entités permanentes. L’approche Cloud native favorise la création d’une infrastructure
remplaçable, par opposition à la réparation d'une infrastructure défaillante. Dans la mesure
où l’approche Cloud native découple les applications de votre infrastructure, elle confère
aux ingénieurs le contrôle et la confiance nécessaires pour modifier l’infrastructure, sachant
qu’ils peuvent annuler les modifications et avancer très facilement.
2 La MFA ajoute une couche de protection au processus de connexion. Lorsqu'ils accèdent aux comptes
ou aux applications, les utilisateurs procèdent à une vérification d’identité supplémentaire, telle que le
balayage d’une empreinte digitale ou la saisie d’un code qu’ils reçoivent sur leur téléphone.
Vous pouvez même utiliser Azure CLI pour scripter de façon déclarative votre infrastructure
Cloud. Ces scripts peuvent être exécutés dans PowerShell ou Bash. Bien que les scripts
Azure s'avèrent performants pour des tâches telles que la création, le démantèlement et le
redéploiement récent de l’infrastructure, ils le sont un peu moins pour des tâches telles que
la mise à jour d’un environnement existant, en raison du manque de idempotence dans les
commandes Azure CLI.
En plus d’Azure, d’autres outils sont disponibles pour la création et la gestion des
environnements Cloud. Nous allons examiner les outils les plus importants.
Terraform
Terraform est un outil IaC open source d'HashiCorp, écrit dans le langage de programmation
Go. Le mot terraform signifie transformer l’environnement d’une planète de manière à ce
qu'il ressemble étroitement à l’atmosphère de la terre, propice à la vie de l’espèce humaine.
Cette analogie s'avère véridique lorsqu'elle est appliquée aux fournisseurs Cloud qui sont
assimilés à des environnements qui doivent être transformés en une infrastructure gérable,
afin que votre application puisse tirer pleinement parti du Cloud et atteindre son véritable
potentiel.
Terraform vous aide à créer, modifier et versionner une infrastructure dans le Cloud de
manière sûre et efficace. Cet outil utilise une syntaxe déclarative. Ainsi, vous n’avez qu’à
lui indiquer l'élément que vous souhaitez créer au lieu de la façon dont vous souhaitez le
concevoir. L’un des principaux avantages de Terraform est la prise en charge d’un langage
spécifique au domaine (DSL) facile à comprendre, appelé HashiCorp Configuration
Language (HCL), qui est relativement facile à interpréter pour les humains. Vous pouvez
également utiliser JSON aux mêmes fins. En outre, Terraform est indépendant du Cloud et
prend donc en charge plusieurs fournisseurs Cloud. Il est donc très facile à prendre en main
car vous n’avez pas besoin d’apprendre le langage (HCL/JSON) une nouvelle fois pour un
autre fournisseur Cloud. Cette section traite de l'utilisation de Terraform pour concevoir
une infrastructure sur Azure à l’aide de la philosophie IaC.
Pour que vous compreniez le fonctionnement de Terraform, nous devons d’abord expliquer
la terminologie de base :
Fournisseurs
Un fournisseur dans Terraform est généralement (mais pas toujours) un fournisseur
Cloud. Ce fournisseur est chargé d’exposer les ressources (par exemple, les ressources
Cloud) et d’interpréter l’API. Certains des fournisseurs pris en charge par Terraform
sont Azure, Amazon Web Services (AWS), Google Cloud Platform (GCP) et PagerDuty.
Plan
Lorsque vous créez votre infrastructure à l’aide de la commande terraform plan,
Terraform crée un plan d’exécution qui est basé sur le code que vous écrivez via les
fichiers de configuration Terraform (.tf). Le plan d’exécution inclut les étapes que
Terraform prendra pour concevoir l’infrastructure demandée.
Application
Lorsque vous êtes satisfait du plan que Terraform a créé, vous pouvez utiliser la
commande terraform apply pour créer l’infrastructure, qui finira par atteindre l’état
souhaité (en l'absence de conflits ou d'erreurs).
Selon le fournisseur que vous utilisez, l’infrastructure sera mise en service dans
l’environnement du fournisseur Cloud correspondant (dans notre cas, il s’agit de Microsoft
Azure). Si vous souhaitez supprimer votre infrastructure, vous pouvez simplement saisir
la commande terraform destroy, qui supprimera l’infrastructure correspondant au
répertoire actif. Veuillez faire très attention lorsque vous supprimez votre infrastructure
avec Terraform.
Maintenant que vous disposez d'une compréhension générale de la charge de travail et des
détails opérationnels de Terraform, intéressons-nous à la pratique.
Une fois que vous avez saisi le fichier ZIP, décompressez le fichier binaire et déplacez le
binaire unique vers /usr/local/bin. Vous pouvez vérifier que Terraform est installé en
recourant à l’aide de Terraform à partir du shell :
$ ~ terraform --version
Terraform v0.12.28
$ ~ terraform --help
Usage: terraform [-version] [-help] <command> [args]
Common commands:
apply Builds or changes infrastructure
console Interactive console for Terraform interpolations
destroy Destroy Terraform-managed infrastructure
env Workspace management
fmt Rewrites config files to canonical format
get Download and install modules for the configuration
graph Create a visual graph of Terraform resources
import Import existing infrastructure into Terraform
init Initialize a Terraform working directory
login Obtain and save credentials for a remote host
logout Remove locally-stored credentials for a remote host
output Read an output from a state file
plan Generate and show an execution plan
providers Prints a tree of the providers used in the configuration
refresh Update local state file against real resources
show Inspect Terraform state or plan
taint Manually mark a resource for recreation
untaint Manually unmark a resource as tainted
validate Validates the Terraform files
version Prints the Terraform version
workspace Workspace management
3 Azure Cloud Shell est livré avec la dernière version de Cloud Shell. Pour en savoir plus sur la prise en main de
Terraform sur Cloud Shell, visitez https://docs.microsoft.com/azure/developer/terraform/get-started-cloud-shell.
1. Cliquez sur l’icône Cloud Shell située dans le coin supérieur droit de votre compte dans
le portail Azure, puis cliquez sur « Créer un compte de stockage ». Vous bénéficierez
ainsi d'un nouveau compte de stockage en quelques minutes.
2. Après avoir sélectionné Cloud Shell, vous pouvez choisir Bash ou PowerShell. Vous
pouvez également modifier le shell ultérieurement si vous le souhaitez. Tout au long
de cet ouvrage, nous allons utiliser le shell Bash. Une fois l’installation terminée, vous
recevez les notifications suivantes :
Requesting a Cloud Shell.Succeeded.
Connecting terminal...
3. Vous devez maintenant obtenir la liste de valeurs d’ID d’abonnement et d’ID de locataire.
Pour ce faire, exécutez la commande suivante dans Cloud Shell pour répertorier tous
les noms de compte Azure, les ID d’abonnement et les ID de locataire :
$ az account list --query "[].{name:name, subscriptionId:id, tenantId:tenantId}"
[
{
"name": "Visual Studio Enterprise",
"subscriptionId": "b1234567-89017-6135-v94s-3v16ifk86912",
"tenantId": "ba0198-d28a-41ck-a2od-d8419714a098"
}
]
$
4. Notez la valeur subscriptionId dans la sortie JSON renvoyée. Ensuite, tout en restant
dans Cloud Shell, remplacez subscriptionId par la commande suivante :
$ az account set --subscription="b1234567-89017-6135-v94s-3v16ifk86912"
Cette commande renvoie les valeurs appId, displayName, name, password, et tenant.
6. Utilisez les données suivantes pour configurer les variables d’environnement Terraform
sur l’ordinateur local :
ARM_SUBSCRIPTION_ID=<subscription>
ARM_CLIENT_ID=<appId>
ARM_CLIENT_SECRET=<password>
ARM_TENANT_ID=<tenant>
7. Dans votre .bash_profile (ou, si vous préférez, envvar.sh), remplacez les variables dans
le code précédent comme suit :
#!/bin/sh
echo "Setting environment variables for Terraform"
export ARM_SUBSCRIPTION_ID=b1234567-89017-6135-v94s-3v16ifk86912
export ARM_CLIENT_ID=b0b88757-6ab2-3v41-1234-23ss224vd41e
export ARM_CLIENT_SECRET=aH2cK.asfbbashfbjafsADNknvsaklvQQ
export ARM_TENANT_ID=ba0198-d28a-41ck-a2od-d8419714a098
8. Effectuez un source .bash_profile sur votre terminal pour lire et exécuter des
commandes depuis le fichier vers l’environnement shell actuel.
Vous pouvez désormais utiliser Cloud Shell pour interagir avec les ressources Azure ou, si
vous préférez, utilisez Azure CLI sur votre ordinateur local pour interagir avec Azure.
4 Un principal de service Azure est une identité créée pour être utilisée avec des applications, des services
hébergés et des outils automatisés pour accéder aux ressources Azure. Cet accès est limité par les rôles
attribués au principal de service, afin que vous puissiez contrôler les ressources accessibles et à quel niveau.
Maintenant que vous avez réussi à vous connecter et à vous authentifier avec Azure, vous
pouvez consulter le répertoire ~/.azure, qui contient les informations d’authentification et
d’autorisation :
$ ls -al
total 44
drwxr-xr-x 1 nsingh nsingh 270 Apr 13 21:13 .
drwxr-xr-x 1 nsingh nsingh 624 Apr 13 21:13 ..
-rw------- 1 nsingh nsingh 7842 Apr 13 21:13 accessTokens.json
-rw-r--r-- 1 nsingh nsingh 5 Apr 13 21:13 az.json
-rw-r--r-- 1 nsingh nsingh 5 Apr 13 21:13 az.sess
-rw-r--r-- 1 nsingh nsingh 420 Apr 13 21:21 azureProfile.json
-rw-r--r-- 1 nsingh nsingh 66 Apr 13 21:21 clouds.config
-rw-r--r-- 1 nsingh nsingh 5053 Apr 13 21:13 commandIndex.json
drwxr-xr-x 1 nsingh nsingh 318 Apr 13 21:21 commands
-rw------- 1 nsingh nsingh 51 Apr 13 21:13 config
drwxr-xr-x 1 nsingh nsingh 26 Apr 13 21:13 logs
drwxr-xr-x 1 nsingh nsingh 10 Apr 13 21:13 telemetry
-rw-r--r-- 1 nsingh nsingh 16 Apr 13 21:13 telemetry.txt
-rw-r--r-- 1 nsingh nsingh 211 Apr 13 21:13 versionCheck.json
provider "azurerm" {
}
resource "azurerm_resource_group" "rg" {
name = "testResourceGroup"
location = "westus"
}
To prevent automatic upgrades to new major versions that may contain breaking
changes, it is recommended to add version = "..." constraints to the
corresponding provider blocks in configuration, with the constraint strings
suggested below.
You may now begin working with Terraform. Try running "terraform plan" to see
any changes that are required for your infrastructure. All Terraform commands
should now work.
------------------------------------------------------------------------
3. Comme vous pouvez le voir dans la sortie précédente, nous essayons de créer un groupe
de ressources intitulé testResourceGroup. Maintenant, vous pouvez enfin créer la
ressource en exécutant terraform apply. N’oubliez pas que vous devez explicitement
saisir yes pour continuer :
$ Test git:(master) ✗ terraform apply
azurerm_resource_group.rg: Creating...
azurerm_resource_group.rg: Creation complete after 3s
[id=/subscriptions/b5627140-9087-4305-a94c-3b16afe86791/resourceGroups/ \
testResourceGroup]
Un groupe de ressources est créé, comme illustré à la figure 2-6. Vous pouvez le vérifier en
accédant au portail Azure.
Vous devriez également le voir dans la CLI. Sachez que l’opération shell n’est pas spécifique
à la région. Les ressources sont affichées sur plusieurs emplacements. Pour répertorier le
groupe de ressources, utilisez la commande suivante :
$ az group list --output table
Name Location Status
-------------------------- ---------- ---------
testResourceGroup westus Succeeded
Dans votre répertoire Test, vous remarquerez peut-être un fichier nommé terraform.
tfstate qui a été créé une fois le groupe de ressources configuré. Il s’agit du fichier d’état qui
maintient l’état actuel de l’infrastructure.
Création d'un stockage blob Azure. Pour créer un stockage blob Azure, vous devez utiliser le
module suivant : https://bit.ly/3bM6jCx.
Notez la sortie de l'opération terraform apply effectuée dans l'étape précédente et copiez
la valeur de la clé d’accès primaire. Vous devrez mettre à jour la valeur de la clé primaire
dans le même .bash_profile dans votre ordinateur local, comme suit :
#!/bin/sh
echo "Setting environment variables for Terraform"
export ARM_SUBSCRIPTION_ID=b1234567-89017-6135-v94s-3v16ifk86912
export ARM_CLIENT_ID=b0b88757-6ab2-3v41-1234-23ss224vd41e
export ARM_CLIENT_SECRET=aH2cK.asfbbashfbjafsADNknvsaklvQQ
export ARM_TENANT_ID=ba0198-d28a-41ck-a2od-d8419714a098
Création d'un réseau virtuel et d'instances Azure.. Nous allons à présent créer un réseau
virtuel sur Azure en suivant la configuration Terraform à l'adresse https://bit.ly/3bHE342.
Nous allons également expliquer le flux syntaxique du module de réseau virtuel, afin de
mieux appréhender la simplicité du code.
private-nic-id = /subscriptions/b5627140-9087-4305-a94c-3b16afe86791/resourceGroups/
CloudNativeAzure-group/providers/Microsoft.Network/networkInterfaces/private-nic
private-subnet-a-id = /subscriptions/b5627140-9087-4305-a94c-3b16afe86791/resourceGroups/
CloudNativeAzure-group/providers/Microsoft.Network/virtualNetworks/cna-prod/subnets/
linkedin-private-a
private-subnet-b-id = /subscriptions/b5627140-9087-4305-a94c-3b16afe86791/resourceGroups/
CloudNativeAzure-group/providers/Microsoft.Network/virtualNetworks/cna-prod/subnets/
linkedin-private-b
pub-nic-id = /subscriptions/b5627140-9087-4305-a94c-3b16afe86791/resourceGroups/
CloudNativeAzure-group/providers/Microsoft.Network/networkInterfaces/public-nic
public-subnet-a-id = /subscriptions/b5627140-9087-4305-a94c-3b16afe86791/resourceGroups/
CloudNativeAzure-group/providers/Microsoft.Network/virtualNetworks/cna-prod/subnets/
linkedin-public-a
public-subnet-b-id = /subscriptions/b5627140-9087-4305-a94c-
3b16afe86791/resourceGroups/CloudNativeAzure-group/providers/Microsoft.Network/
virtualNetworks/cna-prod/subnets/linkedin-private-b
vpc-id = /subscriptions/b5627140-9087-4305-a94c-3b16afe86791/resourceGroups/
CloudNativeAzure-group/providers/Microsoft.Network/virtualNetworks/cna-prod
Comme illustré à la figure 2-9, Terraform a stocké l’état du réseau virtuel sur le compte de
stockage blob que nous avons créé précédemment.
Figure 2-9. État du réseau virtuel téléchargé par Terraform sur le compte de stockage
De même, vous pouvez suivre les étapes précédentes et lancer une machine virtuelle à l’intérieur
de l’un des sous-réseaux à l’aide du module Terraform à l’adresse https://bit.ly/3bQjTEV.
Une fois que vous avez fini de créer les ressources dans cet exemple,
veillez à les supprimer à l’aide de la commande terraform
destroy à l’intérieur de chaque répertoire de ressources, si la
facturation est activée dans votre compte Azure.
le gestionnaire de ressources convertira le fichier JSON en une opération API REST, qui
sera envoyée au fournisseur de ressources Microsoft.Storage comme suit :
PUT
https://management.azure.com/subscriptions/{subscriptionId}/resourceGroups/ \
{resourceGroupName}/providers/Microsoft.Storage/storageAccounts/ \
teststorageaccount?api-version=2019-04-01
REQUEST BODY
{
"location": "eastus",
"sku": {
"name": "Standard_LRS"
},
"kind": "StorageV2",
"properties": {}
}
Vous pouvez également utiliser Terraform pour déployer des modèles ARM à l’aide de la
ressource azurerm_ resource_group_template_deployment pour le fournisseur AzureRM.
5 Azure propose JSON (JavaScript Object Notation) par défaut pour l’écriture de modèles ARM. Azure
propose également un langage spécifique au domaine appelé Bicep qui utilise également la syntaxe
déclarative pour déployer des ressources Azure. Vous pouvez utiliser Bicep au lieu de JSON pour réduire la
complexité et améliorer l’expérience globale de développement/gestion.
Installation de Packer
Pour démarrer avec Packer, téléchargez le binaire Packer approprié pour votre ordinateur
local7. Décompressez le binaire et déplacez-le vers /usr/local/bin. Packer devrait ainsi être
configuré sur votre ordinateur. Pour le vérifier, exécutez packer --help sur votre shell :
$ ~ packer --help
Usage: packer [--version] [--help] <command> [<args>]
Préparé est un terme utilisé pour désigner la préinstallation d’un logiciel sur une image de machine, qui
6
peut être utilisée ultérieurement pour faire tourner plus d’instances ou de conteneurs.
7 Packer est disponible sur Azure Cloud Shell par défaut.
OSType: Linux
ManagedImageResourceGroupName: CloudNativeAzure-group
ManagedImageName: myfirstPackerImage
ManagedImageId: /subscriptions/b1234567-89017-6135-v94s-3v16ifk86912/resourceGroups/
CloudNativeAzure-group/providers/Microsoft.Compute/images/myfirstPackerImage
ManagedImageLocation: East US
La figure 2-11 illustre l’image que nous avons créée dans le portail Azure. Vous pouvez
vérifier que l’image dispose du serveur Web Nginx et de l’équilibreur de charge HAProxy et
que le serveur proxy est intégré en faisant tourner des machines virtuelles à l’aide de l’image.
Maintenant que vous comprenez le rôle de l'outil Packer dans la création d’images,
intéressons-nous à Ansible, qui contribue énormément à la gestion des environnements
Cloud natifs complexes.
Ansible
Ansible est un outil de gestion de configuration simple qui vous permet de mettre en service,
de configurer et de gérer des serveurs. Ansible facilite la gestion des serveurs sur lesquels aucun
agent préinstallé n'est exécuté. Vous pouvez toutefois configurer Ansible en tant que système
basé sur des agents. En outre, vous pouvez utiliser Ansible en tant qu’outil une fois que vous
avez créé l’infrastructure à l’aide de Terraform et d’images de machine préparées via Packer.
Voici les concepts de base d'Ansible :
Playbooks
Les playbooks Ansible sont une liste de tâches ou de pièces qui doivent être exécutées
sur une instance. En voici un exemple simple :
• Ajoutez le référentiel Nginx.
• Installez Nginx.
• Créez le répertoire racine.
Cette liste ordonnée peut être convertie en playbook Ansible comme suit :
---
- hosts: local
vars:
- docroot: /var/www/serversforhackers.com/public
Nœud de contrôle
Il s’agit généralement du nœud à partir duquel vous allez exécuter le playbook Ansible.
Il peut s’agir de n’importe quel nœud où Ansible est installé. Pour exécuter un playbook
Ansible, vous pouvez exécuter la commande suivante dans votre terminal :
ansible-playbook -vi path_to_host_inventory_file playbook.yaml
Nœuds gérés
Les nœuds ou les hôtes que vous souhaitez gérer sont appelés nœuds gérés. Ces nœuds
sont généralement les serveurs distants. Ansible présente un avantage important : vous
n’avez pas besoin d’installer d'agent sur les instances distantes pour les gérer. Tout ce
dont vous avez besoin, c’est d’un démon Secure Shell (SSH) qui écoute et d'installer
Python sur les hôtes. Ansible crée une connexion SSH pour exécuter les playbooks.
Fichier d’inventaire
Le fichier d’inventaire contient la liste de tous les hôtes gérés par Ansible. L’inventaire
contient généralement des adresses IP, des noms d’hôte, le nom d’utilisateur SSH et des
clés pour se connecter à la machine distante. Voici un exemple d'inventaire :
mail.example.com
[webservers]
foo.example.com
bar.example.com
[dbservers]
one.example.com
two.example.com
three.example.com
[midtierrservers]
10.0.1.2
10.2.3.4
Étant donné qu'Ansible n'entraîne pas beaucoup de frais généraux et qu'il est écrit dans
YAML, il s’agit d’un excellent outil post-configuration. Nous utiliserons parfois Ansible
dans cet ouvrage pour configurer des parties des services.
Résumé
Dans ce chapitre, nous avons présenté les tremplins qui permettent de concevoir un
environnement Cloud natif moderne à l’aide d’Azure. Vous avez créé un compte Azure,
que vous utiliserez dans les chapitres à venir, tout en acquérant une compréhension plus
approfondie des technologies Cloud natives. Vous avez également découvert Terraform,
Packer et Ansible : trois orchestrateurs Cloud natifs qui vous aideront à déployer et à gérer
votre infrastructure Cloud. Terraform est un outil indépendant du Cloud, conçu pour
le développement de l’infrastructure en tant que code à partir de zéro. Packer est utilisé
pour créer des images de machine pour le développement d’artefacts immuables, tandis
qu'Ansible est un outil de gestion de configuration.
Grâce à cette compréhension de base d’Azure et des technologies associées, nous pouvons
passer au chapitre suivant, lequel porte sur les conteneurs, le registre de conteneurs et la
conteneurisation de votre application.
Au cours des dernières années, les conteneurs ont gagné en popularité. Ils offrent non
seulement de faibles frais généraux, ainsi qu'une sécurité et une portabilité importantes, tout
en respectant également les principes des bonnes pratiques du Cloud, tels que l’immuabilité,
l'éphémérité et la mise à l’échelle automatique.
Ce chapitre présente les conteneurs et les plateformes de conteneurisation populaires.
Nous étudierons également les conteneurs au-delà de l'effet de mode qu'ils suscitent dans le
secteur en général, en expliquant l'intérêt de leur utilisation. Nous présenterons également
certains de leurs avantages, en particulier en ce qui concerne le Cloud.
35
L’un des avantages les plus importants des conteneurs réside dans le fait qu’ils fournissent
une isolation de type machine virtuelle, sans nécessiter l'exécution d’une instance du
système d’exploitation hôte pour chaque conteneur. À grande échelle, cet avantage permet
d'économiser considérablement les ressources système.
Isolation
Les conteneurs fournissent une isolation grâce à un certain nombre de méthodes d’une
manière flexible qui est configurée par l’administrateur. Les conteneurs peuvent être isolés
de la manière suivante :
Ressources système
L’isolation est réalisée via le processeur, la mémoire et le cgroups de disque.
Espaces de noms
L’isolation est réalisée en autorisant des espaces de noms distincts pour chaque conteneur.
Limites POSIX
L’isolation avec cette méthode vous permet de définir des limites sur votre conteneur.
Ces mécanismes vous permettent d’exécuter en toute sécurité de nombreuses charges de
travail ensemble sans vous soucier de la contention de ressources ou sans qu'un système
en perturbe un autre. Un orchestrateur de conteneurs sensible aux charges de travail vous
permet d'utiliser efficacement toutes les ressources sur un ordinateur hôte sans dégrader
les performances (dénommé bin packing). Si elle est effectuée avec succès à grande échelle,
cette opération permet de réaliser des économies significatives à mesure que vous optimisez
l'efficacité de votre infrastructure.
Sécurité
Fondé sur les fonctions d’isolation des conteneurs, la spécification de runtime du conteneur
OCI (abordée plus loin dans ce chapitre) fournit un certain nombre de fonctions de sécurité
de runtime. Celles-ci garantissent que si une application est compromise au sein d'un
conteneur, le risque de déplacement latéral est considérablement réduit sur tout le réseau.
Conditionnement et déploiement
Comme nous le verrons plus loin dans cet ouvrage, la normalisation des images de
conteneurs et la portabilité de ces images sont extrêmement utiles. Il est relativement
simple de prendre un conteneur en cours d’exécution sur votre bureau et de le déployer
en production sans surcharge opérationnelle importante ou d’effectuer des étapes de
configuration et d’administration supplémentaires. Le mantra de Docker est le suivant
« créer, fournir et exécuter ». Il met en évidence la mentalité « du bureau à la production »
que la conteneurisation apporte au cycle de vie du développement logiciel.
En outre, compte tenu de la spécification des images OCI, comme nous le verrons plus
loin dans ce chapitre, vous pouvez être certain que le système de déploiement fonctionnera
parfaitement tant que votre registre de conteneurs est disponible.
Cgroups
Un groupe de contrôle (cgroup) est une primitive Linux qui offre la possibilité de limiter
les ressources accessibles/attribuables par un groupe de programmes au sein d’un cgroup.
Cette approche permet de remédier au problème de « voisinage bruyant ». Voici la liste des
contrôles effectués par les cgroups :
CPU
Le contrôle du sous-système CPU vous permet d’allouer une certaine quantité de temps
CPU (cpuacct) ou un certain nombre de cœurs (cpuset) à un cgroup. Vous pouvez
ainsi garantir qu’aucun processus ne submerge toutes les ressources du CPU sur une
machine physique.
Mémoire
Le sous-système de mémoire vous permet de signaler et de définir des limites pour
l’utilisation de la mémoire dans un cgroup. Cette méthode fonctionne à la fois pour la
mémoire utilisateur et la mémoire swap.
Blkio
Le sous-système de contrôleur blkio (prononcé Block-i-o) fournit un mécanisme
permettant de limiter les opérations d’entrée/sortie par seconde (IOPS) ) ou de bande
passante (bps) d’un cgroup vers un périphérique de bloc.
PID
Le contrôleur PID (identificateur de processus) définit le nombre maximal de processus
pouvant être exécutés dans le cgroup.
Appareils
Applicable uniquement aux cgroups v1, ce contrôle permet à l’administrateur de
définir des listes d'autorisation/de refus concernant l'accès aux appareils par un cgroup
sur l'ordinateur hôte.
Réseau
Le cgroup classificateur de réseau (net_cls) fournit une interface pour étiqueter les
paquets réseau avec un identificateur de classe (classid).
Le cgroup de priorité réseau (net_prio) fournit une interface pour définir dynamiquement
la priorité du trafic réseau généré par diverses applications.
Dans la plupart des cas, la fonctionnalité de contrôle réseau est mieux assurée par eBPF dans
les versions plus récentes du noyau Linux.
PID (pid)
Fournit le conteneur avec un ensemble de PID numérotés de manière indépendante.
Le premier processus au sein d’un conteneur avec son propre espace de noms PID aura
un PID de 1. Tous les descendants du PID 1 agiront comme un système Unix normal.
Network (net)
Une fonctionnalité extrêmement utile qui vous permet de virtualiser votre infrastructure
réseau. Chaque espace de noms disposera d’un ensemble privé d’adresses IP et de sa
propre table de routage, d'une liste de sockets, de la table de suivi des connexions, d'un
pare-feu et d’autres ressources liées au réseau.
User ID (user)
Similaire à l’espace de noms PID. Il vous permet d’obtenir des privilèges élevés dans le
conteneur, mais pas dans l’ensemble du système. L’espace de noms utilisateur fournit
une séparation d’identification des utilisateurs entre les espaces de noms. L' espace de
noms utilisateur contient une table de mappage qui convertit les ID utilisateur du
point de vue du conteneur au point de vue du système. Ainsi, l’utilisateur racine peut
par exemple présenter l’ID utilisateur 0 dans le conteneur, mais être traité comme l'ID
utilisateur 1 400 000 par le système pour les contrôles de propriété.
Copie en écriture
La copie en écriture (CoW) est une technique de gestion de la mémoire qui copie uniquement
la mémoire lorsqu’une ressource est modifiée (ou écrite). Cette technique réduit la quantité
de mémoire nécessaire.
Capacités
Les fonctionnalités Linux permettent à l’administrateur de contrôler plus étroitement les
fonctionnalités du processus ou du cgroup sur le système hôte. La liste des fonctionnalités
est disponible sur la page de manuel des fonctionnalités (7). Par exemple, si vous souhaitez
exécuter un serveur Web sur le port 80, vous n’avez qu’à donner au cgroup/processus la
fonctionnalité CAP_NET_BIND_SERVICE. Si le serveur Web est compromis, les actions de
l’attaquant sont limitées car le processus ne dispose pas des autorisations système pour
effectuer d’autres commandes administratives.
Seccomp-BPF
Seccomp (SECure COMPuting) est utile pour créer des restrictions absolues sur l’ensemble
des systèmes. Seccomp-BPF permet d'effectuer un contrôle granulaire application par
application. Seccomp-BPF offre une granularité par thread (en mode strict). Il a été ajouté
au noyau dans la version 3.5 (2012).
Seccomp-BPF permet aux programmes Berkeley Packet Filter (BPF) (programmes qui
s’exécutent dans l’espace de noyau) de filtrer les appels système (et leurs arguments) et
de retourner une valeur sur l'événement qui se déroule après la sortie du programme
Seccomp-BPF.
Cette section porte sur ces couches d’abstraction de haut en bas, en expliquant comment
travailler à partir de conteneurs soigneusement orchestrés vers les concepts Linux de bas
niveau qui permettent aux conteneurs de fonctionner.
Orchestrateurs de conteneur
Situés sur la couche supérieure, les orchestrateurs de conteneurs traitent la gestion de la mise
à l’échelle automatique, du remplacement d’instance et de la surveillance d’un écosystème
de conteneurs qui rendent les conteneurs en tant que concept si attrayants. Comme nous
le verrons au chapitre 4 et au Chapitre 5, Kubernetes est la plateforme de planification et
d’orchestration graduée de la Cloud Native Computing Foundation (CNCF).
Les orchestrateurs de conteneurs fournissent généralement les fonctionnalités suivantes :
Logiciel de conteneur
Les démons de conteneur, situés tout en dessous des orchestrateurs, fournissent le logiciel pour
exécuter un démon. Selon l’orchestrateur que vous utilisez, ce processus peut être transparent
pour vous. Essentiellement, les démons de conteneur gèrent le cycle de vie du runtime
• Docker
• Agent Mesos (Mesos)
• Kubelet (Kubernetes)
• LXD (LXC)
• Rkt
Comme nous le verrons plus loin dans ce chapitre, Docker vous permet de prendre une image,
puis de créer des instances de conteneur de celui-ci, en fournissant essentiellement l’interface
utilisateur en tant qu’action non orchestrée. Les agents Mesos ou kubelets sont légèrement
différents car ils sont axés sur des interfaces de ligne de commande ou des API REST.
Runtimes de conteneur
Les runtimes de conteneur fournissent une interface afin d’exécuter des instances de
conteneur. Il existedeux catégories d’interfaces standard à l’échelle du secteur :
• Containerd
• CRI-O
• Docker (jusqu’à Kubernetes v 1.2)
Containerd
Containerd est un runtime de conteneur conforme à l'OCI qui est utilisé dans Docker.
Containerd agit comme une couche d’abstraction entre tous les appels système Linux, qui assure
le fonctionnement d'un conteneur et la configuration OCI standard qui configure un conteneur.
CRI-O
CRI-O est une mise en œuvre de Kubernetes Container Runtime Interface (CRI) qui
active les runtimes compatibles avec OCI. Elle est considérée comme une alternative légère
à l’utilisation de Docker et de containerd. CRI-O prend également en charge l’exécution
de Kata Containers (un conteneur de type machine virtuelle créé par VMware), en étant
extensible à tout autre runtime conforme à l'OCI. Il s'agit donc d'un runtime attractif qui
peut être utilisé pour un certain nombre de cas d’utilisation.
Docker
À ne pas confondre avec la plateforme Docker complète, Docker contient en réalité un
moteur d’exécution qui est ironiquement containerd. Kubernetes a pris en charge Docker
en tant que runtime de conteneur jusqu’à la version v1.20 de Kubernetes.
Conteneurs
L’instance de conteneur est le déploiement et le fonctionnement d’un logiciel tel que défini
par une spécification de conteneur. Le conteneur exécute le logiciel défini (généralement
fourni par une image) selon un certain nombre de paramètres et de limites.
Système d’exploitation
Le système d’exploitation correspond à la structure la plus basse, sur laquelle nos conteneurs
s’exécutent. Dans la plupart des runtimes de conteneur, le noyau est partagé entre toutes les
instances de conteneur.
• Auteur
• Architecture et système d’exploitation
• Utilisateur/groupe pour exécuter le conteneur
• Ports exposés à l’extérieur du conteneur
• Variables d’environnement
• Points d’entrée et commandes
• Répertoire de travail
• Étiquettes d’image
La spécification OCI couvre également la façon dont l’état d’un conteneur est défini et le
cycle de vie du conteneur. L’état du conteneur peut être interrogé par une fonction d’état
(dans containerd, in et runc) et renvoie les attributs suivants :
{
"ociVersion": "0.2.0",
"id": "oci-container1",
"status": "running",
"pid": 4422,
"bundle": "/containers/redis",
"annotations": {
"myKey": "myValue"
}
}
Docker
Docker fournit une plateforme en tant que service (PaaS) qui permet aux utilisateurs
d’exécuter des applications conteneurisées sur un bureau, de manière simplifiée et
standardisée. Docker exécute des images conformes à l'OCI et est souvent un moyen de
tester un déploiement de code avant le déploiement dans un environnement de production.
En outre, la disponibilité générale des logiciels de bureau de Docker offre aux développeurs
un mécanisme facile pour tester le conditionnement et le déploiement de leur code. Il s'agit
donc d'un système attractif pour les développeurs.
app = Flask(__name__)
@app.route('/')
def index():
return "Hello, World"
Nous allons utiliser une image de base. Dans ce cas, nous allons utiliser Ubun-
tu 18.04 dans le registre Docker Hub.
Nous copions le répertoire actuel dans un nouveau répertoire d’images appelé app.
Nous définissons l’application entrypoint en tant que Python3 (il s’agit d’une
bonne pratique Docker/Python).
Dans son intégralité, cette image de conteneur copie sur notre application, puis installe
les exigences de l’application, démarre elle-même et autorise les connexions réseau sur le
port 5000 (le port Flask par défaut).
Pour permettre aux utilisateurs ou à d’autres applications d’accéder à votre conteneur, le
Dockerfile contient une directive, EXPOSE, qui permet à la pile du réseau de conteneurs
d'écouter sur le port spécifié lors du runtime. Nous reviendrons plus en détail sur la
connectivité réseau dans le chapitre 8.
Docker 47
Un Dockerfile est techniquement un mélange d’un runtime
de conteneur et d’une spécification d’image, car il fournit une
sémantique sur le contenu de l’image, ainsi que sur son exécution
(par exemple, les limitations du CPU ou de la mémoire du
cgroup).
Une fois que vous avez créé votre Dockerfile, vous pouvez créer votre image de conteneur à
l’aide de la commande docker build. Cette étape est généralement effectuée avec le chemin
d’accès au fichier actuel (par exemple, docker build), mais vous pouvez également
utiliser une URL (par exemple, docker build https:// github.com/abcd/docker-
example). Une référence complète sur l'utilisation de docker build est disponible dans
la documentation.
Vous devez créer une balise pour votre image afin que vous puissiez la référencer rapidement
et facilement à l’avenir lorsque vous créerez l’image. Pour ce faire, vous pouvez ajouter
l’option--tag lors de la création :
docker build --tag example-flask-container
Lorsque vous exécutez docker build, une sortie semblable à celle-ci sera générée :
[internal] load build definition from Dockerfile
=> transferring dockerfile: 203B
[internal] load .dockerignore
=> transferring context: 2B
[internal] load metadata for docker.io/library/ubuntu:18.04
[1/6] FROM docker.io/libraryubuntu:18.04
[internal] load build context
=> transferring context: 953B
CACHED [2/6] WORKDIR /app
[3/6] COPY requirements.txt requirements.txt
[4/6] RUN pip3 install -r requirements.txt
[5/6] COPY . .
[6/6] CMD [ "python3", "app.py"]
exporting to image
=> exporting layers
=> writing image sha256:8cae92a8fbd6d091ce687b71b31252056944b09760438905b726625831564c4c
=> naming to docker.io/library/example-flask-container
• Utilisez les options docker build. Ces options vous permettent de personnaliser votre
image Docker pour ajouter des fonctions telles que les contrôles cgroup, les balises, les
configurations réseau, etc.
• Utilisez un fichier .dockerignore. Similaire à un fichier .gitignore, un fichier .dockerignore
vérifiera que certains fichiers ou dossiers ne sont pas inclus dans la version de l’image.
• Pour réduire la complexité, les dépendances, les tailles de fichiers et les délais de
création, évitez d’installer des packages supplémentaires ou inutiles.
• U
tilisez des applications multiniveaux. Si vous devez installer des dépendances pour
compiler votre application, vous pouvez le faire pendant le processus de création de
votre image, en copiant uniquement la sortie dans l’image du conteneur. La taille de
votre version d'image est ainsi réduite.
Conteneurs Kata
Les conteneurs Kata sont des conteneurs conformes à l'OCI, qui visent à renforcer la
sécurité. Les conteneurs Kata présentent les fonctions de conteneur léger suivantes :
• Cgroups
• Espaces de noms
• Filtres de capacité
• Filtrage Seccomp
• Contrôle d’accès obligatoire
LXC et LXD
LXC (conteneurs Linux) est l’un des premiers mécanismes de conteneur. LXC utilise princi-
palement les fonctionnalités de cgroup et d’espace de noms du noyau, ainsi qu’un ensemble
standard d’API de bibliothèque pour contrôler les conteneurs.
Registres de conteneurs
Après avoir créé vos images de conteneur, vous aurez besoin d’emplacements pour les
stocker et les servir. Ceux-ci sont appelés registres de conteneurs. Les registres de conteneurs
ont gagné en popularité en raison de leurs mécanismes de déploiement faciles et de leurs
mécanismes de réplication intégrés, qui remplacent les configurations de rsync difficiles
requises pour les référentiels de packages DEB et RPM.
Lors du déploiement d’un conteneur, le système de déploiement de conteneurs téléchargera
l’image à partir du registre vers l'ordinateur hôte. Essentiellement, un registre de conteneurs
agit comme un serveur de fichiers d'image de conteneur hautement disponible (avec
certaines protections). Toutes les plateformes de conteneurisation courantes vous permettent
de configurer un référentiel public ou privé en tant que source pour les images de conteneur.
Bien que ces responsabilités semblent raisonnables, de nombreuses fonctionnalités de
registres de conteneurs sont négligées, alors qu'elles jouent un rôle important dans les
déploiements de conteneurs sécurisés.
Ces fonctions sont les suivantes :
Réplication d'images
Réplication des images vers d’autres registres de conteneurs (globalement)
Authentification
Seuls les utilisateurs autorisés peuvent accéder au registre et à son contenu
Contrôle basé sur les rôles
Restriction des personnes qui peuvent modifier des images et des données au sein du
registre
Analyse des vulnérabilités
Vérification des images pour identifier les vulnérabilités connues
Collecte de déchets
Suppression régulière d’anciennes images
Audit
Fournir des informations fiables sur les modifications apportées au registre de
conteneurs afin de protéger les informations
Voici les produits Cloud natifs actuels (consultez le paysage CNCF pour en savoir plus) :
• Harbor
Bon nombre de ces systèmes sont liés à des fournisseurs spécifiques. Nous allons toutefois
étudier Harbor en détail, car c'est l’un des systèmes de registre de conteneurs open source
les plus populaires.
Installation d'Harbor
Lorsque vous utilisez Harbor, il devient essentiellement un composant critique de vos
pipelines de création et de déploiement. Vous devez l’exécuter sur un hôte qui respecte ces
spécifications recommandées :
Registres de conteneurs 51
Nous vous recommandons d'évaluer les performances de la référence
de disque ou de la configuration afin qu'elles correspondent aux
performances souhaitées. Harbor est essentiellement un serveur de
fichiers, et les performances du disque affectent considérablement
les temps de création et de déploiement.
Vérification de l'installateur
Il est recommandé de vérifier l’intégrité du package téléchargé. Vous devrez ouvrir
l’accès Internet sortant au port TCP/11371 afin d’atteindre le serveur de clés GPG. Pour
vérifier l’installateur :
Tous les paramètres d’installation pour Harbor sont définis dans un fichier appelé harbor.
yml. Les paramètres définis dans ce fichier configurent Harbor pour sa première utilisation
ou lorsqu’il est reconfiguré via le fichier install.sh. Toutes les options de configuration
sont disponibles sur GitHub. Pour commencer, nous allons utiliser les paramètres requis
suivants :
http:
# port for http, default is 80. If https enabled, this port will redirect to https port
port: 80
https:
port: 443
certificate: /your/certificate/path
private_key: /your/private/key/path
harbor_admin_password: Harbor12345
# DB configuration
database:
password: root123
max_idle_conns: 50
max_open_conns: 100
clair:
updaters_interval: 12
jobservice:
max_job_workers: 10
notification:
webhook_job_max_retry: 10
chart:
absolute_url: disabled
log:
level: info
local:
rotate_count: 50
rotate_size: 200M
location: /var/log/harbor
proxy:
http_proxy:
https_proxy:
no_proxy: 127.0.0.1,localhost,.local,.internal,log,db,redis,nginx,core,portal, \
postgresql,jobservice,registry,registryctl,clair
"client_id": "<place-your-client_id-here>",
"client_secret": "<place-your-client_secret-here>",
"tenant_id": "<place-your-tenant-id-here>",
Registres de conteneurs 53
"subscription_id": "<place-your-subscription-here>",
"managed_image_resource_group_name": "CloudNativeAzure-group",
"managed_image_name": "harborImage",
"os_type": "Linux",
"image_publisher": "Canonical",
"image_offer": "UbuntuServer",
"image_sku": "16.04-LTS",
"azure_tags": {
"env": "Production",
"task": "Image deployment"
},
Lorsque vous exécutez le fichier packer build harbor.json, votre image s’intégrera avec
Harbor installé et configuré. Si vous utilisez HTTPS (nous vous le recommandons), vous devrez
modifier le fichier Packer pour y inclure la copie du certificat et des fichiers de clé privée.
1. Connectez-vous au portail Azure et cliquez sur « Créer une ressource », comme illustré
à figure 3-3.
2. Recherchez « registre de conteneur » dans la barre de recherche, puis cliquez sur l’offre
de registre de conteneurs de Microsoft (voir la figure 3-4).
Vous accéderez à un formulaire où vous devrez renseigner des informations de base sur
le registre que vous allez créer (figure 3-5).
Registres de conteneurs 55
Figure 3-5. Première page de la création d'un registre de conteneurs
Registres de conteneurs 57
Figure 3-7. Chiffrement du registre de la mise en réseau du conteneur
6. Cliquez sur « Examiner + créer » pour créer votre registre de conteneurs. Ce déploiement
sera effectué en moins de deux minutes.
Si vous souhaitez déployer votre registre de conteneurs via Terraform, utilisez le code
suivant :
resource "azurerm_resource_group" "rg" {
name = "example-resources" location = "West Europe"
}
identity {
type = "UserAssigned"
identity_ids = [ azurerm_user_assigned_identity.example.id ]
}
Par exemple :
$ docker login https://myharborinstallation.com
Une fois cette opération terminée, Harbor sera en mesure de servir notre image sur
n’importe quel logiciel de conteneur qui la télécharge.
Azure Container Instances
Azure Container Instances (ACI) vous permet de lancer rapidement une instance de
conteneur dans Azure sans avoir à gérer l’infrastructure sous-jacente. Vous obtenez ainsi un
service semblable à Docker, mais dans le Cloud public. ACI permet le déploiement d’images
Azure Container Registry ou d’images Docker à partir de référentiels privés ou publics.
ACI permet également de placer ces instances dans des réseaux privés ou publics en fonction
de l’utilisation des images de conteneurs.
Voici certaines des fonctions supplémentaires proposées par ACI :
En bref, ACI constitue la solution la plus simple pour commencer à exécuter des conteneurs
dans Azure ! ACI vous permet également de tester de nouvelles images de conteneurs sans
créer un environnement totalement distinct.
Quelques mises en garde cependant concernant l'exécution d'ACI :
• Une limite de quatre cœurs/16 Go est appliquée à toutes les instances de conteneur uniques.
• Les paramètres ACI relatifs au CPU et à la mémoire remplaceront tout paramètre
d’exécution que vous avez appliqué à votre image de conteneur.
Cliquez en bas à gauche sur Conteneurs, afin d'accéder à une offre de produits liés aux
conteneurs (voir la figure 3-9). Cliquez sur le lien Instances de conteneurs.
Vous accéderez à un formulaire où vous devrez renseigner des informations de base sur
l'instance de conteneur que vous allez créer (figure 3-10).
Dans cette démo, nous allons attribuer une adresse IP publique à notre instance de conteneur
(afin de pouvoir y accéder via Internet), puis attribuer un nom DNS à l’adresse IP : aci-
demo.eastus.azurecontainer.io (ce nom doit être unique). Nous avons ensuite la possibilité
de rendre les ports TCP ou UDP disponibles à l’extérieur du conteneur.
Enfin, cliquez sur « Examiner + créer » afin de créer l’image de conteneur. Le déploiement
d'une image de démarrage rapide nécessitera environ deux minutes.
Une fois que votre conteneur est déployé, vous pourrez accéder au nom DNS de votre conteneur
dans un navigateur Internet et voir la bannière « Bienvenue dans Nginx ! » (voir la figure 3-13).
Vous pouvez également obtenir une connexion de console à l'instance sur le portail Azure.
$ sudo yum-config-manager \
--add-repo \
https://download.docker.com/linux/centos/docker-ce.repo
$ sudo yum install docker-ce docker-ce-cli containerd.io
Debian/Ubuntu :
$ sudo add-apt-repository \
"deb [arch=amd64] https://download.docker.com/linux/ubuntu \
$(lsb_release -cs) \
stable"
Vous pouvez également installer Docker CE via une image Packer. Voici un exemple
de configuration Packer :
{
"builders": [{
"type": "azure-arm",
"client_id": "<place-your-client_id-here>",
"client_secret": "<place-your-client_secret-here>",
"tenant_id": "<place-your-tenant-id-here>",
"subscription_id": "<place-your-subscription-here>",
"managed_image_resource_group_name": "CloudNativeAzure-group",
"managed_image_name": "DockerCEEngine",
"os_type": "Linux",
"image_publisher": "Canonical",
"image_offer": "UbuntuServer",
"image_sku": "16.04-LTS",
"azure_tags": {
"env": "Production",
"task": "Image deployment"
},
2. Une fois que votre Docker CE s'exécute, démarrez votre conteneur en exécutant :
$ docker run -d <container-name>
3. À l’aide de notre exemple Flask précédant, vous pouvez démarrer votre conteneur en
exécutant :
$ docker run -d -p 5000:5000 http://myharborinstallation.com/demo/ \
example-flask-container
Résumé
Dans ce chapitre, nous avons brièvement discuté des couches d’abstraction qui composent
l’écosystème de conteneurs. Étant donné que l’écosystème de conteneurs est désormais
bien centré sur les spécifications OCI et Kubernetes, il connaît un essor important. Nous
constatons par ailleurs une prolifération de produits de sécurité et de réseau conçus selon la
norme OCI. Dans le chapitre 8, nous étudierons une autre norme de conteneur : Container
Network Interface (CNI). Nous découvrirons comment tirer parti de celle-ci pour configurer
la mise en réseau de votre conteneur.
À mesure que les applications monolithiques sont divisées en microservices, les conteneurs
deviennent les hébergements de référence pour ces microservices. Les microservices
constituent une approche architecturale Cloud native, dans laquelle une application unique est
composée de nombreux services ou composants plus petits, associés librement et déployables
de façon indépendante. Les conteneurs veillent au bon fonctionnement du logiciel lorsqu’il est
déplacé entre différents environnements. Grâce aux conteneurs, les microservices fonctionnent
à l’unisson avec d’autres microservices pour former une application entièrement opérationnelle.
Même si la division des applications monolithiques en services plus petits résout un problème,
elle en crée d'autres plus importants en termes de gestion et de maintenance des applications
sans provoquer de temps d’arrêt significatifs, de mise en réseau des différents microservices, de
stockage distribué, etc. Les conteneurs sont utiles car ils découplent les applications dans des
codes base rapides et plus petits, en se concentrant sur le développement des fonctionnalités.
Toutefois, bien que ce découplage soit propre et facile au début (car il y a moins de conteneurs
à gérer), il devient presque impossible de déboguer, de mettre à jour ou même de déployer des
microservices conteneurisés dans la pile en toute sécurité sans provoquer de défaillance ou
de temps d'arrêt à mesure que le nombre de microservices augmentent dans une application.
La conteneurisation des applications a été la première grande étape vers la création
d’environnements auto-réparables sans aucun temps d’arrêt. Cette pratique devait
néanmoins évoluer davantage, surtout en termes de développement logiciel et de livraison
dans les environnements Cloud natifs. Des planificateurs et des moteurs d'orchestrateur
tels que Mesos, Docker Swarm, Nomad et Kubernetes ont donc été développés par la suite.
Dans ce chapitre et le suivant, nous nous concentrerons sur Kubernetes en raison de sa
maturité et de son adoption étendue dans le secteur.
Google a introduit Kubernetes en 2014, après avoir passé presque une décennie à perfectionner
et à apprendre de son système de gestion de cluster interne, Borg. En termes simples,
Kubernetes est un système d’orchestration de conteneurs open source. Le terme orchestration
de conteneurs désigne principalement le cycle de vie complet de la gestion des conteneurs dans
67
des environnements dynamiques comme le Cloud, où les machines (serveurs) vont et viennent
en fonction des besoins. Un orchestrateur de conteneurs automatise et gère une variété de
tâches, telles que la mise en service, le déploiement, la planification, l’allocation des ressources,
la mise à l’échelle, l’équilibrage de charge et la surveillance de l’intégrité des conteneurs. En
2015, Google a fait don de Kubernetes à la Cloud Native Computing Foundation (CNCF).
Kubernetes (alias K8s) est l’un des éléments les plus largement adoptés d’une solution Cloud
native, car il prend en charge le déploiement, l’évolutivité et la maintenance des applications
conteneurisées. Kubernetes aide les ingénieurs de fiabilité de site (SRE) et les ingénieurs DevOps
à exécuter leur charge de travail dans le Cloud avec résilience, tout en prenant en charge la mise
à l’échelle et le basculement des applications couvrant plusieurs conteneurs entre les clusters.
Voici quelques-unes des fonctions clés prêtes à l'emploi offertes par Kubernetes :
Auto-régénération
L’une des fonctions les plus importantes de Kubernetes est le processus de création de
nouveaux conteneurs lorsqu’un conteneur est défaillant.
Découverte de services
Dans un environnement Cloud natif, les conteneurs passent d’un hôte à un autre. Le
processus qui consiste à déterminer comment se connecter à un service/une application
exécuté(e) dans un conteneur est appelé découverte de services. Kubernetes expose
automatiquement les conteneurs à l’aide de DNS ou de l’adresse IP des conteneurs.
Équilibrage de charge
Pour maintenir l’application déployée dans un état stable, Kubernetes équilibre les
charges et distribue automatiquement le trafic entrant.
Déploiements automatiques
Kubernetes fonctionne avec une syntaxe déclarative, ainsi, vous n’avez pas à vous soucier
du déploiement des applications. Il vous suffit d'indiquer les éléments à déployer et
Kubernetes s'en charge.
Bin packing
Pour tirer le meilleur parti des ressources de calcul, Kubernetes déploie automatiquement
les conteneurs sur le meilleur hôte possible sans gaspiller ou compromettre la
disponibilité globale des autres conteneurs.
Composants de Kubernetes
Le cluster Kubernetes contient deux types de composants de nœud :
Plan de contrôle
Il s’agit du composant de gouvernance du cluster Kubernetes. Il garantit que plusieurs
services importants (par exemple, la planification, le démarrage de nouveaux pods2)
sont toujours en cours d’exécution. L’objectif principal du nœud de plan de contrôle
consiste à garantir l'intégrité et le bon fonctionnement continus du cluster.
Nœuds de travail
Il s’agit des instances de calcul qui exécutent votre charge de travail sur votre cluster
Kubernetes, qui héberge tous vos conteneurs.
La figure 4-1 représente les composants globaux de Kubernetes. Les lignes désignent les
connexions, telles que les nœuds de travail acceptant une connexion parlant à l’équilibreur
de charge, qui distribue le trafic.
1 Managing Kubernetes de Brendan Burns et Craig Tracey (O’Reilly, 2019) ; Kubernetes in Action de Marko
Lukša (Manning, 2018).
2 Les pods sont les plus petites unités de calcul déployables que vous pouvez créer et gérer dans Kubernetes.
Composants de Kubernetes 69
Examinons à présent plus en détails chacun des composants.
Plan de contrôle
Le plan de contrôle est principalement responsable de la prise de décisions globales sur le
cluster Kubernetes, tels que la détection de l’état du cluster, la planification des pods sur
les nœuds et la gestion du cycle de vie des pods. Le plan de contrôle Kubernetes comporte
plusieurs composants, que nous décrirons dans les sous-sections suivantes.
Planificateur Kube
Le planificateur Kube est chargé de déterminer quel nœud de travail exécutera un pod (ou
une unité basique de travail). Nous couvrirons les pods plus en détail plus loin dans ce
chapitre). Le planificateur Kube parle au serveur API, qui détermine quels nœuds de travail
sont disponibles pour exécuter le pod planifié d'une manière optimale. Le planificateur
recherche les pods nouvellement créés qui ne sont pas encore attribués à un nœud, puis
identifie les nœuds possibles comme candidats potentiels. Il évalue chacun d'entre eux en
fonction de différents facteurs, tels que la capacité des ressources de nœud et l’exigence
matérielle, afin de garantir une prise de décision appropriée en matière de planification.
Le nœud présentant le score le plus élevé est choisi pour exécuter le pod. Le planificateur
notifie également le serveur API de cette décision dans un processus appelé liaison.
• Déterminer si un nœud est défaillant et, le cas échéant, prendre des mesures appropriées.
Ce processus est effectué par le contrôleur de nœud.
• Maintenir le nombre adéquat de pods. Ce processus est effectué par le contrôleur de
réplication.
• Joindre les objets de point de terminaison (c.-à-d., les services et les pods). Ce processus
est effectué par le contrôleur de point de terminaison.
etcd
Kubernetes utilise etcd comme une banque de données. etcd est un magasin clé/valeur qui est
responsable de la persistance de tous les objets Kubernetes. Il a été créé à l’origine par l’équipe
de CoreOS et est désormais géré par CNCF. Il est généralement lancé dans une configuration
hautement disponible, et les nœuds etcd sont hébergés sur des instances distinctes.
Nœuds de travail
Un cluster Kubernetes contient un ensemble d'ordinateurs Kubernetes appelées nœuds de
travail qui exécutent les applications conteneurisées. Le plan de contrôle gère les nœuds de
travail et des pods dans le cluster. Certains composants s’exécutent sur tous les nœuds de
travail Kubernetes ; ils sont abordés dans les sous-sections suivantes.
Kubelet
Kubelet est l’agent de démon qui s’exécute sur chaque nœud pour s’assurer que les conteneurs
sont toujours dans un état d’exécution dans un pod, en veillant à leur bon fonctionnement.
Kubelet signale au serveur API les ressources actuellement disponibles (CPU, mémoire,
disque) sur les nœuds de travail afin que le serveur API puisse utiliser le gestionnaire de
contrôleur pour observer l’état des pods. Étant donné que kubelet est l’agent qui s’exécute sur
les nœuds de travail, les nœuds de travail gèrent les tâches d'entretien basiques, telles que le
redémarrage des conteneurs si nécessaire, et effectuent des contrôles d’intégrité systématiques.
Kube-proxy
Kube-proxy est le composant de mise en réseau qui s’exécute sur chaque nœud. KUBE-proxy
surveille tous les services Kubernetes3 du cluster et garantit que lorsqu’une requête à un service
3 Dans Kubernetes, les services sont une façon d’exposer vos pods afin qu’ils puissent être découverts au sein du
cluster Kubernetes.
Composants de Kubernetes 71
particulier est effectuée, elle est acheminée vers le point de terminaison IP virtuel particulier.
Kube-proxy est responsable de la mise en œuvre d’un type d'adresse IP virtuelle pour les services
Maintenant que vous acquis les connaissances de bases sur les composants Kubernetes, nous
allons approfondir ce sujet et nous intéresser d'un peu plus près au serveur API Kubernetes.
Pods
Dans Kubernetes, les pods sont la plus petite unité atomique de base. Un pod est un groupe
d’un ou de plusieurs conteneurs qui sont déployés sur les nœuds de travail. Kubernetes est
responsable de la gestion des conteneurs qui s’exécutent au sein d'un pod. Les conteneurs au
sein d’un pod se retrouvent toujours sur le même nœud de travail et sont étroitement couplés.
Étant donné que les conteneurs au sein d’un pod sont co-localisés, ils s’exécutent dans le même
contexte (c.-à-d. qu’ils partagent le réseau et le stockage). Ce contexte partagé est caractéristique
des espaces de noms Linux, cgroups et d’autres aspects qui maintiennent l’isolement (comme
nous l’avons expliqué au chapitre 3). Les pods obtiennent également une adresse IP unique.
Dans les scénarios typiques, un conteneur unique est exécuté au sein d’un pod, mais dans
certains cas, plusieurs conteneurs doivent travailler ensemble dans un pod. Cette dernière
configuration est généralement appelée conteneur sidecar. L’un des exemples les plus
courants d’exécution d’un conteneur sidecar est l’exécution d’un conteneur de journalisation
pour votre application. Celui-ci expédiera vos journaux vers un stockage externe, tel qu’un
serveur ELK (Elasticsearch, Logstash et Kibana), au cas où votre pod d’application défaille
ou si un pod est supprimé. Les pods constituent également une solution intelligente, car
si un processus plante dans un conteneur, Kubernetes le redémarre instantanément en
fonction des contrôles d’intégrité définis au niveau de l’application.
ReplicaSets
La fiabilité est une caractéristique principale de Kubernetes, et comme personne n’exécute
une seule instance d’un pod, la redondance devient importante. Un ReplicaSet est un objet
Kubernetes qui garantit qu’un ensemble stable de pods de réplica s’exécute pour maintenir
un cluster autorégénérateur. Tout cela est réalisé par la boucle de rapprochement, qui
continue à s’exécuter en arrière-plan pour observer l’état global du cluster Kubernetes.
ReplicaSets utilise la boucle de rapprochement et veille à ce qu'un nouveau pod soit démarré
si l’un des pods plante ou se redémarre, afin de conserver l’état de réplication souhaité.
En général, vous n'interagissez pas directement avec ReplicaSets. Vous utiliserez à la place
l’objet Deployment, qui garantit des mises à jour sans interruption de votre application et
une approche déclarative en matière de gestion et d'exploitation de Kubernetes.
Déploiements
Kubernetes est principalement un orchestrateur axé sur la syntaxe déclarative. Ainsi, pour
déployer de nouvelles fonctions, vous devez indiquer les actions souhaitées à Kubernetes,
afin qu'il détermine comment effectuer ces opérations en toute sécurité. Deployment est
l'un des objets proposés par Kubernetes pour fluidifier la publication de nouvelles versions.
Si vous mettez à jour manuellement les pods, vous devrez les redémarrer et cette opération
provoquera des temps d’arrêt. Bien qu’un ReplicaSet sache comment maintenir le nombre
de pods souhaité, il ne procédera pas à une mise à niveau sans interruption. C'est dans ce
cas que l'objet Deployment s'avère utile, car il permet de déployer des modifications sur des
pods sans interruption, en gardant un nombre prédéfini de pods actif en permanence avant
le déploiement d'un nouveau pod mis à jour.
Services
Pour exposer une application exécutée à l’intérieur d’un pod, Kubernetes propose un
objet appelé Service. Étant donné que Kubernetes est un système très dynamique, il est
nécessaire de s’assurer que les applications s’adressent au back-ends appropriés. Les pods
sont des processus éphémères dans le monde Kubernetes, car ils sont régulièrement
créés ou supprimés. Les pods sont associés à une adresse IP unique. Ainsi, si vous vous
fiez uniquement à l’adresse IP des pods, vous serez certainement confronté à un service
défectueux lorsqu’un pod plante, car celui-ci obtiendra une adresse IP différente après son
redémarrage, même si vous exécutez ReplicaSets. L'objet Service offre une abstraction
en définissant un ensemble logique de pods ainsi qu'une stratégie qui régit l'accès à ces
Espaces de noms
Étant donné que plusieurs équipes et projets sont déployés dans un environnement de
production, il devient nécessaire d’organiser les objets Kubernetes. Pour faire simple, les
espaces de noms sont des clusters virtuels séparés par un partitionnement logique, c’est-à-
dire que vous pouvez regrouper vos ressources, telles que les déploiements, les pods, etc.,
en fonction des partitions logiques. Certaines personnes assimilent les espaces de noms
à des répertoires pour séparer les noms. Chaque objet de votre cluster présente un nom
unique à ce type de ressource particulier, et de même, chaque objet possède un UID unique
sur l’ensemble du cluster. Les espaces de noms vous permettent également de diviser les
ressources de cluster entre plusieurs utilisateurs en définissant des quotas de ressources.
Étiquettes et sélecteurs
À mesure que vous commencez à utiliser Kubernetes et à créer des objets, vous vous
rendrez compte de la nécessité d’identifier ou de marquer vos ressources Kubernetes afin
de les regrouper en entités logiques. Kubernetes propose des étiquettes pour identifier
les métadonnées des objets, ce qui vous permet facilement de regrouper et d’exploiter les
ressources. Les étiquettes sont des paires clé-valeur qui peuvent être associées directement à
des objets tels que les pods, les espaces de noms, les DaemonSets, etc. Vous pouvez ajouter
des étiquettes à tout moment et les modifier à votre guise. Pour rechercher ou identifier vos
ressources Kubernetes, vous pouvez interroger les étiquettes à l’aide de sélecteurs d’étiquettes.
Voici l'exemple d'une étiquette pour un type de niveau d’application :
"tier" : "frontend", "tier" : "backend", "tier" : "midtier"
Annotations
Les annotations sont également des paires clé-valeur, mais contrairement aux étiquettes, qui
sont utilisées pour identifier des objets, les annotations visent à contenir des informations non
identifiantes sur l’objet lui-même. Par exemple, les informations de création, de publication
ou d’image, telles que les horodatages, les ID de publication, la branche Git, les numéros PR,
les hachages d’image et l’adresse des registres peuvent être enregistrées dans une annotation.
Contrôleur d'entrées
Pour que vos services reçoivent du trafic depuis Internet, vous devez exposer les points
de terminaison HTTP et HTTPS de l’extérieur aux services Kubernetes exécutés sur les
pods. Une entrée vous permet d’exposer vos services s’exécutant au sein du cluster vers
le monde extérieur en proposant un équilibrage de charge avec des terminaisons Secure
Sockets Layer/Transport Layer Security (SSL/TLS) à l’aide d’un hébergement virtuel basé
sur le nom. Pour prendre en charge une entrée, vous devez d’abord choisir un contrôleur
StatefulSets
Pour gérer et mettre à l’échelle vos charges de travail avec état sur Kubernetes, vous devez vous
assurer que les pods sont stables (par exemple, un réseau et un stockage stables). StatefulSets
assure la commande des pods et maintient leur unicité (contrairement à ReplicaSets). Un
StatefulSet est un contrôleur qui vous aide à déployer des groupes de pods qui demeurent
résilients pour les redémarrages et les replanifications. Chaque pod d’un StatefulSet dispose
de conventions de nommage uniques dont la valeur ordinale commence à 0. Celles-ci sont
associées à un ID de réseau stable (contrairement à un ReplicaSet, dans lequel la convention
de nommage est aléatoire).
DaemonSets
Dans les environnements ordinaires, nous exécutons un certain nombre de services et d’agents de
démons sur l’hôte, y compris les agents de journalisation et les agents de surveillance. Kubernetes
vous permet d’installer ces agents en exécutant une copie d’un pod sur un ensemble de nœuds
au sein d’un cluster à l’aide de DaemonSets. Tout comme ReplicaSets, les DaemonSets sont de
longs processus qui garantissent que l’état souhaité et l’état observé demeurent identiques. La
suppression d’un DaemonSet supprime également les pods qu’il a précédemment créés.
Tâches
Les tâches sont des entités éphémères dans le monde Kubernetes. Il peut par exemple
s'agir de petites tâches telles que l’exécution d’un script autonome. Les tâches créent des
pods. Les tâches sont exécutées jusqu’à ce qu’elles soient correctement terminées. Il s'agit
de la principale différence entre un pod qui contrôle une tâche et un pod ordinaire qui
continuera à être redémarré et replanifié s’il est terminé. Si un pod de tâche échoue avant
son achèvement, le contrôleur créera un nouveau pod en fonction du modèle.
Cette section couvre Kubernetes en détail, en se concentrant sur les commandes de cluster
de base pour gérer les clusters Kubernetes, les pods et d’autres objets à l’aide de kubectl.
Vous obtiendrez ainsi la liste des ressources de votre nœud et leur statut, ainsi que les
informations de version. Vous pouvez obtenir davantage d’informations à l’aide de -o wide
flag dans la commande get nodes comme suit :
$ ~ kubectl get nodes -o wide
NAME STATUS ROLES AGE VERSION INTERNAL-IP EXTERNAL-IP OS-IMAGE
worker0 Ready <none> 11d v1.17.3 10.240.0.20 <none>
worker1 Ready <none> 11d v1.17.3 10.240.0.21 <none>
worker2 Ready <none> 11d v1.17.3 10.240.0.22 <none>
Pour obtenir encore plus de détails spécifiques sur une ressource ou un collaborateur, vous
pouvez utiliser la commande describe comme suit :
$ ~ kubectl describe nodes worker0
La commande kubectl describe est une commande de débogage très utile. Vous pouvez
éventuellement l’utiliser pour obtenir des informations détaillées sur les pods et d’autres
ressources.
La commande get peut être utilisée pour obtenir des informations supplémentaires sur
les pods, les services, les contrôleurs de réplication, etc. Par exemple, pour obtenir des
informations sur tous les pods, vous pouvez exécuter :
$ ~ kubectl get pods
NAME READY STATUS RESTARTS AGE
busybox-56d8458597-xpjcg 0/1 ContainerCreating 0 1m
Pour obtenir la liste de tous les espaces de noms dans votre cluster, vous pouvez utiliser get
comme suit :
$ ~ kubectl get namespace
NAME STATUS AGE
default Active 12d
kube-node-lease Active 12d
kube-public Active 12d
kube-system Active 12d
kubernetes-dashboard Active 46h
Par défaut, kubectl interagit avec l'espace de nom par défaut. Pour utiliser un espace
de nom différent, vous pouvez passer l'indicateur --namespace pour référencer des objets
dans un espace de noms :
$ ~ kubectl get pods --namespace=default
NAME READY STATUS RESTARTS AGE
busybox-56d8458597-xpjcg 1/1 Running 0 47h
Pour afficher les détails globaux du cluster, vous pouvez utiliser cluster-info comme suit :
$ ~ kubectl cluster-info
Kubernetes master is running at https://40.70.3.6:6443
CoreDNS is running at https://40.70.3.6:6443/api/v1/namespaces/kube-system/services/ \
kube-dns:dns/proxy
Pour modifier l’espace de noms par défaut, vous pouvez utiliser un contexte qui est enregistré
dans le fichier kubectl kubeconfig de votre environnement. Le fichier kubeconfig est le
fichier réel qui indique à kubectl comment trouver votre cluster Kubernetes et s’authentifier
en fonction des secrets qui ont été configurés. Le fichier est généralement stocké dans votre
répertoire personnel sous .kube/. Pour créer et utiliser un nouveau contexte avec un espace
de noms différent comme sa valeur par défaut, procédez comme suit :
$ ~ kubectl config set-context test --namespace=mystuff
Context "test" created.
$ ~ kubectl config use-context test
Switched to context "test"
Assurez-vous que vous disposez réellement du contexte (le cluster Kubernetes test ), sinon
vous ne pourrez pas l’utiliser.
Comme nous l’avons mentionné précédemment, les étiquettes sont utilisées pour organiser
vos objets. Par exemple, si vous souhaitez étiqueter le pod busybox avec une valeur appelée
production, procédez comme suit, en attribuant à l'étiquette le nom environment :
$ ~ kubectl label pods busybox-56d8458597-xpjcg environment=production
pod/busybox-56d8458597-xpjcg labeled
Il peut arriver que vous souhaitiez identifier les problèmes relatifs à vos pods, en essayant
de les déboguer. Pour afficher le journal d'un pod, vous pouvez exécuter la commande logs
sur un nom de pod :
$ ~ kubectl get pods
NAME READY STATUS RESTARTS AGE
busybox-56d8458597-xpjcg 0/1 ContainerCreating 0 2d
$ ~ kubectl logs busybox-56d8458597-xpjcg
Error from server (BadRequest): container "busybox" in pod "busybox-56d8458597-xpjcg" is
waiting to start: ContainerCreating
Il peut arrive que plusieurs conteneurs s'exécutent simultanément au sein d'un pod. Pour
choisir les conteneurs à l’intérieur de celui-ci, vous pouvez utiliser l'indicateur -c.
La commande kubectl run extrait une image publique d’un référentiel de conteneurs et
crée un pod. Vous pouvez par exemple exécuter une image hazelcast comme suit et exposer
également le port du conteneur :
$ ~ kubectl run hazelcast --image=hazelcast/hazelcast --port=5701
deployment.apps/hazelcast created
Vous pouvez également utiliser la syntaxe déclarative dans des manifestes de pod pour
créer des pods. Les manifestes de pod, qui relèvent de la même importance que votre code
d’application, peuvent être écrits à l’aide de YAML ou de JSON. Vous pouvez créer un
manifeste de pod pour exécuter un pod Nginx comme suit :
apiVersion: v1
kind: pod
metadata:
name: nginx
spec:
containers:
Le pod manifeste des informations telles que kind, spec, et d’autres informations en-
voyées au serveur API Kubernetes concerné. Vous pouvez enregistrer le manifeste de pod
avec une extension YAML et utiliser apply comme suit :
$ kubectl apply -f nginx_pod.yaml
pod/nginx created
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx 1/1 Running 0 7s
Lorsque vous exécutez kubectl apply, le manifeste de pod est envoyé au serveur API
Kubernetes, qui planifie instantanément le pod pour qu’il s’exécute sur un nœud sain dans
le cluster. Le pod est surveillé par le processus de démon kubelet, et si le pod plante, il est
replanifié de façon à s'exécuter sur un autre nœud sain.
Continuons à présent et étudions comment mettre en œuvre des contrôles d’intégrité sur
vos services dans Kubernetes.
Contrôles d'intégrité
Kubernetes propose trois types de contrôles d’intégrité HTTP, appelés sondes, pour garantir
le bon fonctionnement de l’application : sondes de disponibilité, sondes de préparation et
sondes de démarrage.
Volumes
Certaines applications nécessitent que les données soient stockées de façon permanente,
mais parce que les pods sont des entités éphémères et sont fréquemment redémarrées
ou supprimées à la volée, toutes les données associées à un pod peuvent également être
supprimées. Les volumes résolvent ce problème avec une couche d’abstraction de disques de
stockage dans Azure. Un volume est un mode de stockage, de récupération et de conservation
des données sur l’ensemble des pods tout au long du cycle de vie de l’application. Si votre
application présente un état, vous devez utiliser un volume pour rendre vos données
persistantes. Azure propose Azure Disk et Azure Files pour créer les volumes de données
qui fournissent cette fonctionnalité.
Requête de volume persistant (PVC). Le PVC sert de couche d’abstraction entre le pod et le
stockage. Dans Kubernetes, le pod monte les volumes à l’aide de PVC et le PVC parle aux
ressources sous-jacentes. Il est important de noter qu’un PVC vous permet de consommer
la ressource de stockage sous-jacente abstraite. Vous pouvez ainsi demander un stockage
préconfiguré. Le PVC définit la taille et le type de disque, puis monte le stockage réel sur
le pod. Ce processus de liaison peut être statique, comme dans un volume persistant (PV)
ou dynamique, dans une classe de stockage par exemple. Par exemple, dans le manifeste
suivant, nous demandons qu'un PersistentVolumeClaim présente un stockage de 1 Gi :
4 Les demandes fractionnaires sont autorisées. Par exemple, un CPU peut être divisé en deux 0,5 s.
L’expression 0,1 équivaut à 100 m.
5 L
a limite et la requête sont mesurées en octets. La mémoire peut être exprimée sous la forme d’un entier simple ou d’un
nombre à virgule fixe à l’aide des suffixes E, P, T, G, M, K ou de leur puissance de deux équivalents Ei, Pi, Ti, Gi, Mi, Ki.
Classe de stockage : dynamique. Les classes de stockage sont des volumes configurés de
manière dynamique pour le PVC (c’est-à-dire qu’elles permettent de créer des volumes
de stockage à la demande). Les classes de stockage fournissent essentiellement aux
administrateurs de cluster un mode de description des classes de stockage proposées.
Chaque classe de stockage dispose d’un provisionneur qui détermine le plug-in de volume
utilisé pour la mise en service des volumes persistants.
Dans Azure, deux types de provisionneurs déterminent le type de stockage qui sera utilisé :
AzureFile et AzureDisk.
AzureFile peut être utilisé avec le mode d’accès ReadWriteMany :
apiVersion: storage.k8s.io/v1
kind: StorageClass
metadata:
name: azurefile
provisioner: kubernetes.io/azure-file
parameters:
skuName: Standard_LRS
La figure 4-3 présente la relation logique entre les différents objets de stockage offerts par
Kubernetes.
Enfin, vous pouvez supprimer un pod à l’aide de kubectl delete pod comme suit :
$ ~ kubectl delete pod nginx
pod "nginx" deleted
Lorsque vous supprimez un pod, vous devez vérifier qu'il n’est pas contrôlé par un
déploiement, car si c'est le cas, il réapparaîtra. Par exemple :
$ ~ kubectl get pods
NAME READY STATUS RESTARTS AGE
hazelcast-84bb5bb976-vrk97 1/1 Running 2 2d7h
nginx-76df748b9-rdbqq 1/1 Running 2 2d7h
$ ~ kubectl delete pod hazelcast-84bb5bb976-vrk97
pod "hazelcast-84bb5bb976-vrk97" deleted
$ ~ kubectl get pods
NAME READY STATUS RESTARTS AGE
hazelcast-84bb5bb976-rpcfh 1/1 Running 0 13s
nginx-76df748b9-rdbqq 1/1 Running 2 2d7h
Un nouveau pod a été dérivé car Kubernetes a observé qu’un état du cluster était
perturbé là où les états souhaités et observés ne correspondaient pas. La boucle de
rapprochement est donc intervenue pour équilibrer les pods. Cet événement peut se
produire car le pod a été déployé via un déploiement, en étant associé à ReplicaSets.
Kubernetes en production
Maintenant que nous avons abordé les notions de base des pods, des concepts Kubernetes et
du fonctionnement du cluster Kubernetes, découvrons comment relier les pods et préparer
un cluster Kubernetes à la production. Cette section explique comment les concepts
abordés dans la section précédente prennent en charge les charges de travail de production
et le déploiement des applications sur Kubernetes.
ReplicaSets
Comme nous l’avons vu, ReplicaSets confère à Kubernetes une capacité de réparation
spontanée au niveau de l’infrastructure en maintenant un nombre stable de pods. En cas de
défaillance au niveau de l’infrastructure (c’est-à-dire les nœuds qui détiennent les pods), le
ReplicaSet replanifiera les pods sur un autre nœud sain. Un ReplicaSet inclut les éléments
suivants :
Sélecteur
ReplicaSets utilise des étiquettes de pod pour rechercher et répertorier les pods
exécutés dans le cluster pour créer des réplicas en cas de défaillance.
Nombre de réplicas à créer
Ce chiffre correspond au nombre de pods à créer.
Modèle
Il spécifie les données associées des nouveaux pods qu’un ReplicaSet doit créer pour
répondre au nombre de pods souhaité.
Dans les cas d’utilisation de production réels, vous aurez besoin d’un ReplicaSet pour
maintenir un ensemble stable de pods exécutés en introduisant une redondance. Vous
ne devez toutefois pas interagir directement avec le ReplicaSet, car il s’agit d’une couche
d’abstraction. Vous devez à la place utiliser des déploiements, qui constituent une option
plus judicieuse pour déployer et gérer les pods.
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
myapp-cnf-replicaset 3 3 3 6s
Déploiements
Dans les environnements de production, le changement est un élément essentiel en
permanence. Vous continuerez à mettre à jour/modifier les applications dans votre
environnement de production à un rythme très rapide, car la tâche la plus courante que
vous effectuerez en production consistera à déployer de nouvelles fonctions de votre
application. Kubernetes propose par défaut l'objet Deployment pour effectuer les mises
à jour propagées, en offrant une expérience transparente à l’administrateur du cluster
et aux utilisateurs. Vous pouvez donc envoyer des mises à jour à vos applications sans
interruption, car Deployment garantit que seul un certain nombre de pods sont arrêtés
pendant la mise à jour. Cette approche est appelée déploiements sans interruption. Par
défaut, les déploiements garantissent qu’au moins 75 % du nombre de pods souhaité sont
fonctionnels. Les déploiements sont la manière fiable, sûre et appropriée de déployer de
nouvelles versions d’applications sans interruption dans Kubernetes.
Fait intéressant, le déploiement gère également les ReplicaSets, car nous avons déclaré avoir
besoin de trois réplicas pour le pod de déploiement. Nous pouvons vérifier ceci comme suit :
$ kubectl get deployment
NAME READY UP-TO-DATE AVAILABLE AGE
nginx-deployment 3/3 3 3 18s
$ kubectl get rs
NAME DESIRED CURRENT READY AGE
nginx-deployment-d46f5678b 3 3 3 29s
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
nginx-deployment-d46f5678b-dpc7p 1/1 Running 0 36s
nginx-deployment-d46f5678b-kdjxv 1/1 Running 0 36s
nginx-deployment-d46f5678b-kj8zz 1/1 Running 0 36s
Ainsi, à partir du fichier manifeste, nous avons créé trois réplicas dans le fichier .spec.rep-
licas. Pour que l'objet Deployment puisse trouver les pods gérés par nginx-deployment,
nous utilisons le champ spec.selector. Les pods sont étiquetés à l’aide du champ de
modèle via metadata.labels.
Déployons maintenant une nouvelle version de Nginx. Supposons que nous souhaitions
épingler la version de Nginx sur 1.14.2. Il nous suffit de changer le manifeste de déploiement
en modifiant le fichier. Nous devons donc modifier la version, puis enregistrer le fichier
manifeste, comme suit :
$ kubectl edit deployment.v1.apps/nginx-deployment
deployment.apps/nginx-deployment edited
L'objet Deployment garantit qu’un certain nombre de pods sont toujours disponibles et en
service, pendant que les anciens pods sont mis à jour. Comme nous l’avons déjà mentionné,
par défaut, un maximum de 25 % des pods sont indisponibles pendant l’exécution d’une
mise à jour. Le déploiement garantit un pourcentage de pic maximal de 25 %, de manière
à ce que seul un certain nombre de pods est créé par rapport au nombre de pods souhaité.
Ainsi, grâce au rollout status, vous pouvez clairement voir qu’au moins deux pods sont
disponibles en permanence, lors du déploiement d'une modification. Vous pouvez à nouveau
obtenir les détails de votre déploiement à l’aide de kubectl describe deployment.
Il est important de noter que pour utiliser la HPA, metrics-server est nécessaire pour collecter
les mesures de kubelets et les exposer dans le serveur API Kubernetes via l’API de métriques,
afin qu'elles soient utilisées par la HPA. Nous commençons par créer une mise à l’échelle
automatique à l’aide de kubectl autoscale pour notre déploiement, comme suit :
$ ~ kubectl autoscale deployment nginx-deployment --cpu-percent=50 --min=3 --max=10
horizontalpodautoscaler.autoscaling/nginx-deployment autoscaled
La commande kubectl précédente créera une HPA qui veillera à ce qu'un nombre minimal
de trois et un nombre maximal de 10 pods soient utilisés dans notre nginx-deployment.
La HPA augmentera ou diminuera le nombre de réplicas pour maintenir une utilisation
moyenne du CPU dans tous les pods à 50 % maximum.
Vous pouvez afficher votre HPA à l’aide des éléments suivants :
$ ~ kubectl get hpa
NAME REFERENCE TARGETS MINPODS MAXPODS REPLICAS AGE
nginx-deployment Deployment/nginx-deployment 0%/50% 3 10 3 6m59s
Nous pouvons ajouter le facteur d’échelle sur lequel nous pouvons créer la mise à l'échelle
automatique à l’aide d'un fichier YAML manifeste HPA qui est lié au déploiement.
Service
Comme nous l’avons mentionné précédemment, l’environnement Kubernetes est un
système très dynamique où les pods sont créés, supprimés et déplacés à un rythme
variable. Cet environnement dynamique ouvre également la voie à un problème
bien connu : trouver les pods de réplicas sur lesquels réside une application, car
plusieurs pods s’exécutent pour un déploiement. Les pods doivent également pouvoir
rechercher les autres pods afin de communiquer avec eux. Kubernetes propose
l'objet Service en tant qu’abstraction pour un point d’entrée unique dans le groupe
de pods. L'objet Service présente une adresse IP, un nom DNS et un port qui ne
Le port représente le port où le service sera disponible et le targetPort est le port de
conteneur réel où le service sera transféré. Dans ce cas, nous avons exposé le port 8080 de
l'application hello-world sur le port cible 8080 sur l’IP de pod :
$ kubectl get svc
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
hello-world-service ClusterIP 10.32.0.40 <none> 8080/TCP 6s
L'adresse IP indiquée est l’IP du cluster et non l’adresse IP réelle de la machine. Si vous
appliquez le SSH sur un nœud de travail, vous pouvez vérifier si le service a été exposé sur le
port 8080 en effectuant simplement une boucle comme suit :
ubuntu@worker0:~$ curl http://10.32.0.40:8080
Hello World
Toute tentative d'accès à cette adresse IP à partir de l’extérieur du cluster (c.-à-d., tout autre nœud
en dehors des nœuds de travail), se soldera par un échec. Vous pouvez donc utiliser NodePort,
qui expose un service sur l'IP de chaque nœud au niveau d'un port défini comme suit :
---
apiVersion: v1
kind: Service
metadata:
name: hello-world-node-service
spec:
type: NodePort
selector:
app: hello-world
ports:
- port: 8080
targetPort: 8080
nodePort: 30767
L’IP dans la commande curl est l’adresse IP physique du nœud de travail (pas l’IP du cluster),
et le port qui est exposé est 30767. Vous pouvez même accéder directement à l’adresse IP
publique du nœud pour le port 30767. La figure 4-5 montre comment l’IP du cluster, le port
de nœud et l’équilibreur de charge interagissent les uns avec les autres.
Entrée
L'objet Service permet d’exposer l’application à l’intérieur et à l’extérieur du cluster.
Toutefois, dans les systèmes de production, nous ne pouvons pas nous permettre d’ouvrir des
ports nouveaux et uniques pour tous les services que nous déployons à l’aide de NodePort, ni
de créer un nouvel équilibreur de charge chaque fois que nous sélectionnons LoadBalancer
comme type de service. Parfois, nous devons déployer un service basé sur HTTP et effectuer
également un déchargement SSL. L' objet Service ne s'avère donc pas utile dans ce cas.
Dans Kubernetes, l’équilibrage de charge HTTP (ou, officiellement l’équilibrage de charge de
couche 7) est effectué par l'objet Ingress.
Pour travailler avec Ingress, nous devons d’abord configurer un contrôleur d’entrées.6
Nous allons configurer Application Gateway Ingress Controller pour Azure Kubernetes
Service (AKS) afin de mieux appréhender ce sujet et découvrir son comportement, et le plus
simple pour y parvenir consiste à étudier ce qui suit :
6 Pour que la ressource Ingress fonctionne, un contrôleur d’entrée doit s'exécuter dans le cluster.
Contrairement aux autres types de contrôleur qui s'exécutent dans le cadre du binaire kube-controller-
manager, les contrôleurs d’entrée ne sont pas démarrés automatiquement avec un cluster. Il existe différents
types de contrôleurs d’entrées. Azure propose notamment AKS Application Gateway Ingress Controller pour
configurer Azure Application Gateway.
Dans le manifeste d’entrées, nous avons créé deux règles et mappé foo.bar.com en tant
qu’hôte à un sous-domaine /bar, dont la destination est notre service précédent hello-
world-node-service.
De même, plusieurs chemins d’accès peuvent être définis pour un domaine et acheminés
vers d’autres services. Les entrées peuvent être configurées de plusieurs façons, en fonction
de vos besoins. Il peut s'agir d’un routage de domaine unique, de plusieurs services ou de
plusieurs domaines acheminés vers plusieurs domaines (voir la figure 4-7).
Vous pouvez sécuriser l'entrée en spécifiant uniquement le certificat TLS encodé en base64 et
la clé. Lorsque vous référencez ce secret dans votre manifeste d’entrée, il s’affiche comme suit :
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: tls-example-ingress
spec:
tls:
- hosts:
- https.mywebsite.example.come
secretName: my_tls_secret
rules:
- host: https.mywebsite.example.come
http:
paths:
- path: /
pathType: Prefix
backend:
service:
name: service1
port:
number: 80
DaemonSet
Comme nous l’avons mentionné plus tôt, DaemonSets est généralement utilisé pour exécuter
un agent sur un nombre de nœuds dans le cluster Kubernetes. L’agent est exécuté à l’intérieur
d’un conteneur extrait par des pods. La plupart du temps, les ingénieurs SRE et DevOps
préfèrent exécuter un agent de journal ou un agent de surveillance sur chaque nœud pour
obtenir la télémétrie et les événements d’application. Par défaut, un DaemonSet crée une
copie d’un pod sur chaque nœud, bien que cela puisse être limité également à l’aide d’un
sélecteur de nœuds. ReplicaSets et DaemonSets présentent de nombreuses similitudes. La
différence principale entre ces deux éléments est l’exigence (avec DaemonSets) de l’exécution
d’une application d’agent unique (par exemple un pod) sur l’ensemble de vos nœuds.
Dans la configuration DaemonSet précédente, nous avons créé un DaemonSet qui déploie
le conteneur Fluentd sur chaque nœud. Nous avons également créé une tolérance, qui ne
planifie pas le nœud Fluentd sur les nœuds maîtres (plan de contrôle).
Tâches
Il se peut que nous devions exécuter un petit script jusqu’à son achèvement. Kubernetes
vous permet de le faire avec l'objet Job. L’objet Job crée et gère les pods qui s’exécutent
jusqu’à leur achèvement, et contrairement aux pods ordinaires, une fois la tâche donnée
terminée, ces pods créés par l'objet Job ne sont pas redémarrés. Vous pouvez utiliser un
YAML Job pour décrire un Jobsimple , comme suit :
apiVersion: batch/v1
kind: Job
metadata:
name: examplejob
spec:
template:
metadata:
name: examplejob
spec:
containers:
- name: examplejob
Ici, nous avons créé un Job pour imprimer une commande shell. Pour créer un Job, vous
pouvez enregistrer le YAML précédent et l’appliquer à l’aide de kubectl apply. Une fois
que vous avez appliqué le manifeste de tâche, Kubernetes créera la tâche et l’exécutera
immédiatement. Vous pouvez vérifier l’état du Job à l’aide de kubectl describe
comme suit :
$ kubectl apply -f job.yaml
job.batch/examplejob created
$ kubectl get jobs
NAME COMPLETIONS DURATION AGE
examplejob 1/1 3s 9s
$ kubectl describe job examplejob
Name: examplejob
Namespace: default
Selector: controller-uid=f6887706-85ef-4752-8911-79cc7ab33886
Labels: controller-uid=f6887706-85ef-4752-8911-79cc7ab33886
job-name=examplejob
Annotations: kubectl.kubernetes.io/last-applied-configuration:
{"apiVersion":"batch/v1","kind":"Job","metadata":
{"annotations":{},"name":"examplejob","namespace":"default"},
"spec":{"template":{"metadat...
Parallelism: 1
Completions: 1
Start Time: Mon, 07 Sep 2020 01:08:53 +0530
Completed At: Mon, 07 Sep 2020 01:08:56 +0530
Duration: 3s
Pods Statuses: 0 Running / 1 Succeeded / 0 Failed
Pod Template:
Labels: controller-uid=f6887706-85ef-4752-8911-79cc7ab33886
job-name=examplejob
Containers:
examplejob:
Image: busybox
Port: <none>
Host Port: <none>
Command:
echo
Cloud Native with Azure
Environment: <none>
Mounts: <none>
Volumes: <none>
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal SuccessfulCreate 61s job-controller Created pod: examplejob-mcqzc
Normal Completed 58s job-controller Job completed
Compte tenu de la complexité sous-jacente liée à la gestion d’un cluster Kubernetes, nous
étudierons comment créer et utiliser ce type de cluster au chapitre 5. Nous découvrirons
également Azure Kubernetes Service, entre autre.
Maintenant que vous avez acquis les notions de base du fonctionnement d'un cluster
Kubernetes, il est temps de mettre ces connaissances en pratique, afin de créer et d’utiliser
un cluster Kubernetes. Plusieurs outils vous permettent de créer et d'exécuter un cluster
Kubernetes dans un environnement de production à haute disponibilité. Certains des outils
les plus courants sont kops, kubeadm, Kubespray et Rancher. Ces outils sont associés à des
playbooks préécrits dédiés à la création d’un cluster, afin qu'il puisse être exécuté dans un
environnement de production de manière fluide grâce à une combinaison de technologies.
Nous n’utiliserons pas d’outil prédéfinis dans ce chapitre. Nous adopterons à la place
une approche plus pratique pour créer un cluster que vous pourrez utiliser dans un
environnement de production.
99
├── K8S_Packer_Image - Machine images for worker and controller
├── Kubernetes_Cluster- Terraform initialization directory for k8s
├── README.md
└── terraform_modules - Terraform modules for k8s cluster
# module.CNA-Terraform-Resource-Grp.azurerm_resource_group.generic-resource-gp
# will be created
+ resource "azurerm_resource_group" "generic-resource-gp" {
+ id = (known after apply)
+ location = "eastus2"
+ name = "K8Scluster"
+ tags = {
+ "cluster" = "k8s-experments"
+ "environment" = "dev"
}
}
Pour continuer, saisissez Oui. Cette étape aboutit à la création d'un groupe de ressources
nommé K8Scluster dans la région eastus2 d’Azure.
OSType: Linux
ManagedImageResourceGroupName: K8Scluster
ManagedImageName: k8s_worker
ManagedImageId: /subscriptions/b5624140-9087-4311-a94a-3b16a2e84792/resourceGroups/ \
K8Scluster/providers/Microsoft.Compute/images/k8s_worker
ManagedImageLocation: eastus2
OSType: Linux
ManagedImageResourceGroupName: K8Scluster
ManagedImageName: k8s_controller
ManagedImageId: /subscriptions/b5624140-9087-4311-a04b-3b16a2e84792/resourceGroups/ \
K8Scluster/providers/Microsoft.Compute/images/k8s_controller
ManagedImageLocation: eastus2
Outputs:
Blob-ID = https://cnabookprod.blob.core.windows.net/k8s-cluster-dev/test
Blob-URL = https://cnabookprod.blob.core.windows.net/k8s-cluster-dev/test
Primary-Access-Key = ymMDE1pUQgtuxh1AOJyUvlvfXnmjAeJEHl2XvMmQ38AZp1O8Z0Xk4Hrw4N/ \
d8yovb8FQ5VzqtREH94gzPCzAWCA==
Cette étape aboutit à la création d'un compte de stockage nommé cnabookprod. Mettez à
jour votre bash_pro file avec une valeur de clé d’accès principal à l’aide du nom de variable
ARM_ACCESS_KEY :
export ARM_ACCESS_KEY=ymMDE1pUQgtuxh1AOJyUvlvfXnmjAeJEHl2XvMmQ38AZp1O8Z0Xk4Hrw4N/ \
d8yovb8FQ5VzqtREH94gzPCzAWCA==
subnet_id = /subscriptions/b5624140-9087-4311-a04b-3b16a2e84792/resourceGroups/ \
K8Scluster/providers/Microsoft.Network/virtualNetworks/cna-k8s-vnet/subnets/cna-k8s-subnet
vnet_id = /subscriptions/b5624140-9087-4311-a04b-3b16a2e84792/resourceGroups/ \
K8Scluster/providers/Microsoft.Network/virtualNetworks/cna-k8s-vnet
Cette étape aboutit à la création d'un réseau virtuel avec un CIDR de 10.240.0.0/24 nommé
cnak-8s-vnet.
module "Worker0" {
source = "../../terraform_modules/Azure_PublicIP"
name_of_ip = "Worker0"
resource-grp-name = "K8Scluster"
azure-dc = "eastus2"
env = "dev"
type-of-cluster = "k8s-experments"
}
module "Worker1" {
source = "../../terraform_modules/Azure_PublicIP"
name_of_ip = "Worker1"
module "Controller0" {
source = "../../terraform_modules/Azure_PublicIP"
name_of_ip = "Controller0"
resource-grp-name = "K8Scluster"
azure-dc = "eastus2"
env = "dev"
type-of-cluster = "k8s-experments"
}
module "Controller1" {
source = "../../terraform_modules/Azure_PublicIP"
name_of_ip = "Controller1"
resource-grp-name = "K8Scluster"
azure-dc = "eastus2"
env = "dev"
type-of-cluster = "k8s-experments"
}
module "Controller2" {
source = "../../terraform_modules/Azure_PublicIP"
name_of_ip = "Controller2"
resource-grp-name = "K8Scluster"
azure-dc = "eastus2"
env = "dev"
type-of-cluster = "k8s-experments"
}
Une fois Terraform initialisé, vous pouvez appliquer la configuration à l’aide de terraform
apply comme suit, afin de créer les adresses IP publiques :
$ terraform apply
.
.
Apply complete! Resources: 7 added, 0 changed, 0 destroyed.
Releasing state lock. This may take a few moments...
Outputs:
Controller0_IP = 52.252.6.89
Controller0_IP_ID = /subscriptions/b5624140-9087-4311-a04b-3b16a2e84792/resourceGroups/ \
K8Scluster/providers/Microsoft.Network/publicIPAddresses/Controller0
Controller1_IP = 52.254.50.7
Controller1_IP_ID = /subscriptions/b5624140-9087-4311-a04b-3b16a2e84792/resourceGroups/ \
K8Scluster/providers/Microsoft.Network/publicIPAddresses/Controller1
Controller2_IP = 52.251.58.212
Controller2_IP_ID = /subscriptions/b5624140-9087-4311-a04b-3b16a2e84792/resourceGroups/ \
K8Scluster/providers/Microsoft.Network/publicIPAddresses/Controller2
PublicIP_ID = /subscriptions/b5624140-9087-4311-a04b-3b16a2e84792/resourceGroups/ \
Le code précédent créera sept adresses IP publiques : six pour les instances de nœud (de
travail et de contrôleur) et une pour l’équilibreur de charge. Nous pouvons désormais créer
l’équilibreur de charge et l'associer à l’IP de l’équilibreur de charge en accédant au répertoire
Chapter5/Kubernetes_Cluster/EK8S-API-Public-loadbalancer et en initialisation Terraform.
Nous pouvons ensuite utiliser terraform apply une nouvelle fois, comme suit :
$ terraform apply
.
.
.
Apply complete! Resources: 4 added, 0 changed, 0 destroyed.
Releasing state lock. This may take a few moments...
Outputs:
lb_backend_pool = /subscriptions/b5624140-9087-4311-a04b-3b16a2e84792/resourceGroups/ \
K8Scluster/providers/Microsoft.Network/loadBalancers/k8s_master_lb/backendAddressPools/ \
k8s-control-plane
load_balancer_frontend_id = /subscriptions/b5624140-9087-4311-a04b-3b16a2e84792/ \
resourceGroups/K8Scluster/providers/Microsoft.Network/loadBalancers/k8s_master_lb/ \
frontendIPConfigurations/K8S-frontend-config
load_balancer_id = /subscriptions/b5624140-9087-4311-a04b-3b16a2e84792/resourceGroups/ \
K8Scluster/providers/Microsoft.Network/loadBalancers/k8s_master_lb
load_balancer_private_ip =
load_balancer_public_ip = /subscriptions/b5624140-9087-4311-a04b-3b16a2e84792/ \
resourceGroups/K8Scluster/providers/Microsoft.Network/publicIPAddresses/k8s_master_lb
Cette procédure crée un équilibreur de charge et appliquer les règles d’équilibreur de charge
que nous avons prédéfinies dans le fichier de configuration Terraform.
Dans la configuration précédente (main.tf), l’ID d’image a été mis à jour pour le nœud
du contrôleur (maître), ainsi que le chemin d’accès à la clé SSH. Vous pouvez maintenant
générer une paire de clés SSH à l’aide de la commande ssh-keygen pour ssh_key. De même,
vous pouvez mettre à jour le fichier de configuration du nœud de travail, puis initialiser
Terraform comme avant. Une fois l’initialisation terminée, vous pouvez utiliser terraform
apply pour créer les instances de travail et de contrôleur :
$ terraform apply
.
.
.
.
Apply complete! Resources: 17 added, 0 changed, 0 destroyed.
Releasing state lock. This may take a few moments...
Outputs:
master_machine_id = [
[
"/subscriptions/b5624140-9087-4311-a04b-3b16a2e84792/resourceGroups/K8Scluster/ \
providers/Microsoft.Compute/virtualMachines/controller0",
"/subscriptions/b5624140-9087-4311-a04b-3b16a2e84792/resourceGroups/K8Scluster/ \
providers/Microsoft.Compute/virtualMachines/controller1",
"/subscriptions/b5624140-9087-4311-a04b-3b16a2e84792/resourceGroups/K8Scluster/ \
providers/Microsoft.Compute/virtualMachines/controller2",
],
]
master_machine_name = [
[
"controller0",
"controller1",
"controller2",
],
]
master_machine_private_ips = [
[
"10.240.0.10",
"10.240.0.11",
Une fois la commande terraform apply exécutée, les nœuds seront configurés pour votre
cluster Kubernetes (voir figure 5-1).
[all:vars]
ansible_user = ubuntu
ansible_ssh_private_key_file = /Users/SSH_KEYS/id_rsa
Une fois le fichier hosts mis à jour, nous devons mettre à jour le groupvars (situé dans le
fichier all du répertoire Chapter5/Ansible-Playbooks/group_vars) avec loadbalancer_
public_ip et la clé de chiffrement. Étant donné que Kubernetes stocke une variété de
données, notamment l’état du cluster, les configurations d'application et les secrets, nous
devons chiffrer ces données au repos. Kubernetes prend en charge le chiffrement des
données de cluster au repos.
Pour créer une clé de chiffrement, vous pouvez simplement émettre la commande suivante
sur votre terminal et coller le secret généré dans le fichier group_vars/all comme suit :
$ head -c 32 /dev/urandom | base64
Uvivn+4ONy9yqRf0ynRVOpsEE7WsfyvYnM7VNakiNeA=
Vous devrez également mettre à jour l’IP de l’équilibreur de charge. Voici à quoi devrait
ressembler le group_vars définitif :
---
#Change loadbalancer_public_ip
loadbalancer_public_ip : 52.254.73.23
controller_private_ips_list : 10.240.0.10,10.240.0.11,10.240.0.12
# Keep k8s_internal_virtual_ip as it is
k8s_internal_virtual_ip: 10.32.0.1
k8s_cluster_cidr: "10.200.0.0/16"
k8s_cluster_name: "cloud-native-azure"
# Generate your own encryption_key : "head -c 32 /dev/urandom | base64"
encryption_key: Uvivn+4ONy9yqRf0ynRVOpsEE7WsfyvYnM7VNakiNeA=
#ETC config below for systemd file, place private ip's. No need to change
controller_0_ip: 10.240.0.10
controller_1_ip: 10.240.0.11
controller_2_ip: 10.240.0.12
Une fois que la mise à jour des fichiers est terminée, nous devons installer les outils côté
client sur le système local, principalement kubectl, cfssl et cfssljson. CFSSL est le
kit de ressources de l'infrastructure à clé publique/Transport Layer Security (PKI/TLS) de
Cloudflare pour la signature, la vérification et le regroupement des certificats TLS en général.
Nous utiliserons cette boîte à outils pour générer le certificat TLS pour les nœuds Kubernetes.
Pour installer le binaire kubectl sur OS X, nous pouvons effectuer les opérations suivantes :
$ curl -LO "https://storage.googleapis.com/kubernetes-release/release/$(curl -s https:// \
storage.googleapis.com/kubernetes-release/release/stable.txt)/bin/darwin/amd64/kubectl"
$ chmod +x ./kubectl
$ sudo mv ./kubectl /usr/local/bin/kubectl
Vous pouvez vérifier le bon fonctionnement du client kubectl en exécutant les commandes
suivantes :
$ kubectl version --client
Client Version: version.Info{Major:"1", Minor:"17", GitVersion:"v1.17.3",
GitCommit:"06ad960bfd03b39c8310aaf92d1e7c12ce618213", GitTreeState:"clean",
BuildDate:"2020-02-11T18:14:22Z", GoVersion:"go1.13.6", Compiler:"gc",
Platform:"darwin/amd64"}
Nous sommes maintenant prêts à créer nos nœuds de contrôleur avec Ansible. Accédez
au répertoire du playbook Ansible (Chapter5/Ansible-Playbooks) et exécutez la commande
suivante :
$ ansible-playbook -vi hosts controllers.yaml
L'exécution de cette commande peut nécessiter un certain temps. Une fois terminée, la sortie
suivante doit s'afficher :
PLAY RECAP *********************************************************************************
inventory_hostname=controller0 : ok=43 changed=39 unreachable=0 failed=0 skipped=4
rescued=0 ignored=0
inventory_hostname=controller1 : ok=22 changed=19 unreachable=0 failed=0 skipped=7
rescued=0 ignored=0
inventory_hostname=controller2 : ok=22 changed=19 unreachable=0 failed=0 skipped=7
rescued=0 ignored=0
Cette étape permet de déployer et de configurer les nœuds de travail avec les binaires
Kubernetes nécessaires.
Outputs:
route_table_id = /subscriptions/b5624140-9087-4311-a04b-3b16a2e84792/resourceGroups/ \
K8Scluster/providers/Microsoft.Network/routeTables/k8s-pod-router
Cette étape permet de configurer la table de route des pods dans Azure. Nous pouvons enfin
créer les routes en accédant au répertoire final, Chapter5/Kubernetes_Cluster/H-k8S_Route-
creation, et en initialisation Terraform comme auparavant. Une fois initialisé, nous pouvons
exécuter terraform apply :
module.route0.azurerm_route.generic-routes: Creating...
module.route1.azurerm_route.generic-routes: Creating...
module.route0.azurerm_route.generic-routes: Creation complete after 4s [id=/subscriptions/
b5624140-9087-4311-a04b-3b16a2e84792/resourceGroups/K8Scluster/providers/Microsoft.Network/
routeTables/k8s-pod-router/routes/k8s-pod-router0]
module.route2.azurerm_route.generic-routes: Creating...
module.route1.azurerm_route.generic-routes: Creation complete after 5s [id=/subscriptions/
b5624140-9087-4311-a04b-3b16a2e84792/resourceGroups/K8Scluster/providers/Microsoft.Network/
routeTables/k8s-pod-router/routes/k8s-pod-router1]
module.route2.azurerm_route.generic-routes: Creation complete after 4s [id=/subscriptions/
b5624140-9087-4311-a04b-3b16a2e84792/resourceGroups/K8Scluster/providers/Microsoft.Network/
routeTables/k8s-pod-router/routes/k8s-pod-router2]
Le fichier kubeconfig sera alors téléchargé et stocké localement afin que vous puissiez accéder
et interagir avec le cluster. Vérifiez si vous pouvez le faire en exécutant kubectl get nodes
sur votre ordinateur local comme suit :
$ kubectl get nodes
NAME STATUS ROLES AGE VERSION
worker0 Ready <none> 27m v1.17.3
La sortie répertorie les nœuds de travail de votre cluster. Vous pouvez maintenant utiliser ce
cluster pour expérimenter et explorer les fonctions abordées dans ce chapitre. Même s'il ne
s’agit pas d’un cluster prêt à la production, vous savez désormais comment créer, exécuter et
gérer un cluster Kubernetes à partir de zéro.
Maintenant que vous connaissez la procédure la plus complexe (semi-automatisée), jetons
un coup d’œil à la méthode privilégiée la plus simple pour exécuter un cluster Kubernetes
de production dans Azure.
Maintenant que vous comprenez les avantages d’AKS, créons un cluster AKS. Vous disposez
de deux méthodes simples pour y parvenir : utilisez le portail Azure (l’approche manuelle)
ou utilisez Terraform (l’approche automatisée).
Par ailleurs, dans Terraform, vous pouvez accéder au répertoire AKS du référentiel /cloud_
native_azure/Chapter5/AKS et exécuter la commande suivante :
$ terraform apply
Cliquez sur Appliquer, afin qu'un cluster Kubernetes de trois nœuds soit exécuté en quelques
minutes (figure 5-3).
Pour télécharger le fichier kubeconfig, vous pouvez utiliser la commande Azure CLI de
votre système local pour obtenir des informations d’identification d’accès pour votre cluster
Kubernetes géré comme suit :
az aks get-credentials --resource-group azure-k8stest --name akstest --file config
Bien que vous puissiez créer à peu près n’importe quelle ressource et déployer des applica-
tions à ce stade, il ne s'agit pas d’un cluster de production. Il existe de nombreuses ressourc-
es en ligne1 susceptibles de vous guider dans la création de clusters de production.
Grâce à ces connaissances, nous sommes prêts à passer à la suite et à découvrir Helm, qui
sert principalement d’outil pour rationaliser l’installation et la gestion des applications
Kubernetes.
Déploiement d’applications et de services avec Helm : un gestionnaire de package pour Kubernetes 113
Figure 5-4. Référentiel de tableau Helm et interaction avec les clients
Essentiellement, Helm extrait des tableaux ou des packages à partir d’un référentiel central,
puis les installe/publie sur le cluster Kubernetes.
Cette recherche est effectuée parmi les données locales sur votre ordinateur.
L’autre méthode de recherche des référentiels Helm consiste à effectuer une recherche dans
le hub Helm. Le hub Helm se compose de plusieurs référentiels publics. Ainsi, si vous ne
trouvez pas de tableau dans votre référentiel local, vous pouvez toujours le rechercher dans
le hub. Dans l'exemple suivant, nous avons cherché tous les tableaux « kafka » :
$ ~ helm search hub kafka
URL CHART VERSION APP VERSION
DESCRIPTION
https://hub.helm.sh/charts/kafkaesque/imagepuller 1.0.0 1.0
Pull container images to your nodes so that the...
https://hub.helm.sh/charts/kafkaesque/pulsar 1.0.26 1.0
Apache Pulsar Helm chart for Kubernetes
https://hub.helm.sh/charts/kafkaesque/pulsar-mo... 0.1.5 1.0
A Helm chart for the Pulsar Monitor application
https://hub.helm.sh/charts/kafkaesque/teleport 1.0.0
Teleport Community
https://hub.helm.sh/charts/bitnami/kafka 11.8.4 2.6.0
Apache Kafka is a distributed streaming platform.
https://hub.helm.sh/charts/stable/kafka-manager 2.3.1 1.3.3.22
A tool for managing Apache Kafka.
https://hub.helm.sh/charts/touk/hermes 0.3.1 1.5.2
A Helm chart for Kubernetes of Hermes, a reliab...
Déploiement d’applications et de services avec Helm : un gestionnaire de package pour Kubernetes 115
REVISION: 1
TEST SUITE: None
NOTES:
1. Get the application URL by running these commands:
NOTE: It may take a few minutes for the LoadBalancer IP to be available.
You can watch the status of by running 'kubectl get svc -w my-first-server-tomcat'
export SERVICE_IP=$(kubectl get svc --namespace default my-first-server-tomcat -o \
jsonpath='{.status.loadBalancer.ingress[0].hostname}')
echo http://$SERVICE_IP:
Ici, nous avons essayé de déployer un serveur Tomcat, en sélectionnant le nom de version
my-first-server. À l’aide de kubectl, vous pouvez vérifier les ressources créées pour le tableau
Tomcat :
$ ~ kubectl get svc --namespace default my-first-server-tomcat
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
my-first-server-tomcat LoadBalancer 10.32.0.3 <pending> 80:31495/TCP 56s
image:
webarchive:
repository: ananwaresystems/webarchive
tag: "1.0"
tomcat:
.
.
.
resources: {}
# limits:
# cpu: 100m
# memory: 256Mi
# requests:
# cpu: 100m
# memory: 256Mi
nodeSelector: {}
tolerations: []
affinity: {}
Pour modifier la valeur, vous pouvez utiliser l'argument --values ou --set. Le premier
présente l'avantage de pouvoir indiquer un fichier YAML que vous pouvez transmettre lors
de l’installation d’un tableau. Les valeurs du tableau sont ainsi remplacées. Par exemple,
dans le tableau précédent, si nous voulons modifier les valeurs par défaut, nous pouvons
créer un fichier YAML comme suit et l’enregistrer sous custom_vals.yaml :
Vous pourrez ainsi mettre à niveau new-v2-install avec le même tableau (stable/tomcat),
tout en mettant à jour de nouvelles valeurs dans le fichier new_vals.yaml.
Déploiement d’applications et de services avec Helm : un gestionnaire de package pour Kubernetes 117
Restaurer une version
Si vous avez besoin de restaurer un tableau déployé (version), vous pouvez simplement
utiliser l'option helm rollback comme suit :
$ ~ helm rollback my-first-server 1
Rollback was a success! Happy Helming!
$ ~
Dans le répertoire, Helm s’attend à ce que le fichier présente la même structure et les mêmes
noms, car Helm les réserve. Chaque élément du répertoire sert un objectif spécifique :
Le fichier Chart.yaml est nécessaire pour créer le tableau, et il contient les champs suivants :
apiVersion: The chart API version (required)
name: The name of the chart (required)
version: A SemVer 2 version (required)
kubeVersion: A SemVer range of compatible Kubernetes versions (optional)
description: A single-sentence description of this project (optional)
type: The type of the chart (optional)
keywords:
- A list of keywords about this project (optional)
home: The URL of this projects home page (optional)
sources:
- A list of URLs to source code for this project (optional)
dependencies: # A list of the chart requirements (optional)
- name: The name of the chart (nginx)
version: The version of the chart ("1.2.3")
repository: The repository URL ("https://example.com/charts") or alias ("@repo-name")
condition: (optional) A yaml path that resolves to a boolean, used for
enabling/disabling charts (e.g. subchart1.enabled )
tags: # (optional)
- Tags can be used to group charts for enabling/disabling together
enabled: (optional) Enabled bool determines if chart should be loaded
import-values: # (optional)
- ImportValues holds the mapping of source values to the parent key to be imported.
Each item can be a string or pair of child/parent sublist items.
alias: (optional) Alias to be used for the chart. Useful when you have to add the same
chart multiple times
maintainers: # (optional)
- name: The maintainers name (required for each maintainer)
email: The maintainers email (optional for each maintainer)
url: A URL for the maintainer (optional for each maintainer)
icon: A URL to an SVG or PNG image to be used as an icon (optional).
appVersion: The version of the app that this contains (optional). This needn't be SemVer.
deprecated: Whether this chart is deprecated (optional, boolean)
annotations:
example: A list of annotations keyed by name (optional).
Vous pouvez ensuite modifier les fichiers dans le répertoire du tableau et les conditionner
dans une archive de tableau :
$ helm package examplechart
Archived examplechart.1.-.tgz
Une fois que vous avez conditionné votre tableau, vous pouvez l’utiliser avec helm install
et créer une version.
Déploiement d’applications et de services avec Helm : un gestionnaire de package pour Kubernetes 119
Résumé
Dans ce chapitre, vous avez appris à créer un cluster Kubernetes, à la fois manuellement
à partir de zéro à l'aide d'Azure et avec Azure AKS en tant que service géré. Nous avons
également découvert Helm, en tant que gestionnaire de package Kubernetes qui vous
permet de créer et de gérer vos applications avec un seul modèle.
Avant de passer à l’étape suivante, nous tenons à souligner que Kubernetes est difficile
à gérer à lui seul(en particulier dans la production). Il ne s'agit certainement pas d'une
solution miracle capable de faciliter la gestion des applications dans les environnements
Cloud natifs. Compte tenu de la complexité sous-jacente de la gestion d’un cluster
Kubernetes, il est évident qu’une approche telle qu'AKS constitue une meilleure solution
pour gérer les services exécutés sur des clusters Kubernetes. AKS vous soulage de la gestion
de l’infrastructure sous-jacente ou des parties mobiles de l’écosystème, car la plupart des
points critiques, comme la haute disponibilité et la redondance du cluster Kubernetes, sont
pris en charge.
Ceci étant dit, passons au chapitre 6, qui traite de l’observabilité des systèmes distribués et
de la fiabilité des applications Cloud natives.
L’évolution rapide des systèmes Cloud natifs a introduit des complexités en matière de
configuration d’infrastructure, de déploiement d’infrastructure et de gestion de logiciels.
La conception des applications est axée sur la résilience, en nécessitant une compréhension
plus approfondie de l’infrastructure sous-jacente de l’environnement Cloud, y compris les
modes de défaillance et les goulots d’étranglement. Il est plus essentiel que jamais d'obtenir
la visibilité nécessaire sur la pile d’applications en raison de la multitude de nouveaux
éléments mobiles et des changements de conception des applications actuelles.
Dans ce chapitre, nous allons introduire le concept d’observabilité et expliquer pourquoi il est
nécessaire dans le monde Cloud natif d’aujourd’hui. Vous en apprendrez davantage sur les trois
piliers de l’observabilité (journaux, métriques et traces), en découvrant comment ils interagissent
pour créer des systèmes observables. Nous allons également examiner divers outils Cloud natifs
bien connus qui peuvent être utilisés pour créer un système observable et démontrer comment
l’observabilité est un sur-ensemble de la surveillance. Enfin, vous découvrirez comment tirer
parti d’Azure en tant que plateforme Cloud pour optimiser l’observabilité de vos applications,
de l’infrastructure sous-jacente et de la pile de mise en réseau.
Introduction à l’observabilité
La première chose à comprendre au sujet de l’observabilité c'est sa définition elle-même.
Le terme observabilité découle du monde de la théorie du contrôle en mathématiques, qui
traite principalement de la création d’un moyen de contrôler les systèmes dynamiques à
l’aide d’un contrôleur à l’aide de retours du système lui-même. Dans la théorie du contrôle,
l’observabilité est la capacité de mesurer l’état interne d’un système à partir des connaissances
des sorties externes. En ce qui concerne l’ingénierie logicielle, l’observabilité implique la
détermination de l'état exact d’une application à partir de ses sorties. En concevant votre
application et votre infrastructure afin qu’elles soient observables, vous serez essentiellement
en mesure de déterminer pourquoi un problème survient et comment vous pourrez le
121
résoudre. L’objectif sous-jacent de rendre un système observable est de permettre à un
ingénieur d'identifier clairement un problème, de sa cause à son effet.
L’observabilité est encore plus importante dans l’infrastructure Cloud native actuelle en raison
de l’environnement dynamique et distribué où les logiciels et les systèmes sont susceptibles
de planter. L’essor des microservices, des conteneurs et de l’informatique sans serveur a
entraîné un maillage complexe de services interconnectés qui effectuent de nombreux appels
entre eux. Lorsque ces réseaux de services entrelacés se comportent mal, il est presque
impossible d'identifier la cause profonde du problème sans perturber les activités. Il devient
essentiel d'identifier rapidement un problème dans l’environnement sous-jacent de services
complexes, afin de ne pas compromettre les activités. L’observabilité résout ce problème, en
vous permettant d'interroger vos systèmes et d’obtenir rapidement des réponses.
Avant de discuter de l'utilité de l’observabilité au sein d'environnements distribués modernes,
expliquons la définition d'un système observable et discutons du principe sous-jacent et de
la philosophie qui sous-tend l’idée de développer l’observabilité dans les systèmes.
Métriques
Les métriques représentent les données numériques mesurées sur un intervalle de temps.
Les métriques sont généralement collectées en exécutant un agent sur un hôte, qui envoie
périodiquement les données dans une banque de données centrale, avant de les regrouper
et de les représenter sur les tableaux de bord. Les métriques sont ensuite utilisées pour
créer des systèmes d’alerte, car elles sont stockées dans une base de données de séries
chronologiques. Par exemple, une métrique est une requête par seconde (qps).
Journaux
Les journaux représentent les événements qui se produisent dans un système (application
et infrastructure). Les journaux contiennent des détails sur l’état interne et les événements.
Ils sont généralement écrits et stockés sur le système d’application dans un format structuré
qui peut être analysé facilement. Une architecture de journalisation performante est l’outil
le plus fondamental pour obtenir la plupart des informations dans un système. Il s'agit
également du premier outil de débogage utilisé par les développeurs de logiciels. Voici un
exemple de journaux d’accès simples au serveur Apache :
10.185.248.71 - - [09/Jan/2015:19:12:06 +0000] 808840 "GET /inventoryService/inventory/ \
purchaseItem?userId=20253471&itemId=23434300 HTTP/1.1" 500 17 "-" \
"Apache-HttpClient/4.2.6 (java 1.5)"
Un système comprenant des journaux, des métriques et des traces ne constitue pas
nécessairement un système observable pour autant. Les trois piliers présentent des
avantages et des inconvénients, que nous allons aborder dans le reste du chapitre. Ils ne
constituent individuellement qu'un point de départ puisqu’ils vous permettent d’identifier
un problème, sans toutefois répondre directement au cas d’utilisation ou aux besoins
de votre entreprise. Pour tirer parti des piliers, vous devez tous les utiliser ensemble, en
tenant compte des facteurs qui influent sur votre entreprise. Si vous collectez des données
des métriques séparément à partir des journaux et des traces, vous risquez de perdre du
contexte et de n'observer qu'un seul système sous-jacent. L’observabilité appliquée à une
approche unifiée implique la collecte et la préservation du contexte sous-jacent, ainsi que
toute sa richesse et sa dimension.
Surveillance des métriques avec Prometheus dans un monde Cloud natif 125
Pour prendre en charge la nouvelle ère des applications Cloud natives, l’écosystème
Prometheus se compose des cinq principaux composants suivants :
Serveur Prometheus
Chargé du scraping des métriques et de leur stockage dans une base de données de
séries chronologiques.
Bibliothèques client
Utilisées pour instrumenter le code de l’application et envoyer les données de
métriques extraites au serveur Prometheus. Les bibliothèques client sont disponibles
dans différents langages, notamment C#, Python, Java et Ruby.
Passerelle Push
Utilisées pour prendre en charge des tâches éphémères.
Exportateurs
Exécutés à côté des applications qui ne peuvent pas être instrumentées directement,
telles que HAP- roxy et statsd, pour extraire des métriques qui peuvent être envoyées
au serveur Prometheus dans le format souhaité.
Alertmanager
Reçoit des alertes du serveur Prometheus en envoyant les notifications de manière
efficace. Alertmanager exécute cette tâche de plusieurs façons cohérentes et efficaces :
• Il regroupe les alertes d’un type similaire afin de réduire le nombre d’alertes
envoyées lors d’une panne importante.
• Il peut limiter les notifications envoyées au système de réception.
• Il permet la suppression des notifications des alertes sélectionnées si des alertes
associées ont déjà été déclenchées.
• Il peut envoyer des alertes à un certain nombre de systèmes, tels qu'OpsGenie et
PagerDuty, entre autres.
La figure 6-2 illustre l'aspect de ces principaux composants dans l’architecture Prometheus.
Prometheus stocke toutes les données sous forme de séries chronologiques, c’est-à-dire des
flux de valeurs horodatées qui appartiennent à la même métrique et au même ensemble de
dimensions étiquetées. Chaque série chronologique est identifiée de manière unique par
son nom de métrique et par une paire clé-valeur facultative appelée étiquettes. En outre, les
bibliothèques client proposent des types de métriques de base quatre cœurs : compteur,
jauge, histogramme et résumé. Nous allons parler de ces quatre types plus loin dans le
chapitre, en fournissant des exemples d’instrumentation.
Tâches et instances
Un point de terminaison que vous pouvez récupérer est appelé une
instance, dans Prometheus et il correspond généralement à un seul
processus. Une collection d’instances ayant le même objectif (un
processus répliqué pour l’évolutivité ou la fiabilité, par exemple) est
appelée une tâche.
Voici l'exemple d'une tâche de serveur API avec quatre instances
répliquées :
job: api-server
instance 1: 1.2.3.4:5670
instance 2: 1.2.3.4:5671
instance 3: 5.6.7.8:5670
instance 4: 5.6.7.8:5671
Nous allons installer et configurer Prometheus pour comprendre quelques concepts clés
supplémentaires autour de l’écosystème Prometheus.
Surveillance des métriques avec Prometheus dans un monde Cloud natif 127
Une fois que vous avez accédé au répertoire Prometheus, vous pouvez configurer Prometheus
pour qu'il récupère son propre point de terminaison HTTP à l’aide du fichier prometheus.
yaml, qui se trouve dans le répertoire Prometheus. Le fichier par défaut contient déjà le port
TCP 9090 sur le localhost sur lequel s’exécute le serveur Prometheus. Vous pouvez exécuter
Prometheus en exécutant le binaire à l’aide de la commande suivante :
$ ./prometheus
level=info ts=2020-11-29T06:51:43.519Z caller=head.go:659 component=tsdb msg="On-disk
memory mappable chunks replay completed" duration=7.944μs
level=info ts=2020-11-29T06:51:43.519Z caller=head.go:665 component=tsdb msg="Replaying WAL,
this may take a while"
level=info ts=2020-11-29T06:51:43.520Z caller=head.go:717 component=tsdb msg="WAL segment
loaded" segment=0 maxSegment=0
level=info ts=2020-11-29T06:51:43.520Z caller=head.go:722 component=tsdb msg="WAL replay
completed" checkpoint_replay_duration=93.857μs wal_replay_duration=695.77μs
total_replay_duration=812.641μs
level=info ts=2020-11-29T06:51:43.521Z caller=main.go:742 fs_type=19
level=info ts=2020-11-29T06:51:43.521Z caller=main.go:745 msg="TSDB started"
level=info ts=2020-11-29T06:51:43.521Z caller=main.go:871 msg="Loading configuration file"
filename=prometheus.yml
level=info ts=2020-11-29T06:51:43.712Z caller=main.go:902 msg="Completed loading of
configuration file" filename=prometheus.yml totalDuration=190.710981ms
remote_storage=6.638μs web_handler=591ns query_engine=807ns scrape=189.731297ms
scrape_sd=42.312μs notify=322.934μs notify_sd=20.022μs rules=3.538μs
level=info ts=2020-11-29T06:51:43.712Z caller=main.go:694 msg="Server is ready to receive
web requests."
Vous pouvez accéder à l’interface utilisateur de Prometheus sur votre navigateur à l'adresse
http://localhost:9090, et consulter les différentes métriques proposées par le serveur
Prometheus à son sujet à l'adresse http://localhost:9090/metrics.
Vous pouvez désormais utiliser le navigateur d’expression pour exécuter des requêtes ou
écrire des expressions PromQL.
PromQL est le langage de requête fonctionnel de Prometheus. Il vous permet de sélectionner
et d’agréger des données de séries chronologiques en temps réel. Les données peuvent être
visualisées sur l’interface utilisateur de Prometheus au format tableau ou graphique.
Pour utiliser le navigateur d’expression, utilisez n’importe quelle métrique exposée à partir
de localhost:9090/metrics, telles que prometheus_http_requests_total (qui est un
compteur pour toutes les requêtes HTTP vers le serveur Prometheus). Cliquez ensuite sur
l’onglet graphique et saisissez la métrique dans la console d'expression, comme illustré à la
figure 6-3.
Le langage de requête est très étendu et prend en charge un certain nombre de fonctions et
d’opérateurs sur les métriques. Par exemple, si vous souhaitez compter le nombre de séries
chronologiques renvoyées pour la métrique prometheus_target_interval_length_
seconds, vous pouvez émettre la commande suivante dans le navigateur d'expression :
count(prometheus_target_interval_length_seconds)
node_exporter
Le node_exporter expose un tableau de métriques au niveau de l’hôte, telles que le CPU,
la mémoire, l’espace disque, les E-S et la bande passante réseau, ainsi qu’une variété de
métriques au niveau du noyau. Vous pouvez télécharger le node_exporter à partir de
https://prometheus.io/download. Une fois que vous avez téléchargé et extrait l’archive tarball,
vous pouvez exécuter le binaire directement sans apporter de modifications :
$ cd node_exporter-1.0.1.darwin-amd64
$ ./node_exporter
level=info ts=2020-12-01T13:20:29.510Z caller=node_exporter.go:177 msg="Starting
Surveillance des métriques avec Prometheus dans un monde Cloud natif 129
level=info ts=2020-12-01T13:20:29.511Z caller=node_exporter.go:112 collector=loadavg
level=info ts=2020-12-01T13:20:29.511Z caller=node_exporter.go:112 collector=meminfo
level=info ts=2020-12-01T13:20:29.511Z caller=node_exporter.go:112 collector=netdev
level=info ts=2020-12-01T13:20:29.511Z caller=node_exporter.go:112 collector=textfile
level=info ts=2020-12-01T13:20:29.511Z caller=node_exporter.go:112 collector=time
level=info ts=2020-12-01T13:20:29.511Z caller=node_exporter.go:112 collector=uname
level=info ts=2020-12-01T13:20:29.511Z caller=node_exporter.go:191 msg="Listening on"
address=:9100
level=info ts=2020-12-01T13:20:29.511Z caller=tls_config.go:170 msg="TLS is disabled and it
cannot be enabled on the fly." http2=false
Une fois que vous avez redémarré Prometheus afin d'appliquer la nouvelle modification,
Prometheus aura deux cibles de point de terminaison pour récupérer les données de métriques.
Vous pouvez également consulter le point de terminaison http://localhost:9090/targets.
Imaginons maintenant que vous deviez déterminer combien de secondes chaque CPU consacre
à la réalisation de différents types de tâches (par exemple, utilisateur, système, iowait, etc.).
Pour ce faire, vous pouvez exécuter la requête suivante dans le navigateur d’expression, à l’aide
de laXfonction irate :
irate(node_cpu_seconds_total{job="node"}[5m])
Le job="node" est l’étiquette qui a été mise en correspondance et qui filtre les métriques.
Examinons maintenant le fonctionnement de l’instrumentation des applications avec
Prometheus.
Compteurs
Comme leur nom l’indique, les compteurs sont principalement utilisés pour compter
les valeurs qui augmentent et ils peuvent être réinitialisés à zéro lors du redémarrage au
moment où l'application redémarre. Par exemple, lorsqu’une requête GET est envoyée au
serveur HTTP Python, le code suivant incrémente la valeur de compteur de 1 :
import http.server
from prometheus_client import Counter, start_http_server
class SampleServer(http.server.BaseHTTPRequestHandler):
def do_GET(self):
http_requests.inc()
self.send_response(200)
self.end_headers()
self.wfile.write(b"Simple Counter Example")
if __name__ == "__main__":
start_http_server(5555)
server = http.server.HTTPServer(('localhost', 5551), SampleServer)
server.serve_forever()
Vous pouvez exécuter ce bloc de code en tant que `python counter.py` dans votre
terminal, afin qu'il démarrer un serveur HTTP simple. Nous utilisons start_http_server
comme point de terminaison à partir duquel les métriques seront récupérées. Vous pouvez
accéder aux métriques à l'adresse http://localhost:5555. Pour ingérer ces métriques dans
Prometheus, vous devez à nouveau configurer le fichier scrape_configs dans le fichier
prometheus.yml comme suit :
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['localhost:9090']
- job_name: node
static_configs:
- targets:
- localhost:9100
- job_name: my_application
static_configs:
- targets:
- localhost:5555
Surveillance des métriques avec Prometheus dans un monde Cloud natif 131
Figure 6-4. Métrique de compteur pour une application instrumentée
Comme vous pouvez le voir, il est assez facile d’instrumenter du code avec des compteurs.
Vous pouvez également utiliser des compteurs pour comptabiliser des exceptions et des
erreurs dans le code, et même avoir une valeur personnalisée pour votre compteur au lieu
de l’augmenter d’un.
Jauges
Les jauges indiquent principalement l’état actuel d’une entité et peuvent augmenter ou
diminuer. Les jauges peuvent être utilisées dans des scénarios différents. Par exemple,
supposons que vous ayez besoin de connaître le nombre de threads actifs ou le nombre
d’éléments dans une file d’attente, ou que vous souhaitez connaître le nombre d’éléments
dans un cache.
Les jauges utilisent trois méthodes principales : inc, dec, et set. L’exemple suivant illustre
comment utiliser les trois méthodes de manière indépendante pour suivre la métrique
souhaitée :
from prometheus_client import Gauge
sample_gauge_1 = Gauge('my_increment_example_requests', 'Description of increment gauge')
sample_gauge_2 = Gauge('my_decrement_example_requests', 'Description of decrement gauge')
sample_gauge_3 = Gauge('my_set_example_requests', 'Description of set gauge')
class SampleServer(http.server.BaseHTTPRequestHandler):
def do_GET(self):
start_time = time.time()
self.send_response(200)
self.end_headers()
self.wfile.write(b"My application with a Summary metric")
LATENCY.observe(time.time() - start_time)
if __name__ == "__main__":
start_http_server(5555)
server = http.server.HTTPServer(('localhost', 5551), SampleServer)
server.serve_forever()
Pour exécuter le code précédent, vous pouvez appliquer la même approche que celle
que nous avons adopté dans « Compteurs » à la page 131. Le point de terminaison de la
métrique à l'adresse http://localhost:5555/metrics présentera deux séries chronologiques :
latency_in_seconds_count et latency_in_seconds_sum. Le premier représente le
nombre d’appels d'observation qui ont été effectués et le dernier correspond à la somme
des valeurs transmises à l'observation. Si vous divisez le taux de ces deux métriques
(taux[latency_in_seconds_count[1m])/taux (latency_in_seconds_sum[1m]), vous
obtiendrez la latence moyenne de la dernière minute.
Histogrammes
Les histogrammes vous permettent de suivre la taille et le nombre d’événements dans
des compartiments, tout en vous permettant de regrouper les calculs de quantiles. Les
histogrammes peuvent être utilisés afin de mesurer les durées des requêtes pour un appel
de requête HTTP spécifique.
L’instrumentation de code des histogrammes utilise également la méthode d'observation,
et vous pouvez la combiner avec le temps nécessaire pour suivre la latence, comme dans
notre exemple précédent. Le code suivant ajoute 10 secondes à la latence de la requête :
from prometheus_client import Histogram
req_latency = Histogram('request_latency_seconds', 'Description of histogram')
req_latency.observe(10) # Observe 10 (seconds in this case)
Surveillance des métriques avec Prometheus dans un monde Cloud natif 133
appliquées au niveau d’instrumentation que vous pouvez/devez ajouter, même si Prometheus
permet de gérer efficacement plusieurs métriques.1
Maintenant que vous comprenez comment fonctionne l’instrumentation de code et
comment les hôtes sont ajoutés à Prometheus et collectés, voyons comment ajouter des
hôtes à Prometheus afin qu'ils soient collectés dans un environnement de production.
Recherche d'hôtes
Prometheus utilise le fichier static_configs sous scrape_configs dans le fichier prometheus.yml
pour trouver des cibles d’hôte à récupérer. Les environnements Cloud sont de nature très
dynamique et ils évoluent souvent, en particulier dans les environnements en conteneurs.
Dans ces environnements, l’ajout manuel d’hôtes au fichier prometheus.yml ne permettra
pas une mise à l'échelle efficace. Prometheus offre une grande variété de moyens pour gérer
ces situations en prenant en charge de nombreuses sources, y compris Kubernetes, Azure et
des plateformes de découverte de service personnalisées. La découverte de services permet
de facilement trouver tous les services exécutés dans un environnement Cloud distribué.
Nous aborderons en détail la découverte de services au chapitre 7. Ici, nous allons étudier
les différentes façons nous permettant de rechercher les hôtes en production qui seront
récupérés par Prometheus.
Utiliser Ansible
Si les hôtes exécutent des exportateurs de nœuds, l’un des moyens les plus simples de trouver
les hôtes consiste à effectuer une mise à jour statique des hôtes d’inventaire dans le fichier
prometheus.yml. Globalement, chaque fois que vous ajoutez une machine, vous devriez
également avoir une provision pour l’ajouter au fichier de configuration prometheus.yml.
Voici un extrait de code pour mettre à jour le fichier prometheus.yml à l’aide d’Ansible :
scrape_configs:
- job_name: {{ hostname }}
static_configs:
- targets:
- {{ hostname }}:9100
Vous pouvez également faire une boucle sur les hôtes sous n’importe quel groupe dans un
inventaire Ansible et les ajouter directement.
1 L’équipe de Prometheus a compilé les bonnes pratiques concernant l’utilisation de l’instrumentation à l’adresse
https://prometheus.io/docs/practices/instrumentation/#counter-vs-gauge-summary-vs-histogram.
Utiliser azure_sd_config
Prometheus permet une prise en charge automatique pour collecter les données des machines
virtuelles Azure. Les configurations de découverte de services (SD) Azure vous permettent
d’extraire des cibles collectées à partir de machines virtuelles Azure. Vous pouvez utiliser la
découverte de services Azure en définissant les informations d’identification Azure dans le
fichier prometheus.yml comme suit :
- job_name: 'azure-nodes'
azure_sd_configs:
- subscription_id: '$SUBSCRIPTION_ID'
tenant_id: '$TENANT_ID'
client_id: '$CLIENT_ID'
client_secret: '$CLIENT_SECRET'
port: 9100
relabel_configs:
- source_labels: [__meta_azure_machine_tag_cloudnative]
regex: true.*
action: keep
- source_labels: [__meta_azure_machine_name]
target_label: web_instance
- source_labels: [__meta_azure_machine_tag_public_ip]
regex: (.+)
replacement: ${1}:9100
target_label: __address__
Surveillance des métriques avec Prometheus dans un monde Cloud natif 135
Dans cette configuration, nous utilisons également le réétiquetage, qui réécrit dynamiquement
l’ensemble d’étiquettes d’une cible avant qu’elle ne soit collectée. Le réétiquetage permet de
manipuler les métriques afin de garder votre stockage en ordre et de ne pas l’encombrer avec
des données non requises. Plusieurs réétiquetages sont appliqués à l’ensemble d’étiquettes
de chaque cible par ordre d’occurrence dans le fichier de configuration.
Le rôle de nœud
Le rôle de nœud découvre tous les nœuds du cluster Kubernetes. Étant donné que kubelet
s’exécute sur chaque nœud d’un cluster Kubernetes, le rôle de nœud découvre les nœuds
Le rôle de service
Le rôle de service vous aide principalement à surveiller les systèmes opaques pour vérifier si
tous les services répondent. Le rôle de service trouve une cible pour chaque port de service
de chaque service. Vous pouvez collecter un objet de service comme suit :
scrape_configs:
- job_name: prometheus-pushgateway
kubernetes_sd_configs:
- role: service
Le rôle de Pod
Le rôle de Pod est responsable de la découverte de tous les Pods en cours d’exécution dans
le cluster et d’exposer les conteneurs qui y sont en cours d’exécution en tant que cibles. Il
renvoie également toutes les métadonnées liées aux Pods. Vous pouvez collecter les Pods
comme suit :
scrape_configs:
- job_name: 'pods'
kubernetes_sd_configs:
- role: pod
Surveillance des métriques avec Prometheus dans un monde Cloud natif 137
Le rôle d’entrée
Enfin, le rôle d’entrée permet de découvrir une cible pour chaque chemin de chaque entrée.
Ce rôle est également un moyen d’effectuer une surveillance opaque de l’entrée. Vous pouvez
collecter une entrée comme suit :
scrape_configs:
- job_name: 'gateway'
kubernetes_sd_configs:
- role: ingress
scheme: https
tls_config:
ca_file: cert.crt
Maintenant que nous avons examiné les métriques en détail, voyons comment la
journalisation est mise en œuvre dans les applications natives du cloud.
Une fois que vous avez téléchargé et installé td-agent pour votre distribution, assurez-vous
qu’il est opérationnel. Par exemple, sur macOS, vous pouvez le faire avec launchctl :
$ ~ sudo launchctl load /Library/LaunchDaemons/td-agent.plist
Password:
$
Vous pouvez confirmer que l’agent s’exécute en consultant les journaux qui se trouvent à
l’emplacement suivant.
$ ~ tail -f /var/log/td-agent/td-agent.log
2020-12-17 22:57:46 +0530 [info]: adding match pattern="td.*.*" type="tdlog"
2020-12-17 22:57:46 +0530 [warn]: #0 [output_td] secondary type should be same with primary
one primary="Fluent::Plugin::TreasureDataLogOutput" secondary="Fluent::Plugin::FileOutput"
2020-12-17 22:57:46 +0530 [info]: adding match pattern="debug.**" type="stdout"
2020-12-17 22:57:46 +0530 [info]: adding source type="forward"
2020-12-17 22:57:46 +0530 [info]: adding source type="http"
2020-12-17 22:57:46 +0530 [info]: adding source type="debug_agent"
2020-12-17 22:57:46 +0530 [info]: #0 starting fluentd worker pid=96320 ppid=95841 worker=0
2020-12-17 22:57:47 +0530 [info]: #0 [input_debug_agent] listening dRuby
uri="druby://127.0.0.1:24230" object="Fluent::Engine"
2020-12-17 22:57:47 +0530 [info]: #0 [input_forward] listening port port=24224
bind="0.0.0.0"
2020-12-17 22:57:47 +0530 [info]: #0 fluentd worker is now running worker=0
<source>
@type http
port 9999
bind 0.0.0.0
</source>
La définition précédente définit deux sources : dans la première, nous recevons des
événements du port TCP 24224, alors que dans la deuxième, nous avons un serveur HTTP
à l’écoute sur le port TCP 9999.
L’événement soumis par la source au moteur de routage de Fluentd contient trois entités :
balise, heure et enregistrement. Par exemple, dans la sortie de journal suivante :
2020-12-16 15:38:27 +0900 test.root: {"action":"logout","user":3}
2020-12-16 15:38:27 +0900 est l’heure, qui est déterminée par les modules d’extension
d’entrée et doit être au format d’heure Unix. test.root est la balise (selon Fluentd, il est
fortement recommandé que l’étiquette soit en minuscules et comporte un mélange de chiffres
et de traits de soulignement). Enfin, {"action":"logout","user":3} est un objet JSON.
Les modules d’extension d’entrée sont responsables de la récupération des journaux
d’événements à partir de sources externes. En règle générale, un module d’extension d’entrée
crée un thread, un socket et un socket d’écoute. Les plug-ins d’entrée ne sont pas seulement
limités à http et à forward. Voici quelques plug-ins supplémentaires :
in_syslog
Pour récupérer des événements de journal au moyen du protocole de Syslog sur UDP
ou TCP. Fluentd crée un socket sur le port 5140. Ensuite, vous n’avez plus qu’à installer
votre démon Syslog pour envoyer des événements de journal sur ce socket :
<source>
@type syslog
port 5140
bind 0.0.0.0
in_tail
Permet à Fluentd de lire les événements à partir de la fin des fichiers journaux, tout
comme la commande Unix tail -f :
<source>
@type tail
path /var/log/httpd-access.log
pos_file /var/log/td-agent/httpd-access.log.pos
tag apache.access
<parse>
@type apache2
</parse>
</source>
Fluentd offre des plug-ins d’entrée supplémentaires, comme in_unix pour récupérer les
enregistrements dans un socket de domaine Unix et in_exec pour exécuter les programmes
externes et extraire les journaux d’événements. Vous pouvez même rédiger vos propres
plug-ins d’entrée personnalisés.
Dans la configuration précédente, nous faisons correspondre les événements balisés avec
mywebapp.access et nous les stockons dans file à l’adresse /var/log/mywebapp/access.
En plus de file et forward, vous pouvez avoir d’autres types de plug-ins de sortie qui
déterminent essentiellement où vous souhaitez écrire les données. Par exemple, out_
elasticsearch est un plug-in de sortie qui écrit les enregistrements sur un point de
terminaison de cluster Elasticsearch. Vous devrez d’abord installer le plug-in en utilisant :
fluent-gem install fluent-plugin-elasticsearch
Ensuite, vous pouvez utiliser la configuration suivante pour envoyer les données de sortie
à un point de terminaison Elasticsearch :
<match my.logs>
@type elasticsearch
host 192.168.23.13
port 9200
logstash_format true
</match>
<filter test.session>
@type grep
<exclude>
key action
pattern ^logout_session$
</exclude>
</filter>
<match test.session>
@type stdout
</match>
Dans la configuration précédente, une fois que les données sont sourcées, elles passent par
la section de filter, puis par celle de match. L’instruction filter acceptera ou rejettera
l’événement en fonction de son type et de sa règle. Ici, nous avons rejeté l’action logout_
session et utilisé le type grep à l’intérieur de filter pour exclure tout message sur lequel
la clé action a la chaîne logout.
Voici quelques plug-ins filter supplémentaires :
filter_record_transformer
Permet de modifier un flux d’événements entrant. Vous pouvez utiliser l’exemple de
configuration suivant pour record_transformer :
<filter myweb.access>
@type record_transformer
<record>
host_param "#{Socket.gethostname}"
</record>
</filter>
• log_level
• suppress_repeated_stacktrace
• emit_error_log_interval
• suppress_config_dump
• without_source
• process_name
Ici, nous définissons d’abord les noms de processus de superviseur et de travailleur sur
my_app, puis nous définissons le niveau de journal par défaut sur error. Nous demandons
également à Fluentd de démarrer sans aucun plug-in d’entrée.
<filter test.session>
@type grep
<exclude>
<label @MYCLUE>
<filter test.session>
@type grep
<exclude>
key action
pattern ^logout$
</exclude>
</filter>
<match test.session>
@type stdout
</match>
</label>
Dans la configuration précédente, le paramètre @label sous source est la redirection vers
la section de l’étiquette @MYCLUE. Le contrôle ignorera la définition filter pour login et
passera directement à l’étiquette @MYCLUE.
# http
@include http://example.com/fluent.conf
Avant de poursuivre, voyons brièvement comment exécuter l’agent pour voir vos
journaux. Pour exécuter une configuration simple comme la suivante :
<source>
@type http
port 9999
bind 0.0.0.0
</source>
<filter myapp.test>
@type grep
<exclude>
key action
pattern ^logout$
</exclude>
<match myapp.test>
@type stdout
</mat ch>
Vous pouvez maintenant exécuter les commandes curl suivantes pour simuler différentes
actions :
$ curl -i -X POST -d 'json={"action":"login","user":2}' http://localhost:9999/myapp.test
HTTP/1.1 200 OK
Content-Type: text/plain
Connection: Keep-Alive
Content-Length: 0
Si vous essayez de publier une action en tant que logout dans la commande curl suivante,
elle sera supprimée en fonction de la règle de filtre que nous avons déterminée et vous ne
pourrez voir aucun journal en cours d’impression :
$ curl -i -X POST -d 'json={"action":"logout","user":2}' http://localhost:9999/myapp.test
HTTP/1.1 200 OK
Content-Type: text/plain
Connection: Keep-Alive
Content-Length: 0
• Vous pouvez utiliser le conteneur sidecar pour diffuser les journaux d’application vers
le stdout du conteneur.
• Vous pouvez exécuter un agent de journalisation à l’intérieur d’un conteneur sidecar,
qui sélectionne essentiellement les journaux des conteneurs d’application et les expédie
à un back-end de journalisation.
• Vous pouvez expédier des journaux d’application produits dans différents formats de
journal (structurés ou non structurés) en ayant deux conteneurs sidecar pour diffuser
un fichier journal particulier vers différents flux de journaux.
• Les conteneurs sidecar peuvent lire les journaux à partir de fichiers, de sockets ou de
journaux, puis chaque conteneur sidecar imprimera le journal dans les flux stdout et stderr.
• Les conteneurs sidecar peuvent également être utilisés pour effectuer la rotation des
fichiers journaux lorsque l’application elle-même ne peut pas le faire.
• Le disque d’E/S peut augmenter de manière considérable dans un scénario où vous
écrivez les journaux dans un fichier, puis où vous les diffusez sur stdout.
• Étant donné que plusieurs Pods exécutent votre application, vous devrez également
déployer plusieurs conteneurs sidecar dans chaque Pod.
Vous pouvez utiliser le transfert de port pour vérifier que le cluster Elasticsearch a été
déployé avec succès :
$ kubectl port-forward svc/elasticsearch-master 9200
Forwarding from 127.0.0.1:9200 -> 9200
Forwarding from [::1]:9200 -> 9200
Handling connection for 9200
Handling connection for 9200
Une fois que vous avez mis à jour le fichier YAML avec les détails d’Elasticsearch, vous
pouvez déployer le DaemonSet de Fluentd sur AKS en passant au référentiel GitHub et en
appliquant le DaemonSet comme suit :
$ kubectl apply -f fluentd-daemonset-elasticsearch-rbac.yaml
Kibana (figure 6-6) devrait maintenant être opérationnel sur votre http://localhost:5601.
Un autre nouvel outil d’agrégation de journaux est Loki de Grafana Labs. Loki enregistre
efficacement des étiquettes de journal déterminées au lieu d’un flux de journaux entier et
peut facilement s’intégrer à Fluentd. Nous n’étudierons pas ce sujet en détail, car il s’étend
au-delà de la portée de ce livre.
À présent que vous comprenez comment fonctionne la journalisation dans les
environnements natifs du cloud, concluons le chapitre par le suivi distribué.
2 Kibana est une interface utilisateur en code source libre qui est généralement utilisée pour visualiser les
données (journaux). Vous trouverez des informations supplémentaires sur https://elastic.co/kibana.
Pour mieux comprendre les principes fondamentaux du suivi distribué, jetez un coup d’œil
à l’application web simple illustrée à la figure 6-7.
Figure 6-7. Une application web simple présentant la propagation des requêtes via différents
niveaux de services
Prenons la figure 6-7 et supposons que vous disposiez d’un exemple de service qui prévoit des
ressources sur un cloud d’après le plan de l’utilisateur. Le flux normal d’exécution commence
par le client faisant une demande à l’équilibreur de charge. Celui-ci communique avec le
service d’authentification et le service de facturation, puis alloue des ressources au client
en effectuant un appel final au service d’allocation de ressources. Sur la figure 6-8, vous
pouvez voir les identifiants de demande uniques propagés dans le flux, ce qui aide ensuite à
regrouper les traces.
Périodes
Une période représente un appel opérationnel simple et constitue le bloc de construction
principal d’un suivi distribué, qui représente quant à lui une unité individuelle de travail
effectuée dans un système distribué. Les périodes contiennent des références à d’autres
périodes, ce qui permet à plusieurs périodes d’être regroupées dans une seule trace
complète. Par exemple, sur la figure 6-8, la période « transaction d’équilibreur de charge
du début à la fin » comprend d’autres périodes, comme l’équilibreur de charge interagissant
avec le service d’authentification ou l’équilibreur de charge interagissant avec le service de
facturation.
Les périodes sont créées sous la forme d’une relation parent-enfant dans laquelle chaque
période a un enfant, à l’exception de la racine et du service de début (figure 6-9).
Traces
Une trace représente le parcours complet d’une demande dans l’ensemble des services par
lesquels elle passe. Une trace complète simple est habituellement constituée de plusieurs
périodes pour la demande. Par exemple, la transaction complète du client du début à la fin
est constituée de plusieurs périodes.
Propagation du contexte
Pour chaque demande d’un service vers un service en aval, un identificateur d’exécution de
demande global est transmis en tant que métadonnées, lequel demeure unique pour chaque
demande. Cet identificateur d’exécution de demande global est utilisé ultérieurement pour
reconstruire l’exécution complète de la demande en regroupant les enregistrements sur la base
de l’identificateur de demande. Le processus de transmission de l’identificateur d’exécution
en tant que métadonnées de demande est appelé propagation de contexte distribué.
Les métadonnées qui sont propagées dans l’ensemble des périodes comprennent également
l’identifiant de trace et l’identifiant de période en plus de deux autres détails : les balises et
les journaux. Les balises sont des paires clé-valeur qui peuvent être ajoutées aux périodes
pour fournir des informations supplémentaires, telles que les codes d’erreur et les détails
de l’hôte. Les journaux sont également des paires clé-valeur qui capturent des messages de
journalisation propres à la période et aident au débogage.
Pour utiliser le suivi distribué, vous devez d’abord instrumenter le code de votre application
à l’aide d’une bibliothèque cliente. Les bibliothèques clientes sont offertes dans de nombreux
langages, notamment Java, Go et Python. La bibliothèque envoie les données à un agent
qui se trouve généralement sur la même instance ou le même hôte. L’agent est responsable
du transfert des suivis vers le back-end (par exemple, vers la couche de stockage au moyen
d’une couche mise en mémoire tampon en mode asynchrone). Par la suite, les suivis sont
reconstruits et affichés dans l’interface utilisateur. Ils peuvent également être utilisés pour
effectuer d’autres analyses et agrégations à l’aide de techniques d’exploration de données.
À partir de là, nous pouvons exécuter tous les composants de Jaeger dans une seule image
Docker :
$ docker run -d -p6831:6831/udp -p16686:16686 jaegertracing/all-in-one:latest
def book_movie_now(showtime_details):
with tracer.start_span('BookShow', child_of=get_current_span()) as span:
with span_in_context(span):
num = random.randint(1,30)
time.sleep(num)
Ticket_details = "Ticket Details"
flags = ['false', 'true', 'false']
random_flag = random.choice(flags)
span.set_tag('error', random_flag)
span.log_kv({'event': 'CheckCinema' , 'value': showtime_details })
assert len(sys.argv) == 2
tracer = initialize_tracer('movie_booking')
movie = sys.argv[1]
booking_manager(movie)
time.sleep(2)
tracer.close()
Dans le code précédent, nous initialisons d’abord le traceur à l’aide de la méthode initial
ize_tracer, qui définit la configuration pour la journalisation et l’échantillonnage. La
prochaine chose à noter dans le code est la façon dont nous utilisons l’instance de traceur
pour démarrer une nouvelle période avec start_span, et child_of pour démarrer de
nouvelles périodes enfants à la période racine. Par exemple, la période racine est générée
dans la méthode booking_manager, alors que le reste des méthodes (par exemple, check_
movie_showtime et check_movie) sont principalement des périodes enfants de la période
racine.
Nous définissons également des balises et des journaux dans les méthodes. Par exemple :
-> span.set_tag('error', random_flag)
Vous pouvez maintenant simplement exécuter ce programme dans votre console Python en
transmettant un titre de film composé comme argument, comme suit :
Vous pouvez voir les quatre périodes à la figure 6-11, movie_booking étant la période et
les autres, les périodes enfants. Étant donné qu’il s’agit d’un exemple de programme, à des
fins de démonstration, nous avons généré de façon aléatoire des erreurs dans le code qui
sont propagées. En production, ces erreurs indiquent des problèmes qui surviennent dans
l’environnement (par exemple, la temporisation de Redis en raison d’un problème d’E/S).
Nous pouvons également instrumenter notre code à l’aide d’OpenTelemetry, car
OpenTracing est à présent en cours de suppression. Tout d’abord, nous devons installer
l’API OpenTelemetry et le kit de développement logiciel :
pip install opentelemetry-api
pip install opentelemetry-sdk
trace.set_tracer_provider(TracerProvider())
jaeger_exporter = jaeger.JaegerSpanExporter(
service_name="my-helloworld-service",
agent_host_name="localhost",
agent_port=6831,
)
trace.get_tracer_provider().add_span_processor(
BatchExportSpanProcessor(jaeger_exporter)
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("foo"):
with tracer.start_as_current_span("bar"):
with tracer.start_as_current_span("tango"):
print("Hello world from Opentelemetry! Happy Tracing")
Le code précédent est un script Python de style « Hello World » simple qui utilise
OpenTelemetry. Notez comment nous utilisons l’exportateur Jaeger pour nous indiquer
l’emplacement de l’agent Jaeger.
Vous avez besoin de Python3 pour exécuter le script précédent :
$ python3 opentelemetry_simple.py
Hello world from Opentelemetry! Happy Tracing
Là encore, vous pouvez afficher dans l’interface utilisateur les périodes qui sont remplies
au même point de terminaison de Jaeger (http://localhost:16686) sous le service
my-helloworld-service.
Vous pouvez également instrumenter n’importe quel code en fonction du langage de votre
application. Par exemple, vous pouvez instrumenter une application Python Flask comme suit :
import flask
import requests
trace.set_tracer_provider(TracerProvider())
jaeger_exporter = jaeger.JaegerSpanExporter(
service_name="flask_app_example",
agent_host_name="localhost",
agent_port=6831,
)
trace.get_tracer_provider().add_span_processor(
SimpleExportSpanProcessor(jaeger_exporter)
)
app = flask.Flask(__name__)
FlaskInstrumentor().instrument_app(app)
RequestsInstrumentor().instrument()
@app.route("/")
def hello():
tracer = trace.get_tracer(__name__)
with tracer.start_as_current_span("example-request"):
requests.get("http://www.example.com")
app.run(debug=True, port=5000)
Vous pouvez exécuter le script précédent comme suit et consulter http://localhost:5000 pour
générer les suivis dans l’interface utilisateur de Jaeger :
$ python3 opentelemetry_flask.py
* Serving Flask app "opentelemetry_flask" (lazy loading)
* Environment: production
WARNING: This is a development server. Do not use it in a production deployment.
Use a production WSGI server instead.
* Debug mode: on
* Running on http://127.0.0.1:5000/ (Press CTRL+C to quit)
* Restarting with stat
* Debugger is active!
* Debugger PIN: 156-661-048
127.0.0.1 - - [30/Dec/2020 20:54:37] "GET / HTTP/1.1" 200 -
127.0.0.1 - - [30/Dec/2020 20:54:37] "GET /favicon.ico HTTP/1.1" 404 -
Ce sont quelques façons dont vous pouvez utiliser le suivi distribué dans vos environnements
natifs du cloud pour les rendre observables. En dehors des approches mentionnées ici,
les maillages de services tels qu’Istio fournissent également une architecture de mise en
œuvre de type sidecar pour effectuer un suivi distribué. Nous présenterons les maillages
de services au chapitre 7. Pour obtenir de plus amples informations sur le suivi distribué,
veuillez consulter Mastering Distributed Tracing (Maîtriser le suivi distribué) de Yuri Shkuro
(Packt, 2019).
Voyons maintenant ce qu’Azure peut vous offrir en termes d’espace de pilotage.
Azure Monitor
En plus des solutions sur mesure mentionnées précédemment pour la création de systèmes
observables, Microsoft Azure propose également Azure Monitor, une solution standard qui
peut vous aider à surveiller une application et une infrastructure exécutées dans le cloud et
dans des environnements sur site. Azure Monitor utilise principalement des métriques et
des journaux pour connaître les performances de votre application et identifie de manière
proactive les problèmes potentiels, ainsi que toute dépendance des ressources.
Azure Monitor dispose de différentes fonctions qui peuvent vous aider à détecter divers
problèmes dans votre application et votre infrastructure, comme indiqué ici et illustré
à la figure 6-12 :
Application Insights
Vous pouvez détecter et diagnostiquer les problèmes entre les applications et les
dépendances en surveillant la disponibilité, les performances et l’utilisation de vos
applications web hébergées dans le cloud ou sur site.
Azure Monitor pour les conteneurs et les machines virtuelles
Vous pouvez surveiller les performances de vos conteneurs exécutés sur AKS, ainsi que
la machine virtuelle qui les héberge.
Azure Monitor vous permet également d’utiliser des données de suivi distribué. Il existe
essentiellement deux façons de procéder. La première consiste à utiliser la vue de diagnostic
de transactions, qui est similaire à une pile d’appels avec l’ajout d’une dimension temporelle.
La vue Diagnostics de transaction fournit une visibilité sur une seule transaction/requête.
Elle est utile pour trouver la cause profonde des problèmes de fiabilité et les goulots
d’étranglement de performances à la demande. La deuxième méthode consiste à utiliser
la vue cartographique de l’application, qui regroupe de nombreuses transactions pour
afficher une vue topologique de la manière dont les systèmes interagissent, ainsi que des
performances moyennes et des taux d’erreur.
Résumé
Dans ce chapitre, nous avons présenté l’observabilité comme un besoin croissant dans
l’environnement natif du cloud. Nous avons abordé l’observabilité et la façon dont elle
complète la surveillance, puis nous avons présenté le développement axé sur l’observabilité
comme la nouvelle méthode par excellence pour obtenir des informations sur votre
application et votre infrastructure cloud. Nous avons vu les trois piliers de l’observabilité
et abordé les méthodes préconisées en matière de journalisation, de surveillance et de
suivi pour les systèmes distribués modernes sur Azure. Enfin, nous avons brièvement vu
comment Azure propose ses solutions intégrées pour effectuer des tâches similaires avec
Azure Monitor. Grâce à ces connaissances, vous pouvez désormais créer en toute confiance
des systèmes observables dans des environnements natifs du cloud et intégrer l’observabilité
dans votre application.
Dans le chapitre suivant, nous allons examiner comment le maillage et la découverte des
services sont utiles dans les environnements natifs du cloud.
Résumé 161
CHAPITRE 7
Découverte et maillage des services :
Rechercher de nouveaux territoires
et traverser les frontières
Lorsque les applications modernes sont passées à une architecture de microservices, elles
sont devenues évolutives et efficaces sur le cloud. Les microservices favorisent la division
d’une application en composants indépendants et découplés. Le découplage est généralement
réalisé en séparant les bases de code en applications autonomes connectées à l’aide du réseau
et d’API ou d’interfaces bien définies que les microservices utilisent pour communiquer.
Une fois vos applications déplacées vers une architecture de microservices, de nombreuses
possibilités s’offrent à vous : vous pouvez faire évoluer chaque service individuellement,
découpler le cycle de publication de chaque service, choisir un différent langage pour écrire
vos composants d’application individuels et même organiser la structure de votre équipe en
fonction de ces services indépendants.
Cependant, maintenant que vous avez divisé votre application en applications plus petites,
ces binaires ont leur propre cycle de vie. Ce dernier est planifié indépendamment et se
termine indépendamment selon les besoins, tout en maintenant la communication sur le
réseau. Dans ce scénario, supposons que vous ayez un grand nombre de microservices en
cours d’exécution qui communiquent entre eux. Vous commenceriez probablement à poser
plusieurs questions, dont les suivantes :
•
Comment les services communiquent-ils entre eux lorsqu’ils sont de nature
dynamique ? (Autrement dit, puisque les services communiquent sur un réseau,
l’adresse IP ne fournit pas suffisamment d’informations pour joindre les services, car
ceux-ci peuvent être résiliés indépendamment et reprogrammés sur un autre hôte.)
• Comment puis-je contrôler et gérer le trafic ou le trafic d’itinéraire selon les besoins,
y compris les scénarios avancés tels que les versions Canary, les tests A/B et les ruptures
de circuits ?
163
• Comment puis-je assurer la sécurité entre les services et chiffrer le trafic entre eux ?
Pour résoudre ces problèmes, vous pouvez commencer à écrire et à créer une logique propre
à l’infrastructure supplémentaire dans votre application. Toutefois, cela augmenterait la
portée de l’application au-delà de vos besoins professionnels et vous auriez à mettre en
œuvre cette logique avec chaque pile de microservices que vous utilisez.
Heureusement, ces problèmes ont été résolus dans l’espace de l’environnement natif du
cloud à l’aide des technologies de découverte de services et de maillage de services, qui
offrent un moyen beaucoup plus flexible de gérer, de sécuriser et de fournir un contrôle
beaucoup plus important sur les services.
La découverte de services est un mécanisme par lequel les services se découvrent les uns les
autres afin de pouvoir communiquer. La découverte de services est principalement axée sur
la recherche de l’emplacement réseau d’un service dans le cloud. Dans les environnements
classiques, où vous avez affaire à des serveurs physiques, vous connaissez les adresses IP
statiques de vos serveurs et vous pouvez utiliser un fichier de configuration simple pour
stocker les adresses IP, qui peuvent ensuite être utilisées par vos services pour contacter
d’autres services. Cette configuration fonctionne très bien dans un environnement local
ou physique. Toutefois, pour les applications hautement évolutives dans le cloud, cette
approche échoue, car votre application est désormais de nature dynamique, ce qui signifie
que l’application peut être redémarrée, replanifiée ou terminée selon les besoins. Dans de
tels scénarios, il est impossible de coder l’IP car elle peut changer. La découverte des services
permet de stocker un mappage pour chaque nom de service à l’adresse IP dans le cloud.
Un maillage de services est axé sur la résolution de la complexité accrue qu’entraîne la
communication interservices. Il s’agit d’une infrastructure dédiée qui gère toutes les
communications réseau de service à service dans l’environnement cloud. Il offre les
avantages suivants : visibilité élevée, résilience, gestion du trafic et contrôle de sécurité, avec
peu ou pas de modification du code d’application existant.
Dans ce chapitre, nous examinerons CoreDNS, une plateforme de découverte de services de
premier plan dans le domaine natif du cloud qui est utilisée par Azure Kubernetes Service
(AKS) pour la gestion DNS de clusters et la résolution de noms. Nous aborderons également
Istio, un maillage de services important qui est largement utilisé dans les environnements
cloud comme Azure.
Découverte de services
La découverte de services est un composant fondamental d’un environnement natif du cloud
moderne. Elle doit s’assurer que les services peuvent se trouver et communiquer entre eux sur
un réseau. En règle générale, la découverte de services implique un registre de services auquel
tous les services/applications de l’environnement cloud doivent s’inscrire. Le registre des
services est le référentiel central qui contient l’emplacement des services. Dans un scénario
type, un nouveau service s’enregistre d’abord avec le registre de service lorsqu’il entre dans
l’environnement. Le registre des services met à jour le dernier emplacement réseau du service,
164 Chapitre 7 : Découverte des services et maillage de services : trouver de nouveaux territoires et franchir les frontières
et lorsqu’un service client demande à se connecter au service, le registre des services permet
au consommateur d’avoir un emplacement pour ce service.
Dans cette section, nous allons explorer CoreDNS et voir comment il peut être utilisé en
tant qu’outil de découverte de service dans les environnements cloud.
Présentation de CoreDNS
CoreDNS est un serveur DNS extensible qui prend en charge les protocoles DNS, DNS sur
TLS et DNS standard sur gRPC. CoreDNS a été créé par Miek Gieben en 2016 en utilisant une
infrastructure de serveur développée dans le cadre du serveur web Caddy. Il dispose d’une
architecture de plug-in qui est hautement configurable, flexible et extensible. CoreDNS a été
plus largement adopté après avoir reçu le support de Cloud Native Computing Foundation
(CNCF). En 2019, CoreDNS a reçu le niveau de maturité « graduation » de CNCF.1
CoreDNS est maintenant le serveur DNS par défaut officiel avec Kubernetes 1.13 et versions
ultérieures. Il remplace Kube-DNS. CoreDNS résout les problèmes de fiabilité et de sécurité
dans la mise en œuvre originale de Kube-DNS grâce à plusieurs différences clés :
•
CoreDNS exécute un conteneur unique, tandis que Kube-DNS exécutait trois
conteneurs : kubedns, dnsmasq et sidecar.
• CoreDNS est conçu pour être utilisé en tant que serveur DNS à usage général
rétrocompatible avec Kubernetes.
• CoreDNS est principalement un processus Go qui améliore les fonctionnalités de
Kube-DNS.
L’architecture de plug-in CoreDNS garantit que la fonctionnalité du serveur DNS reste stable
et permet d’ajouter d’autres fonctionnalités à l’aide de plug-ins. L’utilisateur final peut définir
plusieurs serveurs en configurant des zones à servir sur un port particulier. Chaque serveur
transmet les requêtes via une chaîne de plug-in, qui détermine le type de réponse à envoyer :
• Si plusieurs serveurs sont configurés pour être écoutés sur le port interrogé, il vérifie
quelle est la zone la plus spécifique pour la requête à l’aide de la correspondance
de suffixe la plus longue. Par exemple, si un utilisateur effectue une requête pour
www.health.abc.com et que deux serveurs sont configurés en tant que abc.com et health.
abc.com, la requête est acheminée vers ce dernier serveur.
• Une fois qu’un serveur approprié a été trouvé, il est acheminé via la chaîne de plug-in
configurée pour le serveur.
1 CNCF attribue différents niveaux de maturité aux projets : sandbox, incubés et gradués, qui correspondent aux
niveaux des Visionnaires, des Premiers adoptants et de la Majorité précoce du diagramme Franchir le gouffre.
Le niveau de maturité est un signal que CNCF attribue à un projet afin d’identifier les types d’entreprises qui
devraient adopter le projet.
La figure 7-1 présente les étapes qui se produisent lorsque le CoreDNS traite une requête.
166 Chapitre 7 : Découverte des services et maillage de services : trouver de nouveaux territoires et franchir les frontières
Installation et configuration de CoreDNS
Vous pouvez installer CoreDNS à l’aide du fichier binaire, disponible à l’emplacement
GitHub de ce livre. Une fois que vous avez saisi le binaire pour votre système d’exploitation,
vous pouvez le déplacer vers votre emplacement local. Par exemple, si vous avez téléchargé
le binaire pour macOS, coredns_1.8.1_darwin_amd64.tgz, vous pouvez décompresser le
fichier et le déplacer vers /usr/local/bin. Vérifiez que CoreDNS fonctionne correctement en
émettant la commande suivante :
$ coredns -version
CoreDNS-1.8.1
darwin/amd64, go1.15.7, 95622f4
CoreDNS offre de nombreuses options de configuration qui sont gérées par un Corefile.
Lorsque CoreDNS démarre, il recherche un fichier nommé Corefile dans le répertoire actif
si l’indicateur -conf n’est pas passé. Le fichier définit principalement les éléments suivants :
où ZONE représente la zone DNS, PORT est l’endroit où la zone du serveur est exécutée (en
général, le port 53) et PLUGIN définit les plug-ins qui doivent être chargés.
Parmi les entrées les plus courantes d’un fichier Corefile figurent les différents blocs de
serveurs qui définissent un serveur dans CoreDNS (c’est-à-dire la façon dont les requêtes
pour un nom de domaine particulier sont traitées). Voici un exemple :
example.com {
}
Le bloc de serveurs précédent gérera toutes les requêtes qui se retrouvent dans
example.com, sauf si un bloc de serveurs plus précis, comme foo.example.com, est présent.
Pour un exemple plus concret, imaginons que vous ayez ce qui suit dans votre Corefile :
cloudnativeazure.io:53 {
log
errors
}
.:53 {
forward . 8.8.8.8
log
errors
Dans cet exemple, nous avons deux blocs de serveurs pour cloudnativeazure.io et la
racine (.). Tous deux écoutent sur le port 53. De plus, plusieurs plug-ins sont définis : log,
pour consigner chaque requête reçue par CoreDNS, errors, pour consigner les erreurs et
cache, pour activer le cache frontal (c’est-à-dire tous les enregistrement, sauf les transferts
de zone et les métadonnées qui seront mis en cache pendant un maximum de 3 600 s).
Vous pouvez exécuter le Corefile précédent en tapant simplement coredns dans le même
répertoire que celui où se trouve Corefile, ou faire coredns -conf Corefile:
$ coredns -conf Corefile
.:53
cloudnativeazure.io.:53
CoreDNS-1.8.1
darwin/amd64, go1.15.7, 95622f4
En effectuant l’action dig pour cloudnativeazure.io sur un autre terminal, vous verrez
ce qui suit :
$ ~ dig @127.0.0.1 cloudnativeazure.io:53
; <<>> DiG 9.10.6 <<>> @127.0.0.1 cloudnativeazure.io:53
; (1 server found)
;; global options: +cmd
;; Got answer:
;; ->>HEADER<<- opcode: QUERY, status: NXDOMAIN, id: 48995
;; flags: qr rd ra ad; QUERY: 1, ANSWER: 0, AUTHORITY: 1, ADDITIONAL: 1
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
;; QUESTION SECTION:
;cloudnativeazure.io:53. IN A
;; AUTHORITY SECTION:
. 1800 IN SOA a.root-servers.net. nstld.verisign-grs.com. 2021021001 \
1800 900 604800 86400
Vous pouvez voir les journaux sur le terminal CoreDNS comme suit :
$ coredns -conf Corefile
.:53
cloudnativeazure.io.:53
CoreDNS-1.8.1
darwin/amd64, go1.15.7, 95622f4
Nous n’avons couvert que les notions de base de CoreDNS ici. Pour obtenir de plus amples
informations, nous vous suggérons de lire Learning CoreDNS de John Belamaric et Cricket
Liu (O’Reilly, 2019).
168 Chapitre 7 : Découverte des services et maillage de services : trouver de nouveaux territoires et franchir les frontières
Voyons maintenant comment CoreDNS est utilisé dans la découverte de services sur Kubernetes.
Vous pouvez également entrer une commande dig afin de voir l’enregistrement A pour le service :
dnstools# dig nginx.default.svc.cluster.local
;; OPT PSEUDOSECTION:
; EDNS: version: 0, flags:; udp: 4096
; COOKIE: 5086e790e261bf20 (echoed)
;; QUESTION SECTION:
;nginx.default.svc.cluster.local. IN A
170 Chapitre 7 : Découverte des services et maillage de services : trouver de nouveaux territoires et franchir les frontières
;; ANSWER SECTION:
nginx.default.svc.cluster.local. 5 IN A 10.0.148.122
Microsoft Azure fournit également DNS en tant que service, par le biais d’un service
d’hébergement connu sous le nom d’Azure DNS. C’est ce que nous allons voir maintenant.
Azure DNS
Azure DNS fournit principalement l’infrastructure de Microsoft Azure afin de gérer les
résolutions de noms pour les domaines DNS. Vous pouvez utiliser Azure DNS pour héberger
votre domaine DNS et gérer vos enregistrements DNS. En hébergeant vos domaines
dans Azure, vous pouvez gérer vos enregistrements DNS en conservant les informations
d’identification, API, outils et données de facturation utilisés pour vos autres services Azure.
Azure DNS peut être utilisé pour traduire les noms d’hôte dans les domaines public et
privé. La fonction de DNS public peut être utilisée pour héberger votre nom de domaine
préacheté sur Azure, tandis que le DNS privé vous permet de gérer et de traduire les noms
de domaine dans les réseaux virtuels.
CoreDNS fournit également un plug-in propre à Azure utilisé pour servir des zones à partir
d’Azure DNS. Le plug-in Azure peut être activé comme suit :
azure AZURE_RESOURCE_GROUP:ZONE... {
tenant <TENANT_ID>
client <CLIENT_ID>
secret <CLIENT_SECRET>
subscription <SUBSCRIPTION_ID>
environment <ENVIRONMENT>
fallthrough [ZONES...]
access private
}
•
AZURE_RESOURCE_GROUP:ZONE est le groupe de ressources auquel appartiennent les
zones hébergées sur Azure, alors que ZONE est la zone qui contient des données.
• C LIENT_ID et CLIENT_SECRET sont les informations d’identification pour Azure,
tandis que tenant définit le TENANT_ID à utiliser. SUBSCRIPTION_ID est l’identifiant
d’abonnement.
• environment définit ENVIRONMENT dans Azure.
Maintenant que nous avons couvert le rôle et l’importance de la découverte des services dans
les environnements distribués natifs du cloud, voyons ce qu’un maillage de services a à offrir.
L’architecture générale d’un maillage de services comporte deux composants de haut niveau :
un plan de données et un plan de contrôle. La figure 7-2 représente quatre services (A – D)
déployés dans un maillage de services.
Comme vous pouvez le voir, chaque instance de service dispose d’une instance de
proxy sidecar qui est responsable de tous les flux et de la gestion du trafic. Cela signifie
fondamentalement que lorsque le service A veut parler au service C, par exemple, le
service A initie le flux de communication via son proxy sidecar local, qui accède ensuite au
proxy sidecar du service C. De cette façon, le service n’est pas au courant du proxy de réseau
local et reste isolé du réseau le plus important. Ainsi, chaque fois qu’un service doit parler à
un autre service, le proxy intercepte la requête et la transmet au destinataire.
172 Chapitre 7 : Découverte des services et maillage de services : trouver de nouveaux territoires et franchir les frontières
Figure 7-2. Architecture générale du maillage de services
Présentation d’Istio
Lorsque les applications monolithiques se sont transformées en microservices, les
développeurs et les équipes opérationnelles ont rencontré des difficultés avec la
communication d’un service à l’autre dans le maillage de services. Lorsque la taille d’un
maillage de services augmente, celui-ci devient difficile de gérer et à maintenir. Il devient
également difficile de comprendre comment les différents composants en évolution
fonctionnent ensemble.
Istio est un maillage de services open source qui simplifie la communication entre les
microservices dans les applications natives du cloud distribuées. Istio fournit des ensembles
de fonctionnalités riches et prédéfinis qui appliquent des modèles de résilience tels que
les nouvelles tentatives, les disjoncteurs, la mise en forme du trafic, le comportement de
routage, le déploiement canari, etc. En outre, Istio vous permet de créer facilement un
réseau de microservices déployés à l’aide de l’équilibrage de charge, de la surveillance et de
l’authentification, avec presque aucun changement de code d’application.
Comme nous l’avons mentionné dans la section précédente, une architecture de maillage
de services se compose d’un plan de données et d’un plan de contrôle. Istio utilise Envoy
comme plan de données et istiod comme plan de contrôle (comme illustré à la figure 7-3) :
Envoy (plan de données)
Envoy est un proxy haute performance écrit en C++ qui intercepte tous les trafics
entrants et sortants pour chaque application dans le maillage de services. Il est déployé
en tant que sidecar avec l’application et fournit un grand nombre de fonctionnalités, y
compris la terminaison TLS, l’équilibrage de charge, la rupture de circuit, les contrôles
d’intégrité, la découverte de service dynamique, l’injection d’erreur, etc. Ce modèle de
proxy sidecar vous permet d’utiliser Istio en tant que maillage de services sans aucune
modification de code.
Istiod (plan de contrôle)
Istiod gère et configure les proxys. Istiod comporte trois sous-composants :
• Pilot, responsable de la configuration des proxys Envoy au moment de l’exécution
• Citadel, responsable de l’émission et de la rotation des certificats
•
Galley, responsable de la validation, de l’ingestion, de l’agrégation, de la
transformation et de la distribution de la configuration dans Istio
Istiod convertit les règles de routage de haut niveau qui contrôlent le trafic en configuration
spécifique à Envoy et se propage aux sidecars Envoy lors de l’exécution.
174 Chapitre 7 : Découverte des services et maillage de services : trouver de nouveaux territoires et franchir les frontières
Figure 7-3. Architecture Istio
Voyons maintenant comment vous pouvez utiliser Istio et Envoy dans un environnement
Azure Kubernetes.
• Istio fournit un outil de ligne de commande appelé istioctl, qui peut être utilisé pour
fournir un niveau de personnalisation riche au plan de contrôle Istio et au plan de don-
nées proxy Envoy.
• Vous pouvez utiliser l’opérateur Istio Kubernetes pour gérer l’installation via les
définitions de ressources personnalisées (CRD) de l’API Kubernetes.
• Vous pouvez utiliser des tableaux Helm pour installer Istio directement.
Les tableaux Helm étant également utilisés indirectement dans les méthodes 1 et 2, nous les
utiliserons ici pour installer Istio.
$ cd istio-1.9.2
2. Créez un nouvel espace de noms pour les composants Istio, appelé istio-system :
$ kubectl create namespace istio-system
namespace/istio-system created
3. Installez le graphique de base Istio qui contient les ressources à l’échelle du cluster
utilisées par le plan de contrôle istiod :
$ helm install istio-base manifests/charts/base -n istio-system
NAME: istio-base
LAST DEPLOYED: Sun Mar 28 15:59:16 2021
NAMESPACE: istio-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NAME: istiod
LAST DEPLOYED: Sun Mar 28 16:02:23 2021
NAMESPACE: istio-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
5. Vérifiez l’installation :
$ helm list -A
NAME NAMESPACE REVISION UPDATED STATUS
CHART APP VERSION
istio-base istio-system 1 2021-03-28 15:59:16.429126 +0530 IST deployed
base-1.9.2
istiod istio-system 1 2021-03-28 16:02:23.950541 +0530 IST deployed
istio-discovery-1.9.2
$ kubectl get pods -n istio-system
NAME READY STATUS RESTARTS AGE
istiod-6d68c86c8d-5nv2r 1/1 Running 0 10m
Il est important de s’assurer que chaque fois qu’un nouveau Pod est déployé dans le cluster,
un proxy Istio sidecar (proxy Envoy) est également injecté dans le même Pod afin que vous
puissiez tirer parti de toutes les fonctionnalités d’Istio. Nous verrons comment procéder à
la prochaine section.
176 Chapitre 7 : Découverte des services et maillage de services : trouver de nouveaux territoires et franchir les frontières
Injection automatique du proxy Sidecar (proxy Envoy)
Pour que vous puissiez tirer pleinement parti d’Istio en tant que maillage de services,
les Pods du cluster doivent également utiliser le proxy Istio sidecar. istio-proxy, qui
est essentiellement le proxy Envoy, peut être déployé de deux façons : manuellement
ou automatiquement. La méthode manuelle vous permet de modifier la configuration
d’injection et de proxy. La méthode automatique, comme son nom l’indique, permet
une configuration de proxy automatique au moment de la création du Pod à l’aide d’un
contrôleur d’admission en mutation. Bien que la méthode manuelle soit utile lorsque vous
avez besoin d’une configuration spécifique, la méthode automatique est plus généralement
privilégiée. Nous allons maintenant voir comment utiliser la méthode automatique.
Dans la mesure où l’injection se produit lorsque le Pod est créé, nous pouvons tuer le
pod Nginx et créer un nouveau Pod nginx, seulement cette fois, il aura un sidecar injecté
automatiquement :
$ kubectl delete pod -l app=nginx
pod "nginx-deployment-6b474476c4-bqgh8" deleted
Notez que le déploiement créé deux conteneurs. Il s’agit du proxy sidecar en cours d’exécution
dans le Pod. Vous pouvez le vérifier à l’aide de describe comme suit :
$ kubectl describe pod -l app=nginx
Events:
Type Reason Age From Message
---- ------ ---- ---- -------
Normal Scheduled <unknown> default-scheduler Successfully
assigned default/nginx-deployment-6b474476c4-pfgqv to aks-agentpool-20139558-vmss000001
Normal Pulling 2m35s kubelet, aks-agentpool-20139558-vmss000001 Pulling image
"docker.io/istio/proxyv2:1.9.2"
Normal Created 2m34s kubelet, aks-agentpool-20139558-vmss000001 Created
container nginx
Normal Created 2m34s kubelet, aks-agentpool-20139558-vmss000001 Created
container istio-init
Normal Started 2m34s kubelet, aks-agentpool-20139558-vmss000001 Started
container istio-init
Normal Pulled 2m34s kubelet, aks-agentpool-20139558-vmss000001 Container image
"nginx:1.14.2" already present on machine
Normal Pulled 2m34s kubelet, aks-agentpool-20139558-vmss000001 Successfully
pulled image "docker.io/istio/proxyv2:1.9.2"
Normal Started 2m34s kubelet, aks-agentpool-20139558-vmss000001 Started
container nginx
Normal Pulling 2m34s kubelet, aks-agentpool-20139558-vmss000001 Pulling image
"docker.io/istio/proxyv2:1.9.2"
Normal Pulled 2m33s kubelet, aks-agentpool-20139558-vmss000001 Successfully
pulled image "docker.io/istio/proxyv2:1.9.2"
Normal Created 2m33s kubelet, aks-agentpool-20139558-vmss000001 Created
container istio-proxy
Normal Started 2m33s kubelet, aks-agentpool-20139558-vmss000001 Started
container istio-proxy
Maintenant que vous savez comment déployer le proxy sidecar, vous pouvez utiliser Istio
pour la gestion du trafic, la sécurité, l’application des stratégies et l’observation. Nous
n’aborderons pas chacun de ces aspects, car cela dépasse le cadre de ce livre.
Lorsque vous utilisez un maillage de services, vous devez être en mesure de le visualiser et
de le gérer. Dans la section suivante, nous allons nous concentrer sur Kiali, une console de
gestion pour les maillages de services basés sur Istio.
178 Chapitre 7 : Découverte des services et maillage de services : trouver de nouveaux territoires et franchir les frontières
Gestion des maillages de services Istio à l’aide de Kiali
Kiali est une console de gestion pour Istio qui vous permet d’exécuter et de configurer
facilement un maillage de services avec une observabilité supplémentaire dans votre
environnement. Kiali fournit une image claire du maillage de services à travers les tableaux
de bord qui utilisent la topologie du trafic pour afficher sa structure et son intégrité. Dans
cette section, nous allons voir comment installer Kiali sur un cluster Kubernetes afin de
gagner en visibilité sur le maillage de services Istio.
Nous allons commencer par installer la passerelle d’entrée et de sortie pour Istio à partir du
répertoire istio-1.9.2 que nous avons utilisé lors de l’installation d’Istio :
Istio-1.9.2 $ helm install istio-ingress manifests/charts/gateways/istio-ingress -n \
istio-system
NAME: istio-ingress
LAST DEPLOYED: Mon Apr 5 15:19:01 2021
NAMESPACE: istio-system
STATUS: deployed
REVISION: 1
TEST SUITE: None
NAME: kiali-operator
LAST DEPLOYED: Mon Apr 5 15:27:03 2021
NAMESPACE: kiali-operator
STATUS: deployed
REVISION: 1
TEST SUITE: None
NOTES:
Welcome to Kiali! For more details on Kiali, see: https://kiali.io
The Kiali Operator [v1.32.0] has been installed in namespace [kiali-operator]. It will be
ready soon.
You have elected to install a Kiali CR in the namespace [istio-system]. You should be able
to access Kiali soon.
If you ever want to uninstall the Kiali Operator, remember to delete the Kiali CR first
before uninstalling the operator to give the operator a chance to uninstall and remove all
the Kiali Server resources.
À ce stade, nous pouvons exposer Kiali à l’aide des configurations suivantes, qui vont créer
une passerelle, un service virtuel et une règle de destination :
180 Chapitre 7 : Découverte des services et maillage de services : trouver de nouveaux territoires et franchir les frontières
hosts:
- "kiali.${INGRESS_DOMAIN}"
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
name: kiali-vs
namespace: istio-system
spec:
hosts:
- "kiali.${INGRESS_DOMAIN}"
gateways:
- kiali-gateway
http:
- route:
- destination:
host: kiali
port:
number: 20001
---
apiVersion: networking.istio.io/v1alpha3
kind: DestinationRule
metadata:
name: kiali
namespace: istio-system
spec:
host: kiali
trafficPolicy:
tls:
mode: DISABLE
---
EOF
Type: kubernetes.io/service-account-token
Data
====
ca.crt: 1765 bytes
namespace: 14 bytes
Vous pouvez maintenant copier le jeton et vous connecter avec celui-ci. Vous devez
également installer Prometheus avec Istio pour enregistrer des métriques qui assurent
le suivi de l’intégrité d’Istio et des applications au sein du maillage de services (repor-
tez-vous au chapitre 6 si vous avez besoin d’une actualisation sur la façon de procéder).
Utilisez le manifeste suivant pour installer et configurer Prometheus :
$ kubectl apply -f https://raw.githubusercontent.com/istio/istio/release-1.9/samples/ \
addons/prometheus.yaml
La figure 7-4 montre le tableau de bord Kiali obtenu. Vous remarquerez que la passerelle
d’entrée Istio envoie le trafic à Kiali, ainsi que d’autres déploiements dans l’espace de noms
istiosystem. Le tableau de bord présente différentes configurations et fonctionnalités
Istio qui peuvent être utilisées directement à partir de l’interface utilisateur. Par exemple,
si vous regardez l’espace de noms par défaut dans l’onglet Présentation, vous pouvez voir
que l’auto-injection de proxy sidecar est déjà activée pour tous les déploiements dans cet
espace de noms (voir la figure 7-5). Vous pouvez utiliser cette fonctionnalité à partir de
l’interface utilisateur pour activer ou désactiver l’injection automatique du proxy sidecar.
182 Chapitre 7 : Découverte des services et maillage de services : trouver de nouveaux territoires et franchir les frontières
Figure 7-5. Tableau de bord Kiali montrant l’état du proxy sidecar d’injection automatique
dans l’espace de noms par défaut
Après avoir déployé l’application de voyage de démonstration, vous devez commencer par
activer la prise en charge du proxy sidecar. Vous allez activer l’injection automatique pour
tous les espaces de noms nouvellement créés en cliquant sur les trois points dans la zone en
surbrillance à la figure 7-6.
Vous pouvez également activer l’injection automatique dans une charge de travail déjà
déployée (par exemple, des Pods) en cliquant sur le bouton Actions situé dans le coin
supérieur droit (voir la figure 7-7).
184 Chapitre 7 : Découverte des services et maillage de services : trouver de nouveaux territoires et franchir les frontières
Figure 7-7. Activation de l’injection automatique pour la charge de travail des voitures
Lorsque vous activez l’injection automatique pour les charges de travail via le tableau de
bord Kiali, le Pod d’application est redéployé avec un sidecar injecté automatiquement, ce
qui est similaire à la méthode que nous avons abordée précédemment pour le Pod Nginx.
Vous pouvez également utiliser la fonction de routage des demandes pour un service dans
l’onglet Services, comme illustré à la figure 7-8, afin de générer une règle de trafic qui crée
une configuration Istio pour acheminer une quantité de trafic souhaitée vers un hôte de
passerelle spécifique, ou qui utilise des disjoncteurs.
Figure 7-9. Ajout d’un itinéraire de requête pour un service dans une configuration Istio via Kiali
Kiali fournit également des journaux disponibles dès le départ, des métriques via
Prometheus et des suivis via Jaeger si vous les avez déployés dans votre environnement.
Nous vous conseillons vivement d’explorer l’interface utilisateur de Kiali pour découvrir
l’ensemble de ses fonctionnalités.
186 Chapitre 7 : Découverte des services et maillage de services : trouver de nouveaux territoires et franchir les frontières
Résumé
Dans ce chapitre, nous avons exploré la découverte des services et le maillage de services,
deux concepts importants qui vous permettent d’associer efficacement vos applications
à un environnement cloud comme Azure. Nous avons présenté CoreDNS comme DNS
par défaut remplaçant kube-dns en tant que mécanisme de découverte de services dans
l’environnement Kubernetes. Nous avons également vu le maillages de services Istio, qui
utilise Envoy comme plan de données pour obtenir des informations utiles sur les services
et fournit l’ensemble complet de fonctionnalités du maillage de services Istio. Vers la fin
du chapitre, nous avons présenté Kiali, qui fournit une console de gestion complète sur un
maillage de services basé sur Istio. Kiali est en mesure de fournir une observabilité dans un
service natif du cloud en offrant une vue unique de tout dans la pile.
Dans le chapitre suivant, nous verrons en détail comment le réseau de conteneurs fonctionne
dans Kubernetes et comment vous pouvez sécuriser votre infrastructure avec diverses
techniques de gestion des stratégies.
Résumé 187
CHAPITRE 8
Gestion des réseaux et des stratégies :
De véritables gardiens
Dans les chapitres précédents, nous avons créé une infrastructure dans Azure et nous avons
expliqué comment découvrir et surveiller nos applications. Maintenant, il est temps de
sécuriser ces applications ! Bien qu’il y ait eu de nombreuses violations de données dans
le cloud au fil du temps en raison de simples erreurs de configuration, la sécurisation de
l’infrastructure cloud est bien plus simple qu’il n’y paraît. La technologie de mise en réseau
dans le cloud a rapidement évolué et, aujourd’hui, un certain nombre de fournisseurs
proposent des logiciels natifs du cloud qui peuvent vous aider à améliorer votre configuration
réseau et à la sécuriser.
Azure est livré avec une offre, la stratégie Azure, qui vous permet de définir une stratégie sur
un locataire, un groupe de gestion ou un abonnement, afin de bénéficier d’une couche de
sécurité par défaut. Par exemple, dans Azure, vous pouvez définir une stratégie qui garantit
qu’aucun compte de stockage n’est accessible publiquement au sein d’un groupe de gestion
ou d’un abonnement.
Dans ce chapitre, nous allons explorer la puissance de la mise en réseau de conteneurs et
les nombreuses façons dont vous pouvez l’utiliser pour améliorer votre infrastructure. Nous
vous expliquerons également comment appliquer une stratégie à votre infrastructure pour
assurer sa sécurité.
Nous commencerons par une discussion sur la mise en réseau des conteneurs et les normes
sur lesquelles plusieurs projets sont conçus, puis nous nous concentrerons sur des produits
tels que Calico et Flannel, qui fournissent une connectivité réseau et une mise en œuvre
des stratégies réseau. Nous conclurons le chapitre par une discussion sur l’application de la
stratégie système avec Open Policy Agent (OPA).
189
Container Network Interface (CNI)
Comme nous l’avons mentionné dans les chapitres précédents, les conteneurs offrent un
vaste éventail de fonctionnalités de sécurité et de portabilité. La pile de mise en réseau est
l’une des capacités les plus intéressantes. Les fonctionnalités des espaces de noms cgroups
et réseau de Linux permettent d’accéder à diverses fonctionnalités réseau qui peuvent être
utilisées pour améliorer la sécurité et la télémétrie, ainsi que pour gérer les performances.
Cilium, un outil logiciel qui fournit l’équilibrage de charge, la sécurité, la télémétrie, la
gestion de la bande passante et d’autres fonctionnalités en tant que module complémentaire
pour Kubernetes, est un bon exemple de la flexibilité et de la puissance de la fonctionnalité
de réseau de conteneurs. Nous aborderons les Cilium en détail plus loin dans ce chapitre.
Au chapitre 3, nous avons brièvement mentionné comment le secteur dispose d’une
spécification standard pour le runtime de conteneur et l’image de conteneur. L’interface
de réseau de conteneurs (CNI) a été créée en 2015 (et a finalement été ajoutée à la liste
de projets d’incubation de la Cloud Native Computing Foundation [CNCF]) en tant que
norme pour la configuration des interfaces réseau de conteneurs et des paramètres réseau
associés. La spécification CNI permet de gérer les primitives suivantes :
Ces plug-ins garantissent que le conteneur peut s’interfacer correctement avec le plan de
contrôle Azure VNet. Vous pouvez utiliser ces plug-ins dans Azure Kubernetes service
(AKS) et des machines virtuelles Azure autonomes.
Avec les plug-ins azure-vnet et azure-vnet-ipam, l’hôte n’a plus besoin de s’occuper de la
configuration ni de la gestion des IP, car c’est le plan de contrôle Azure VNet qui s’en charge.
Divers projets CNI
Le projet CNI contient un ensemble de plug-ins CNI par défaut appartenant à trois catégories :
Principal
Ces plug-ins créent des interfaces (bridge, ipvlan, macvlan, ptp, host-device).
IPAM
Ces plug-ins affectent des adresses IP aux interfaces (dhcp, host-local, statique).
Meta
Il s’agit d’autres plug-ins natifs qui permettent d’effectuer des actions telles que :
• Réglage de sysctl
• Limitation de la bande passante
• Pare-feu
• Flannel (que nous verrons en détails plus loin dans ce chapitre)
Vous trouverez plus d’informations sur ces plug-ins natifs sur la page des plug-ins CNI.
• Infoblox
• Juniper Contrail
• VMware NSX
Bien que certains plug-ins CNI soient conçus pour une infrastructure très spécifique (par
exemple, le CNI ACI de Cisco), bon nombre d’entre eux fonctionnent parfaitement bien avec
les services Azure et avec Azure. Dans les sections suivantes, nous allons explorer Calico,
Cilium, Flannel et OPA, puis nous aborderons la façon dont ces systèmes contribuent à la
création et à la sécurisation de l’infrastructure réseau.
Calico
Calico est une solution de sécurité et de stratégie de réseau open source pour les conteneurs,
les machines virtuelles et les installations bare metal sous Windows et Linux. Calico fournit
l’application de la stratégie de sécurité réseau, ainsi que la possibilité de mettre en œuvre
des réseaux Zero Trust. Calico prend en charge plusieurs plans de données, y compris un
plan de données de pointe Berkeley Packet Filter étendu (eBPF) Linux, le plan de données
de réseau Linux standard et le plan de données Windows HNS. Calico est exécuté au-dessus
du plan de données hôte pour effectuer l’application des stratégies réseau. Il prend en charge
la pile de réseau Linux standard.
Calico 193
Architecture de base
Calico est doté d’une architecture client/magasin de données qui simplifie le fonctionnement
de la plateforme. Il inclut les composants clés suivants (également représentés à la figure 8-1) :
Felix
Démon de programmation réseau qui installe des listes de contrôle d’accès réseau
(ACL), des informations de routage et la gestion des interfaces et des rapports sur l’état
BIRD
Obtient des informations de routage de Felix et redistribue le routage via le
protocole BGP (routes over Border Gateway Protocol)
confd
Écoute les modifications de routage depuis le magasin de données Calico et les transmet
à BIRD
Plug-in CNI Calico
Interface des interfaces réseau du conteneur
Banque de données
Contient des informations opérationnelles sur les stratégies, les charges de travail et les
allocations IPAM
Typha
Proxy de mise en cache pour le magasin de données utilisé pour mettre à l’échelle le
nombre de nœuds qui se connectent au magasin de données
calicoctl
Interface de ligne de commande pour la création, la lecture, la mise à jour et la
suppression d’objets Calico
Déploiement de Calico
Il existe deux options pour le déploiement de Calico : l’installer dans le cadre du moteur de
stratégie réseau dans une installation AKS ou le déployer manuellement sur Kubernetes.
Calico 195
Déploiement de Calico via l’installation AKS
Azure offre une excellente prise en charge de Calico en tant que moteur de stratégie
réseau. Il peut être installé dans le cadre de la création d’une instance AKS dans l’étape de
configuration réseau, comme illustré à la figure 8-2.
Dans cette étape, si vous cliquez sur Calico dans le cadre de l’installation d’AKS, un Pod
Calico Typha est installé sur chaque nœud de calcul Kubernetes.
1. Tout d’abord, installez l’opérateur, puis les ressources Calico. Cela créera un espace
de noms d’opérateur tigera- :
$ kubectl create -f https://docs.projectcalico.org/manifests/tigera-operator.yaml
$ kubectl create -f https://docs.projectcalico.org/manifests/custom-resources.yaml
2. Vérifiez que tous les nœuds de Calico sont maintenant en cours d’exécution :
$ kubectl get pods -n calico-system
Installation de calicoctl
Pour contrôler Calico, vous devrez avoir accès à son utilitaire d’interface de ligne de
commande. Il existe plusieurs façons d’accéder à l’utilitaire, comme décrit dans la
documentation d’installation de Calico. Dans le cadre de cet exemple, nous allons
simplement télécharger l’interface de ligne de commande sur notre machine et l’exécuter
en tant que plug-in kubectl :
2. Téléchargez le binaire :
$ curl -o kubectl-calico -O -L "https://github.com/projectcalico/calicoctl/releases/ \
download/v3.21.0/calicoctl-linux-ppc64le"
Exploration de Calico
Nous avons vu les avantages généraux de l’utilisation de Calico, ainsi que quelques notions
de base sur son fonctionnement et son installation. Nous allons maintenant détailler son
utilisation. Dans le reste de cette section, nous allons utiliser eBPF comme plan de données
au lieu de la pile réseau Linux standard.
Azure n’autorise pas les IP inconnues dans son plan de données, de sorte que vous ne pouvez
utiliser qu’un réseau de superposition basé sur VXLAN entre les nœuds. Cela n’est possible
que si vous créez un cluster auto-géré (figure 8-3) et non AKS. Sur AKS, vous devez utiliser
Activation d’eBPF
La prochaine étape de la mise en place de notre infrastructure Calico consiste à activer
le plan de données eBPF. L’activation d’eBPF vous permet de tirer parti des nouvelles
fonctionnalités du noyau et de supprimer l’utilisation de kube-proxy pour l’équilibrage de
charge. Lorsqu’eBPF est activé, l’utilisation de kube-proxy est désactivée. Pour en savoir plus
sur la mise en œuvre d’eBPF de Calico, lisez cet article de blog.
Calico 197
Pour activer eBPF, procédez comme suit :
La stratégie de réseau de Calico prend en charge la sécurisation des applications à l’aide des
critères OSI des couches 5 à 7, ainsi que de l’identité de chiffrement. Vous trouverez des
exemples sur la page Configuration de la stratégie réseau de Calico.
• À l’échelle mondiale (s’applique à tous les Pods de tous les espaces de noms), connue
sous le nom de GlobalNetworkPolicy
• Par réseau ou hôte, connu sous le nom de HostEndpoint
• Par espace de noms, connu sous le nom NetworkPolicy
NetworkPolicy : autorisation du trafic au sein d’un espace de noms entre deux étiquettes
Dans cet exemple, nous allons autoriser le trafic de l’espace de noms de production avec
le sélecteur vert vers un Pod dans le même espace de noms avec le sélecteur bleu sur le
port TCP/1234. Créez un nouveau fichier appelé network-policy.yaml :
apiVersion: projectcalico.org/v3
kind: NetworkPolicy
metadata:
name: allow-tcp-1234
namespace: production
spec:
selector: color == 'blue'
ingress:
- action: Allow
protocol: TCP
Calico 199
source:
selector: color == 'green'
destination:
ports:
- 1234
Une fois cette stratégie appliquée, le trafic sera en mesure de circuler vers le port TCP 1234
pour n’importe quel Pod vert.
Cilium
L’un des outils de mise en réseau les plus innovants qui a été lancé au cours des cinq
dernières années est le projet Cilium, qui utilise largement eBPF pour fournir une suite
de fonctionnalités de mise en réseau, d’observabilité et de sécurité qui sont orientées vers
l’infrastructure native du cloud.
Cilium utilise la technologie du noyau Linux eBPF qui permet de bénéficier d’une visibilité
réduite, d’une puissance élevée et d’une logique de contrôle pour le noyau et les applications
qui s’exécutent au-dessus de celle-ci. L’utilisation d’eBPF a contribué à la popularité de
Cilium pour les architectes d’infrastructure, car la plateforme fournit des fonctionnalités
autour de trois piliers clés :
Mise en réseau
Cilium implémente son propre CNI qui utilise Linux eBPF. Cilium est ainsi extrêmement
performant et peut effectuer un équilibrage de charge au lieu de s’appuyer sur kube-
proxy. Il permet également la connectivité multicluster, ce qui est important pour les
grandes installations.
Observabilité
Grâce à l’utilisation d’eBPF, Cilium est un logiciel d’observabilité unique. Cilium peut
effectuer une inspection approfondie des paquets sur toutes les couches de connectivité
et de données du réseau.
Sécurité
L’une des meilleures fonctionnalités de Cilium est qu’il peut effectuer un chiffrement
transparent entre les hôtes via IPSec. Cela signifie que vous obtenez un chiffrement de
bout en bout via un mécanisme très efficace, sans avoir à apporter de modifications
à votre application. Bien que Cilium fournisse sa propre stratégie de sécurité de
correspondance avec étiquette + CIDR, il effectue également un filtrage (OSI) de
couche 7 (par exemple, il filtre les requêtes DNS sortantes ou les requêtes HTTP
entrantes).
En dernier lieu, Cilium vous permet d’effectuer une introspection de la couche 7 pour
prendre des décisions stratégiques (consultez cet article de blog pour en savoir plus).
Déploiement de Cilium
Cilium peut être installé sur un cluster Kubernetes auto-géré ou sur un cluster AKS géré.
Dans les deux cas, Cilium peut être déployé via Helm, ce qui facilite l’installation. En outre,
Cilium fournit un conteneur pour effectuer des contrôles de connectivité afin de vérifier
que le trafic réseau peut circuler librement entre les Pods de votre cluster.
Pour plus d’informations, consultez la documentation spécialisée sur le déploiement de
Cilium sur Azure.
Cilium 201
$ kubectl apply -f https://raw.githubusercontent.com/cilium/cilium/v1.9/install/ \
kubernetes/quick-install.yaml
Cela va déployer une série de Pods qui utiliseront différents chemins de réseau pour se
connecter les uns aux autres afin de vérifier la connectivité. Les chemins de connectivité
incluent ou non l’équilibrage de charge de service et diverses combinaisons de stratégies réseau.
2. Maintenant, nous allons créer un principal de service pour interagir avec les API Azure
et remplir les variables d’environnement à transmettre à Helm :
$ az ad sp create-for-rbac --name cilium-operator > azure-sp.json
3. Nous allons installer le référentiel Cilium localement, puis installer Cilium sur notre
cluster Kubernetes :
$ helm repo add cilium https://helm.cilium.io/
$ helm install cilium cilium/cilium --version 1.9.9 \
--namespace kube-system \
--set azure.enabled=true \
--set azure.resourceGroup=$AZURE_NODE_RESOURCE_GROUP \
--set azure.subscriptionID=$AZURE_SUBSCRIPTION_ID \
--set azure.tenantID=$AZURE_TENANT_ID \
--set azure.clientID=$AZURE_CLIENT_ID \
--set azure.clientSecret=$AZURE_CLIENT_SECRET \
--set tunneldisabled \
--set ipam.mode=azure \
--set masquerade=false \
--set nodeinit.enabled=true
4. Nous pouvons contrôler l’installation en vérifiant que les quatre Pods initiaux ont été
créés et que des Pods cilium et cilium-operator sont en cours d’exécution :
$ kubectl -n kube-system get pods --watch
cilium-operator-ad4375ds5-2x2q3 1/1 Running 0 4m18s
cilium-s5x8xk 1/1 Running 0 4m19s
Installation de Hubble
Vous devez également installer Hubble, une interface utilisateur qui vous permet d’afficher
une carte de service représentant les dépendances entre les services et les statistiques sur
l’utilisation et les performances du réseau. L’interface de mise à jour en temps réel de Hubble
(voir la figure 8-6) vous permet de présenter un grand nombre d’informations sur la mise
en page et le flux des données entre les conteneurs. De plus, elle permet de modéliser la
stratégie Cilium.
Figure 8-6. Capture d’écran de l’interface utilisateur Hubble montrant une architecture simple
Cilium 203
Intégration de Cilium à votre cloud
Comme nous l’avons déjà mentionné, Cilium dispose d’un riche ensemble de fonctionnalités
dont vous pouvez tirer parti. Dans cette section, nous allons utiliser Cilium en tant que
fournisseur de réseau et d’agent responsable de l’application des stratégies (pare-feu). Nous
verrons ensuite l’observabilité avec Cilium.
Pare-feu hôte
Comme nous l’avons fait dans le cadre de l’exploration approfondie de Calico, nous allons
mettre en œuvre un ensemble de stratégies réseau. L’avantage de Cilium est qu’il peut
appliquer la stratégie sur les couches L3, L4 ou L7. La mise en œuvre de la stratégie réseau
comporte trois modes, comme indiqué dans le tableau 8-1.
La stratégie est écrite par rapport à un modèle de liste autorisée dans lequel le trafic sera
bloqué s’il n’existe pas de règle d’autorisation explicite.
Les règles des couches L3 et L4 peuvent être spécifiées à l’aide des méthodes suivantes :
Étiquettes
Utilisez un sélecteur pour regrouper les Pods.
Services
Définissez une stratégie à l’aide d’un service Kubernetes.
Entités
Étendues prédéfinies spéciales gérées par Cilium.
IP/CIDR
Une IP ou une plage IP (CIDR).
Noms DNS
Un nom DNS.
En outre, si vous souhaitez créer un exemple L4 dans lequel vous souhaitez limiter le DNS
de sortie aux serveurs DNS publics de Google, vous pouvez écrire la règle illustrée dans
l’exemple suivant :
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "allow-to-google-dns"
spec:
endpointSelector:
{}
egress:
- toCIDR:
- 8.8.8.8/32
- 8.8.8.4/32
toPorts:
- ports:
- port: '53'
protocol: UDP
- ports:
- port: '53'
Protocol: TCP
En dernier lieu, Cilium permet également la visibilité L7 pour le trafic HTTP(s), Kafka et
DNS. Dans l’exemple suivant, nous autorisons le trafic vers le point de terminaison /admin
sur le port 80 pour tous les Pods :
apiVersion: "cilium.io/v2"
kind: CiliumNetworkPolicy
metadata:
name: "rule1"
spec:
description: "Allow HTTP GET /admin
endpointSelector:
{}
ingress:
Cilium 205
- fromEndpoints:
toPorts:
- ports:
- port: "80"
protocol: TCP
rules:
http:
- method: "GET"
path: "/admin"
Vous trouverez des détails plus spécifiques sur les règles de stratégie L7 dans la documentation
Cilium et la stratégie de couche 7.
Observabilité
Comme nous l’avons mentionné brièvement plus tôt, Hubble est l’endroit où les opérateurs
Cilium peuvent observer ce qui se passe dans leur infrastructure. Une fois que vous aurez
installé Hubble et le test de connectivité (à partir des étapes d’installation), vous serez en
mesure d’observer les flux réseau au sein de l’espace de noms. Dans cette section, nous irons
plus loin et nous utiliserons une nouvelle fonctionnalité Cilium qui fournit une visibilité de
protocole pour les couches 3 et 4, afin de vous aider à obtenir des détails plus spécifiques
sur le trafic au niveau de chaque port. Vous devrez implémenter des stratégies de couche 7
pour obtenir des fonctionnalités d’observabilité de cette dernière.
Pour activer la visibilité sur la couche 3 et la couche 4, vous devrez activer les annotations
sur vos Pods. Voici un exemple :
$ kubectl annotate pods --all io.cilium.proxy-visibility="<Egress/53/UDP/DNS>, \
<Ingress/80/TCP/HTTP>"
Cela permettra de mesurer le trafic DNS sortant (sortie), ainsi que le trafic entrant
(entrée) HTTP vers le Pod.
Les informations de visibilité sont représentées par une liste de tuples séparés par des
virgules dans l’annotation :
<{Traffic Direction}/{L4 Port}/{L4 Protocol}/{L7 Protocol}>
Lorsqu’il est activé, Hubble affiche des informations spécifiques au protocole. La figure 8-7
montre un exemple de visibilité DNS.
Si vous souhaitez apprendre à inspecter les connexions chiffrées TLS (Transport Layer
Security), consultez la page Inspection des connexions chiffrées TLS.
Flannel
Flannel est un système d’infrastructure réseau (OSI) de couche 3 pour Kubernetes
qui était initialement intégré au projet CoreOS de Red Hat. Il s’agit de l’un des CNI les
plus simples pour Kubernetes. Il s’appuie sur un agent binaire, nommé flanneld, pour
être exécuté sur chaque hôte afin de configurer un réseau Pod de superposition, puis de
stocker la configuration dans le magasin de données Kubernetes. Flannel ne fournit que la
connectivité réseau. Il ne prend en charge aucun type d’application de la stratégie de réseau.
Déploiement de Flannel
Flannel peut être installé rapidement lorsque vous configurez votre cluster en exécutant :
$ kubectl apply -f https://raw.githubusercontent.com/coreos/flannel/master/ \
Documentation/kube-flannel.yml
Flannel 207
L’application de kube-flannel.yml définira ce qui suit :
•
ClusterRole et ClusterRoleBinding pour le contrôle d’accès basé sur les rôles (RBAC).
• Le compte de service Kubernetes qui sera utilisé par Flannel.
• Un ConfigMap contenant à la fois une configuration CNI et une configuration de
Flannel. Le réseau de la configuration de Flannel doit correspondre au système de
routage interdomaine sans classe (CIDR) du réseau du Pod. Le choix du back-end est
également effectué ici et la valeur par défaut est VXLAN.
• Un DaemonSet pour chaque architecture afin de déployer le Pod Flannel sur chaque nœud.
Le Pod comporte deux conteneurs : le démon Flannel lui-même et un initContainer
pour le déploiement de la configuration CNI à un emplacement que le kubelet peut lire.
Lorsque vous exécuterez des Pods, des adresses IP leur seront allouées à partir du CIDR
de réseau du Pod. Quel que soit le nœud sur lequel ces Pods se retrouveront, ils seront en
mesure de communiquer entre eux.
Vous pouvez reconfigurer votre back-end de façon à ce qu’il utilise un autre espace
d’adresse, un masque plus petit ou des paramètres de back-end différents en modifiant les
données écrites dans net-conf.json dans le fichier fkube-flannel.yaml. Vous trouverez plus
d’informations sur la configuration du back-end dans les pages Documentation sur le back-
end Flannel et Configuration de Flannel.
Désormais, les nœuds de travail Kubernetes auront des adresses IP à partir de votre VNet
Azure, mais n’importe quel Pod déployé aura des adresses IP issues de la plage d’IP du
réseau de Pod configurée. Si vous souhaitez disposer de plusieurs réseaux Pod (pour la
séparation du trafic réseau), vous devrez exécuter un processus flanneld distinct.
Exploration de Flannel
Flannel est un CNI Kubernetes plus simple qui nécessite une configuration minimale. Il
dispose de back-ends utilisés comme des plug-ins qui créent des réseaux de superposition
entre les machines d’un réseau (voir la figure 8-8). Les back-ends de transport pris en charge
sont les suivants :
• VXLAN
• Host-gw
• Protocole UDP (User Datagram Protocol)
• Alivpc
Flannel 209
L’équipe de projet de flanelle recommande VXLAN ou host-gw comme back-ends pour la
communication. Si vous avez besoin de chiffrer le trafic, IPsec est également une option.
Vous trouverez plus d’informations sur les back-ends pris en charge dans la documentation
de Flannel.
Flannel ne vous permet pas d’exécuter plusieurs réseaux à partir d’un seul démon ; vous
devrez exécuter des démons distincts avec différents fichiers de configuration.
Stratégie Azure
Bien qu’il soit sans aucun doute utile d’exécuter activement un logiciel qui protège votre
infrastructure basée sur le cloud, la stratégie Azure vous permet de définir une stratégie
globale sur de nombreux aspects de votre infrastructure cloud, en particulier en ce qui con-
cerne la sécurité des ressources.
La stratégie Azure exécute trois fonctions clés :
La stratégie Azure inclut également des initiatives, qui sont des collections de stratégies
alignées sur une norme du secteur (par exemple, PCI v3.2.1:2018).
À ce stade, les stratégies ont été créées, mais aucune portée ne leur a été attribuée. Vous
pouvez appliquer une stratégie sur un abonnement (ainsi que toutes les ressources au sein
de celui-ci), ou vous pouvez l’appliquer à un groupe de gestion qui couvrira tous les groupes
de gestion enfants et les abonnements.
Dans tous les cas, vous devrez faire enregistrer le fournisseur de ressources Microsoft.
PolicyInsights pour votre ou vos abonnements. Vous pouvez l’activer en exécutant :
$ az provider register --namespace 'Microsoft.PolicyInsights'
• Ajouter
• Auditer
• AuditIfNotExists
• Refuser
Vous pouvez en savoir plus sur leur utilisation dans l’article « Comprendre les effets de la
stratégie Azure ».
Dans la réponse, nous verrons le chemin de la nouvelle stratégie dans le champ id, par
exemple :
"id": "/subscriptions/<subscription-ID>/providers/Microsoft.Authorization/ \
policyDefinitions/allowed-regions"
La stratégie est désormais appliquée. Si nous devions essayer de créer une ressource dans
une région autre que celle des États-Unis, nous recevrions une erreur similaire à celle
illustrée à la figure 8-10.
Les stratégies OPA sont codifiées dans un langage déclaratif appelé Rego (voir la
documentation sur le langage de la stratégie). Les stratégies sont ensuite déployées sur le
service OPA sur l’hôte. Contrairement à un certain nombre de systèmes que nous avons
abordés dans ce chapitre, OPA n’effectue aucune exécution, il effectue plutôt des décisions
stratégiques. OPA évalue les stratégies et les données pour produire des résultats de requête
renvoyés au client. Les stratégies sont écrites dans un langage déclaratif de haut niveau et
peuvent être chargées de manière dynamique dans OPA, à distance via des API ou via le
système de fichiers local.
OPA fournit une API REST que les services/systèmes tiers tels que Kubernetes, SSH, Sudo
et Envoy peuvent utiliser pour répondre à des questions telles que les suivantes :
GET /v1/policies/<name>
Renvoie une stratégie spécifique
PUT /v1/policies/<name>
Crée ou met à jour une stratégie
DELETE /v1/policies/<name>
Supprime une stratégie
GET/POST /v1/data/<name>
Vous permet de retourner ou de créer un document
OPA vous permet de centraliser plusieurs stratégies de sécurité sur plusieurs éléments
d’infrastructure dans un seul système. Vous trouverez une liste complète des intégrations
OPA sur la page Écosystème OPA. Sans OPA, vous devrez mettre en œuvre la gestion des
stratégies pour votre logiciel à partir de zéro. Les composants requis tels que le langage
de stratégie (syntaxe et sémantique) et le moteur d’évaluation doivent être soigneusement
conçus, mis en œuvre, testés, documentés, puis conservés pour garantir un comportement
correct et une expérience utilisateur positive pour vos clients.
Les exemples suivants vont créer une stratégie qui permet l’autorisation SSH pour le groupe
sre et le groupe associé à l’application :
package sshd.authz
import input.pull_responses
import input.sysinfo
import data.hosts
# Allow access to any user who contributed to the code running on the host.
#
# This rule gets the "host_id" value from the file "/etc/host_identity.json."
# It is available in the input under "pull_responses" because we
# asked for it in our pull policy above.
#
# It then compares all the contributors for that host against the username
# that is asking for authorization.
allow {
hosts[pull_responses.files["/etc/host_identity.json"].host_id].contributors[_] == \
sysinfo.pam_username
}
# If the user is not authorized, then include an error message in the response.
errors["Request denied by administrative policy"] {
not allow
}
Nous allons créer une deuxième stratégie qui autorise uniquement l’accès sudo pour le
groupe sre :
package sudo.authz
# If the user is not authorized, then include an error message in the response.
errors["Request denied by administrative policy"] {
not allow
}
Une fois ces commandes exécutées avec succès, notre stratégie sera appliquée et seuls les
utilisateurs du groupe sre auront un accès SSH et sudo à toutes les machines. Pendant ce
temps, le groupe de services approprié ne disposera d’un accès SSH que pour la machine sur
laquelle le service sera déployé.
Résumé
Bien que l’utilisation d’une infrastructure native du cloud présente des avantages
considérables pour l’opérateur, elle constitue un risque important pour votre entreprise si
l’infrastructure n’est pas bien sécurisée. Dans ce chapitre, nous avons examiné un moyen de
sécuriser et d’auditer votre infrastructure. Tout d’abord, nous avons examiné la norme CNI
et la façon dont elle est le fondement d’autres plateformes telles que Flannel et Cilium. Nous
avons examiné comment ces systèmes peuvent être utilisés pour fournir une connectivité
et une sécurité réseau à votre infrastructure cloud. Ensuite, nous avons examiné les
mécanismes de stratégie non-réseau pour la gestion de votre infrastructure cloud via la
stratégie Azure, ainsi que la stratégie pour les applications via l’agent de stratégie ouverte.
La création de votre infrastructure cloud grâce à une configuration réseau sécurisée et à une
stratégie bien définie vous aidera à vous assurer que votre infrastructure évolue de manière
sécurisée. Maintenant que vous comprenez les bases de la mise en réseau des conteneurs et
du cloud, nous allons orienter la discussion vers le stockage et le service de données dans
le cloud.
L’un des plus grands obstacles à surmonter lors de la création d’une infrastructure native
du cloud est la mise en place d’un stockage fiable et évolutif pour une utilisation en ligne
et hors ligne. Bien que les premiers services de stockage exécutés dans le cloud aient été
désapprouvés, un certain nombre de projets de stockage natif du cloud ont réussi, le plus
important d’entre eux ayant été Vitess. Les services cloud, y compris Azure, ont également
considérablement investi dans les disques gérés pour les machines virtuelles et les virtual
machine scale sets, ainsi que les comptes de stockage avancé (par exemple, Gen2) et les
services de bases de données gérées (comme MySQL, SQL Server et Redis). Tout cela a
fait du stockage un concept de premier ordre dans le cloud d’Azure. Dans ce chapitre, nous
allons examiner pourquoi vous devez exécuter des solutions de stockage à grande échelle
dans Azure et comment les orchestrer de façon à faciliter leur gestion.
219
Dans ce chapitre, nous allons examiner certains des magasins de données matures qui font
partie du paysage CNCF. Vitess, Rook, TiKV et etcd sont tous des magasins de données cloud
matures qui sont capables de s’adapter à une taille énorme et sont exécutés en tant que systèmes
de données de première classe sur Azure. Ces systèmes représentent les éléments constitutifs
fondamentaux d’un écosystème de données exploité dans une infrastructure cloud.
Architecture Vitess
Vitess fournit le partitionnement en tant que service en créant un système de style
middleware, tout en continuant à utiliser MySQL pour stocker des données. L’application
cliente se connecte à un démon connu sous le nom de VTGate (voir la figure 9-1). VTGate
est un routeur prenant en charge les clusters qui achemine les requêtes vers les instances
VTTablet appropriées, qui gèrent chaque instance de MySQL. Le service de topologie stocke
la topologie de l’infrastructure, y compris l’emplacement où les données sont stockées et la
capacité de chaque instance VTTablet à servir les données.
Figure 9-1. Architecture Vitess
Vitess fournit également deux interfaces administratives : vtctl, une interface de ligne de
commande ; et vtctld, une interface web.
VTGate est un routeur de requête (ou proxy) pour acheminer des requêtes du client vers les
bases de données. Le client n’a pas besoin de connaître quoi que ce soit, sauf l’emplacement
où se trouve l’instance de VTGate, ce qui signifie que l’architecture client-serveur est simple.
4. Vous serez en mesure de vérifier que l’installation du cluster initial a été une réussite en
procédant comme suit :
$ kubectl get pods
NAME READY STATUS RESTARTS AGE
example-etcd-faf13de3-1 1/1 Running 0 78s
example-etcd-faf13de3-2 1/1 Running 0 78s
example-etcd-faf13de3-3 1/1 Running 0 78s
example-vttablet-zone1-2469782763-bfadd780 3/3 Running 1 78s
example-vttablet-zone1-2548885007-46a852d0 3/3 Running 1 78s
example-zone1-vtctld-1d4dcad0-59d8498459-kwz6b 1/1 Running 2 78s
example-zone1-vtgate-bc6cde92-6bd99c6888-vwcj5 1/1 Running 2 78s
vitess-operator-8454d86687-4wfnc 1/1 Running 0 2m29s
Vous disposez maintenant d’un petit cluster Vitess à une seule zone exécuté avec deux réplicas.
Vous trouverez d’autres exemples d’opérations de base de données sur la page d’exemple des
opérations Kubernetes Vitess.
L’un des cas d’utilisation les plus courants que vous rencontrerez est la nécessité d’ajouter
ou de supprimer des réplicas de la base de données. Pour ce faire, vous pouvez facilement
exécuter les opérations suivantes :
$ kubectl edit planetscale.com example
# To add or remove replicas, change the replicas field of the appropriate resource
# to the desired value. E.g.
keyspaces:
- name: commerce
turndownPolicy: Immediate
partitionings:
- equal:
parts: 1
shardTemplate:
databaseInitScriptSecret:
name: example-cluster-config
key: init_db.sql
replication:
enforceSemiSync: false
tabletPools:
L’architecture de Rook
Rook est un orchestrateur Kubernetes et non une véritable solution de stockage. Rook
prend en charge les systèmes de stockage suivants :
• Ceph, une solution de stockage distribué hautement évolutive pour le stockage en bloc,
le stockage d’objets et les systèmes de fichiers partagés avec des années de déploiements
en production
•
Cassandra, une base de données NoSQL hautement disponible présentant des
performances ultra-rapides, une cohérence réglable et une évolutivité massive
• NFS, qui permet aux hôtes distants de monter des systèmes de fichiers sur un réseau et
d’interagir avec ces systèmes de fichiers comme s’ils étaient montés localement
2. Installez l’opérateur :
$ cd rook/cluster/examples/kubernetes/cassandra
$ kubectl apply -f operator.yaml
5. Pour vérifier que tous les nœuds souhaités sont en cours d’exécution, émettez la
commande suivante :
$ kubectl -n rook-cassandra get pod -l app=rook-cassandra
apiVersion: cassandra.rook.io/v1alpha1
kind: Cluster
metadata:
name: rook-cassandra
namespace: rook-cassandra
spec:
version: 3.11.6
repository: my-private-repo.io/cassandra
mode: cassandra
annotations:
datacenter:
name: us-east2
racks:
- name: us-east2
members: 3 # Change this number up or down
De même, les clusters Ceph et NFS peuvent être déployés facilement à l’aide de
l’opérateur Rook.
Présentation de TiKV
TiKV (Titanium key-value), créé par PingCAP, Inc., est un magasin clé-valeur open source,
distribué et transactionnel. Contrairement à de nombreux systèmes NoSQL et de clé-valeur,
TiKV fournit des API simples (brutes), ainsi que des API transactionnelles qui offrent une
conformité à l’atomicité, à la cohérence, à l’isolation et à la durabilité (ACID).
• Géoréplication
• Évolutivité horizontale
• Transactions distribuées cohérentes
• Prise en charge du coprocesseur
• Partitionnement automatique
TiKV est une option intéressante en raison de ses fonctions de partitionnement automatique
et de géoréplication, ainsi que de sa capacité à évoluer pour stocker plus de 100 To de
données. Il fournit également de solides garanties de consensus grâce à son utilisation du
protocole Raft pour la réplication.
Architecture TiKV
Comme nous l’avons mentionné précédemment, TiKV dispose de deux API qui peuvent
être utilisées pour différents cas d’utilisation : brute et transactionnelle. Le tableau 9-1 décrit
les différences entre ces deux API.
Dans un nœud TiKV (illustré à la figure 9-3), RocksDB fournit les mécanismes de stockage
sous-jacents et Raft fournit un consensus pour les transactions. L’API TiKV fournit une
interface pour interagir avec les clients et le coprocesseur gère les requêtes qui ressemblent
à du SQL et assemble le résultat du stockage sous-jacent.
2. Nous devrons explorer l’opérateur Helm. Tout d’abord, ajoutez le référentiel PingCap :
$ helm repo add pingcap https://charts.pingcap.org/
4. Installez l’opérateur :
$ helm install --namespace tikv-operator tikv-operator pingcap/tikv-operator \
--version v0.1.0
5. Déployez le cluster :
$ kubectl apply -f https://raw.githubusercontent.com/tikv/tikv-operator/master/ \
examples/basic/tikv-cluster.yaml
Cela va créer un cluster de stockage à hôte unique avec 1 Go de stockage et une instance de
pilote de placement (DP).
Vous pouvez modifier les paramètres de réplicas et de stockage dans la définition de
cluster afin de répondre à vos besoins. Nous vous conseillons d’exécuter votre stockage avec
au moins trois réplicas à des fins de redondance. Par exemple, si vous exécutez kubectl
edit ikv.org TikvCluster et que vous modifiez les réplicas en les définissant sur 4 et
Si vous utilisez etcd pour votre infrastructure de base, vous comprendrez rapidement
l’importance de l’exécution fiable de cette infrastructure. Étant donné qu’un cluster etcd
est un élément essentiel de votre infrastructure, nous vous recommandons les éléments
suivants pour garantir la stabilité d’un cluster etcd dans Azure.
Ces références vous permettent explicitement d’associer des SSD premium ou ultra, ce qui
permettra d’augmenter les performances du cluster.
Cela désactivera le HPA (Horizontal Pod Autoscaler), qui est utilisé dans Kubernetes pour
dimensionner automatiquement les clusters. Vous trouverez plus d’informations sur le HPA
dans la documentation sur Kubernetes.
Disponibilité et sécurité
etcd est un service de plan de contrôle, c’est pourquoi il est important qu’il soit hautement
disponible et que les communications soient sécurisées. Nous vous conseillons d’exécuter
au moins trois nœuds etcd dans un cluster pour garantir la disponibilité du cluster. Le débit
du cluster dépendra des performances du stockage. Nous vous recommandons vivement de
ne pas utiliser de mécanismes de découverte statique pour vos nœuds de cluster et d’utiliser
plutôt des enregistrements SRV DNS, comme conseillé dans le Guide de clustering etcd.
TLS etcd
etcd prend en charge le chiffrement TLS (Transport Layer Security) client-serveur et d’égal à
égal (serveur-serveur). Nous vous conseillons vivement de l’activer, car etcd est un système
de plan de contrôle. Nous n’allons pas entrer dans les détails de la mise en œuvre ici (car
ils dépendent grandement de votre infrastructure). Vous pouvez trouver des options de
configuration dans la documentation sur la sécurité d’etcd.
Résumé
Malgré les idées fausses courantes, il est possible d’exécuter des systèmes de données à
grande échelle en mode natif dans Azure. Dans ce chapitre, nous avons passé en revue
les raisons pour lesquelles il est avantageux d’utiliser des systèmes de données natifs du
cloud dans le cloud d’Azure. Nous avons abordé quatre systèmes : Vitess (relationnel), Rook
Résumé 231
(blob), TiKV (clé-valeur) et etcd (configuration de clé-valeur/découverte de services).
Ces systèmes sont le socle d’une architecture native du cloud qui stocke et sert les données en
ligne. De plus, ils offrent un large important par rapport à l’utilisation de composants PaaS.
Vous devriez maintenant savoir quel logiciel gérer, ainsi que quels services PaaS utiliser et
comment les déployer dans votre infrastructure.
Le cloud, et en particulier Kubernetes, est devenu un endroit beaucoup plus convivial pour
exécuter votre infrastructure avec état. Bien que les comptes de stockage Azure Gen2 soient
une excellente ressource pour le stockage blob, les logiciels natifs du cloud peuvent vraiment
vous aider à créer une infrastructure à grande échelle et de longue durée.
Maintenant que vous comprenez comment il est possible de stocker et de servir des données
dans un environnement cloud, examinons comment déplacer des données entre les systèmes
à l’aide de la messagerie en temps réel.
Dans ce chapitre, nous allons discuter des avantages de la messagerie dans les architectures
natives du cloud et fournir un bref historique des modèles de messagerie afin que vous
puissiez comprendre leur origine et l’évolution de la communication interprocessus vers les
systèmes distribués natifs du cloud.
À la fin de ce chapitre, vous serez en mesure de déployer les implémentations de messagerie
les plus courantes utilisées dans les applications et les microservices natifs du cloud dès
aujourd’hui. Nous comparerons les fonctionnalités de solutions de messagerie matures
telles que RabbitMQ et Kafka qui sont en production depuis des années, et nous mettrons
en œuvre des modèles de messagerie courants dans NATS. Étant donné que ce livre se
concentre sur Azure, vous serez en mesure de gérer les offres de messagerie Azure à l’aide
de Terraform. Nous fournirons également de petits exemples de code en Python montrant à
quel point il est facile de produire et de consommer des messages et de valider le déploiement
approprié de l’infrastructure de messagerie pour Azure et NATS.
233
s’appuie sur un intermédiaire (appelé courtier) se trouvant entre l’expéditeur et le récepteur
qui ne suit généralement pas le paradigme de requête-réponse afin que la communication
devienne asynchrone. Nous verrons pourquoi c’est important sous peu.
À mesure que le cloud se développait dans les années 2010, l’utilisation des services de
messagerie gérés, tels que les serveurs Amazon SQS et RabbitMQ fonctionnant sur des
machines virtuelles, a joué un rôle dans l’amélioration de la fiabilité et de l’évolutivité des
sites web. Vers le milieu des années 2010, Kafka est devenu une solution populaire pour les
cas d’utilisation de messagerie, y compris l’agrégation de journaux, l’analyse du flux de clics
et les pipelines de données. NATS est une autre implémentation de messagerie légère et avec
des performances élevées qui est devenue populaire pour les cas d’utilisation de l’analyse de
périphérie et l’Internet des objets (IoT), en raison de sa capacité à s’adapter à des appareils
de plus petite taille et à sa facilité d’exécution.
Les modèles de files d’attente et de messagerie publication/abonnement ont fait partie des
premiers services gérés offerts par les fournisseurs de cloud et Azure dispose de plusieurs
services de messagerie, y compris Azure Event Grid, Azure Event Hubs et Azure Service Bus,
qui fournissent des protocoles et des implémentations basés sur des normes compatibles avec
Java, .NET, Python et d’autres kits SDK. Ces services permettent la migration des charges de
travail existantes et/ou le développement de nouvelles applications natives du cloud.
Avant de plonger plus profondément dans l’histoire de la messagerie, voici les raisons
pour lesquelles et les moments où vous devrez implémenter la messagerie dans votre
infrastructure ou en vue de son utilisation par des applications :
Améliorez les performances et le débit
L’utilisation de modèles de messagerie (qu’il s’agisse de files d’attente simples ou
de modèles de publication/abonnement plus complexes) permet une évolutivité
horizontale et une mise en parallèle des charges de travail. La mise à l’échelle des
producteurs, des consommateurs et des courtiers en fonction de la charge est possible
grâce aux approches de mise à l’échelle automatique des machines virtuelles, telles que
les ensembles de machines virtuelles Azure, via Kubernetes ou le service cloud.
Renforce la résilience
La capacité d’avoir plusieurs expéditeurs (producteurs) et récepteurs (consommateurs)
qui échangent des messages offre une meilleure résilience. En outre, le fait que les
messages puissent s’accumuler dans une file d’attente (les expéditeurs continuent à
envoyer des messages) lors les clients n’effectuent pas le traitement garantit que les
messages ne sont pas perdus et que vous pouvez effectuer une maintenance sur vos
agents de travail. Selon le modèle de mise en file d’attente, le système peut survivre
aux défaillances de connectivité entre les composants, ainsi qu’aux échecs d’application
dans les producteurs ou les consommateurs.
Exemple de cas d’utilisation de messagerie : ingestion des journaux et analyse de données 235
Figure 10.1. Génération 1, sans files d’attente
Figure 10.3. Génération 3, avec une architecture de microservices et des files d’attente mises
à l’échelle horizontalement
L’adoption de systèmes de messagerie peut être un élément clé pour contribuer à l’évolution
d’un produit. Dans l’exemple précédent, le système de messagerie a été utilisé pour le
traitement des événements de mise à l’échelle. Cependant, les systèmes de messagerie
peuvent être utilisés à d’autres fins, telles que le transport d’analyses, de journaux ou de
toute autre donnée formatée qui n’a pas besoin d’être traitée en temps réel.
Exemple de cas d’utilisation de messagerie : ingestion des journaux et analyse de données 237
Les bases des plateformes de messagerie
Le besoin en composants logiciels (qu’il s’agisse d’applications client ou serveur, ou de
programmes individuels exécutés sur un seul ordinateur) est antérieur au cloud et même
à Internet. Tous les systèmes d’exploitation, sauf les systèmes intégrés les plus primitifs qui
sont à usage général, offrent aux programmes la capacité d’envoyer des données à d’autres
programmes et d’en recevoir de ces derniers.
Producteurs et consommateurs
Comme lorsque vous communiquez avec un autre être humain, un message a toujours un
expéditeur et un destinataire, mais il peut être envoyé directement ou non, et vous pouvez
obtenir une réponse ou non. Lorsque vous envoyez un e-mail, il y a plusieurs intermédiaires
(voir la figure 10.5). Ces parties incluent votre client de messagerie électronique, les serveurs
de votre fournisseur de messagerie électronique (agents de transfert de messages [MTA],
qui jouent un rôle de courtier), le serveur du destinataire (un autre MTA) et un client
de messagerie électronique de réception. Dans cet exemple, il y a un certain nombre de
consommateurs et de producteurs ; le client de messagerie électronique met en file d’attente
les messages à envoyer/produire à/pour les serveurs de messagerie du fournisseur de
services Internet, et l’agent de transfert de messages met ensuite en file d’attente les messages
envoyés, puis il les envoie/produit à/pour l’agent de transfert de messages du destinataire.
Le client de messagerie électronique du destinataire recevra et consommera ensuite les
messages de l’agent de transfert de messages de son fournisseur de services Internet.
Courtiers et clustering
Dans notre exemple d’e-mail précédent, les composants intermédiaires, les agents de
transfert de messages, agissent en tant que courtiers entre l’expéditeur et le destinataire.
Dans de nombreux cas, le logiciel d’agents de transfert de messages peut être mis en cluster.
Un ou plusieurs courtiers dans un cluster permettent aux expéditeurs et aux destinataires
d’être découplés les uns des autres. RabbitMQ, Kafka et NATS, les mises en œuvre de
messagerie abordées dans ce chapitre, nécessitent au moins un courtier, et suivant le principe
de la plupart des protocoles de système distribués, ces plateformes requièrent souvent un
minimum de trois courtiers et doivent généralement comporter un nombre impair d’entre
eux (pour les algorithmes de cohérence). Les considérations relatives au clustering incluent
la réplication d’état, l’élection de responsable, le comportement d’appartenance au nœud et
le partitionnement de cluster en cas de défaillance du réseau (ainsi que le problème tant
redouté de déconnexion cérébrale).
En ce qui concerne les clusters (qui peuvent rapidement devenir un goulot d’étranglement),
vous devez également tenir compte de la façon dont ils peuvent être mis à l’échelle sans
temps d’arrêt. La surcharge opérationnelle de la maintenance des clusters de messagerie à
haut débit et à faible latence est la raison pour laquelle les équipes désignent le fournisseur
de services cloud pour gérer l’infrastructure afin que les développeurs puissent se
concentrer sur le développement et l’optimisation des applications des producteurs et des
consommateurs.
Distribution de message
Outre la source et de la destination, il existe trois modèles importants que vous devez
connaître au sujet des plateformes axées sur les messages, comme nous allons le voir dans
ce chapitre :
Au moins une fois
Implique qu’il pourrait y avoir des doublons ; en particulier, si un consommateur est
tombé en panne et n’a pas avisé le courtier que le message avait été reçu, ou qu’un
message pouvait être distribué à plusieurs consommateurs
Une fois au maximum
Suppose qu’un message peut être envoyé, mais ne pas être réellement reçu ou reconnu
par un consommateur, ce qui implique une nouvelle distribution dont le client est
responsable
Une seule fois
Une situation très limitée dans laquelle les transactions sont nécessaires et les messages
doivent être distribués une seule fois
L’architecture de messagerie peut prendre en charge un ou plusieurs de ces modèles. Ceux-
ci peuvent peut-être être configurables par le courtier lui-même ou dans les bibliothèques
client des consommateurs et des producteurs.
Publication et abonnement
Comme illustré à la figure 10.6, un producteur (P) envoie des messages et tous les
consommateurs qui écoutent (abonnés) (C) les reçoivent. Il peut y avoir ou non un accusé
de réception, mais si les consommateurs ne sont pas en ligne, ils manqueront le message.
Jusqu’à présent, nous avons couvert beaucoup de théories sur les bases de la messagerie et
de l’architecture. Nous allons maintenant explorer les différentes plateformes de messagerie
natives du cloud.
RabbitMQ
Bien que RabbitMQ ait plus de 15 ans et soit évidemment antérieur à l’adoption publique
généralisée du cloud et des microservices, il s’agit d’un système de messagerie éprouvé qui a
optimisé des charges de travail critiques et qui continue d’être pertinent dans le monde des
conteneurs et des clusters Kubernetes. L’une des raisons en est que RabbitMQ a été développé
dans Erlang/OTP, un langage de programmation fonctionnel conçu pour l’évolutivité, la
concurrence et la fiabilité. Il est donc idéal pour le développement de systèmes distribués
qui traitent des millions à des centaines de millions de messages par jour avec des temps
d’arrêt très faibles.
Apache Kafka
En 2010, les ingénieurs de LinkedIn ont constaté que RabbitMQ ne pouvait pas s’adapter
à la nature complexe et à la taille de leur écosystème. Kafka a été créé pour permettre à la
messagerie de devenir le cœur de la pile technologique de LinkedIn et a réussi à évoluer
jusqu’à atteindre des billions de messages par jour sur le site.
Plus loin dans ce chapitre, nous parlerons d’Azure Event Hubs, un service compatible avec
Apache Kafka et permettant aux applications de simplement mettre à jour la chaîne de con-
nexion du consommateur et du producteur, mais qui peut ne pas rendre toutes les fonction-
nalités de Kafka disponibles. Managed Kafka fait également partie de HDInsight, une large
suite de services d’analyse dans le cloud sur Azure. HDInsight dépasse la portée de ce livre.
Une vue d’ensemble des plateformes de messagerie populaires natives du cloud 243
CNCF CloudEvents
CloudEvents a été lancé pour la première fois en 2017 au sein du groupe de travail sans serveur
CNCF. Selon les propres mots de CNCF : « CloudEvents est une spécification pour décrire
les données d’événement dans des formats courants afin d’assurer l’interopérabilité entre les
services, les plateformes et les systèmes. » Bien que ce projet ait un grand potentiel (et soit
pris en charge par Azure Event Grids), nous ne le couvrirons pas plus en détail dans ce livre.
Étant donné que l’architecture de base est la publication et l’abonnement, les producteurs
de NATS sont des éditeurs et ses consommateurs sont des abonnés. NATS JetStream utilise
l’abstraction interne des consommateurs.
L’échange le plus simple possible entre un éditeur et un abonné utilisant l’interface de ligne
de commande de NATS est la meilleure façon de voir à quel point le protocole est simple.
Examinons un exemple. Dans le code suivant, un producteur envoie le message : « arf »,
avec comme objet : dog.food:
$ echo "arf" | nats pub dog.food
16:10:43 Reading payload from STDIN
16:10:43 Published 4 bytes to "dog.food"
Dans le code suivant, un consommateur s’abonne au service pour tous les messages qui
commencent par « dog. » :
$ nats sub dog.*
16:09:49 Subscribing on dog.*
[#1] Received on "dog.food"
En supposant que nous ayons deux serveurs Linux différents sur 192.168.2.238
et 192.168.2.247, nous pouvons configurer une cluster avec les commandes suivantes :
nats-server -DV -cluster nats://192.168.2.238:4248
nats-server -DV -cluster nats://192.168.2.247:4248 -routes nats://192.168.2.238:4248
Nous pouvons passer les arguments complets de la ligne de commande. Dans ce cas, nous
précisons un volume à monter dans notre répertoire ~/tmp à utiliser pour la persistance
JetStream.
Vous pouvez utiliser un outil tel que Telegraf pour extraire ces points de terminaison HTTP
et les envoyer à un back-end de métrique en amont ou à l’exportateur Prometheus.
Sécurité NATS
Un chapitre entier pourrait facilement être écrit sur la configuration de l’éventail des
capacités d’authentification, d’autorisation et de chiffrage de NATS 2.3.x. Dans cette section,
nous couvrirons les étapes de base nécessaires pour élever le niveau en ce qui concerne les
valeurs par défaut non sécurisées que nous avons utilisées dans la plupart de nos exemples
jusqu’à présent, mais qui sont inappropriées pour les déploiements de production. Une
solide infrastructure de gestion des identités et des secrets est le fondement des systèmes
cloud sécurisés, mais cela dépasse la portée de ce livre. NATS fournit un sous-système
d’autorisations robuste qui permet de définir le contrôle granulaire sur une base thématique
et utilise des magasins d’identités distribués.
La clé publique (qui commence par un « U ») est configurée sur le serveur :
$ cat server.conf
net: 0.0.0.0
port: 4242
authorization {
users: [
{ nkey: UBFHQJERKEBE323BXQEVT6257CIRJ4CIC5LGT6R2LJ524GQTUQHXCUK3 }
]
}
La clé privée (ou « seed », ce qui explique le préfixe « S ») est stockée sur le disque et trans-
mise en tant qu’argument au client NATS ou en tant que variable dans le code. Comme
pour toute donnée, il est préférable que ces clés soient stockées dans un magasin de secrets
externe tel qu’Azure Key Vault ou en tant que secret Kubernetes :
$ cat client.nkey
SUAGWCAMMXKR43EDIXVC5FEA5G3767ALGQR75N27NGPK37KZUURS7F32FE
Authentification TLS
Bien que nous disposions d’une authentification sécurisée (et éventuellement d’une autori-
sation, selon la façon dont nous avons configuré les autorisations d’objet), l’utilisation de
Nkey seule n’est pas adéquate pour la sécurité du réseau, car NATS est, par défaut, un pro-
tocole de texte brut ASCII.
Comme la plupart des protocoles natifs du cloud, NATS prend en charge le chiffrement TLS
mutuel. En général, le plus grand défi avec TLS est la gestion des certificats et des clés, ce qui
dépasse la portée de ce livre. À des fins de démonstration, mkcert fournit un chemin plus
facile qu’OpenSSL pour générer les paires de clés d’autorité de certification (CA), de client
et de serveur nécessaires pour le chiffrement de bout en bout.
# Create the CA
$ mkcert -install
Ensuite, nous démarrons le serveur (dans le répertoire ~/nats) et nous ajoutons les
paramètres de certificat TLS :
$ nats-server -DV --tls --tlscert=server-cert.pem --tlskey=server-key.pem -ms 8222
5. Vous
pourrez afficher Grafana dans votre navigateur à l’adresse http://127.0.0.1:3000/d/
nats/nats-surveyor?refresh=5s&orgId=1.
Votre déploiement d’aide offre un certain nombre de configurables Helm. Vous pouvez en
savoir plus à ce sujet sur la page de configuration du déploiement de NATS Helm.
Vous pouvez coder sur NATS d’une manière très simple en Python, en utilisant le paquet
nats-py. Dans l’exemple suivant, vous codez un producteur et un consommateur de base
en Python. NATS fournit un serveur public dans lequel vous pouvez effectuer des tests. Si
vous souhaitez effectuer des tests dans votre propre environnement, remplacez nc = await
nats.connect (« nats://demo.nats.io:4222 ») par l’adresse de votre instance NATS :
import time
import asyncio
import nats
from nats.aio.errors import ErrConnectionClosed, ErrTimeout, ErrNoServers
time.sleep(5)
# Remove interest in subscription
await sub.unsubscribe()
if __name__ == '__main__':
loop = asyncio.get_event_loop()
loop.run_until_complete(run())
loop.close()
• Compatibilité avec les plateformes et les protocoles filaires de messagerie sur site
(ActiveMQ, RabbitMQ), ainsi que les outils
• Niveau d’intégration requis avec d’autres services gérés Azure
• Besoin en messagerie et transactions ordonnées
• Capacité à gérer le streaming d’événements
• Utilisation de pipelines de big data
• Taux d’ingestion maximal (événements par seconde)
• Modèles d’événements asynchrones disponibles
• Tarification
L’un des principaux avantages de l’utilisation des services de messagerie Azure est la
possibilité de tirer parti de la gestion des capacités et des secrets avec les solutions de gestion
des identités et des accès d’Azure. Examinons maintenant en détail les offres Azure.
Concepts de Service Bus
Les abstractions Azure Service Bus (voir les figures 10.11 et 10.12 pour les architectures de
référence) fournissent des fonctionnalités similaires à celles disponibles dans NATS.
Espaces de noms. Les espaces de noms permettent la segmentation des rubriques, des files
d’attente et des services en tant que conteneur pour les composants de messagerie, de la
même manière qu’un réseau virtuel sert une limite pour les composants réseau tels que
les machines virtuelles et les équilibreurs de charge. Kafka ne fournit pas une abstraction
comparable, mais les hôtes virtuels RabbitMQ et les comptes NATS le font.
tags = {
source = "terraform"
}
}
En utilisant azure-cli, nous pouvons voir les ressources qui ont été créées :
$ az servicebus queue list --namespace-name mdfranz-servicebus-namespace -g \
terraform-servicebus
[
{
"accessedAt": "0001-01-01T00:00:00+00:00",
"autoDeleteOnIdle": "10675199 days, 2:48:05.477581",
"countDetails": {
"activeMessageCount": 0,
Nous pouvons également voir les ressources dans la console Azure, comme le montre
la figure 10.13.
Nous pouvons également voir les métriques globales dans les espaces de noms et cliquer sur
une file d’attente précise qui fournit plus de détails sur le stockage et la taille des messages
(voir la figure 10.14).
Azure fournit des bibliothèques à code source libre pour envoyer et recevoir des messages
au service Azure dans tous les langages de programmation populaires. L’exemple suivant
crée un producteur et un consommateur simple en Python :
import os
connstr = os.environ['SERVICE_BUS_CONN_STR']
queue_name = os.environ['SERVICE_BUS_QUEUE_NAME']
print(s,r)
for m in messages:
s.send_messages(ServiceBusMessage(m))
while True:
print(r.receive_messages(max_message_count=1,max_wait_time=10))
Outre RabbitMQ, les lecteurs qui connaissent déjà AWS SNS et SQS trouveront que
Service Bus est simple et capable de répondre à des cas d’utilisation similaires.
Azure Event Hubs
Azure Event Hubs est conçu pour fournir certaines des fonctionnalités d’Apache Kafka afin
de répondre aux cas d’utilisation pour le partitionnement et les groupes de consommateurs,
mais dans un service cloud géré (voir la figure 10.15). Bien que vous perdiez la visibilité
sur l’infrastructure principale que vous auriez lors de l’exécution de Kafka sur des
machines virtuelles ou Kubernetes, vous obtenez une intégration plus étroite avec des
services de données supplémentaires tels que le stockage de grands objets binaires Azure,
Azure Data Lakes et Azure Stream Analytics, pour n’en nommer que quelques-uns. Azure
prend également en charge les protocoles AMQP 1.0 et Kafka 1.0 afin de préserver la
compatibilité avec les bibliothèques clientes.
Azure Event Hubs a quelques concepts transférés d’Azure Service Bus. Nous allons
rapidement les passer en revue ici :
Producteurs
Ce sont les clients qui envoient des messages à Azure Event Hubs.
Partitions
Les messages sont répartis entre les partitions pour permettre le stockage des réplicas
du message.
Groupe de clients
Ce sont des clients qui travaillent à l’unisson pour consommer des messages produits
de manière coordonnée.
Comme c’était le cas avec Azure Event Bus, il existe plusieurs façons de s’authentifier auprès
des points de terminaison Event Hubs. Le moyen le plus simple consiste à utiliser une
chaîne de connexion, comme illustré à l’exemple suivant :
$ az eventhubs namespace authorization-rule keys list --resource-group mdfranz-eventbus- \
group --namespace-name mdfranz-eventhub-namespace --name RootManageSharedAccessKey
{
"aliasPrimaryConnectionString": null,
"aliasSecondaryConnectionString": null,
"keyName": "RootManageSharedAccessKey",
"primaryConnectionString": "Endpoint=sb://mdfranz-eventhub-namespace.servicebus.windows. \
net/;SharedAccessKeyName=RootManageSharedAccessKey; \
SharedAccessKey=jfMUbfQZX8UJglcCKLAeIp5CZVLcwcSGpuKdJX/CMzk=",
"primaryKey": "jfMUbfQZX8UJglcCKLAeIp5CZVLcwcSGpuKdJX/CMzk=",
"secondaryConnectionString": "Endpoint=sb://mdfranz-eventhub-namespace.servicebus. \
windows.net/;SharedAccessKeyName=RootManageSharedAccessKey; \
SharedAccessKey=gFy7SuuGjw12GfoHXd6UQeZdy5Y0xu/gStZtQUhaxsY=",
"secondaryKey": "gFy7SuuGjw12GfoHXd6UQeZdy5Y0xu/gStZtQUhaxsY="
}
Azure Event Grid utilise une terminologie qui diffère légèrement des autres plateformes
dont nous avons discuté :
Domaines
Les domaines sont analogues aux espaces de noms, ce qui sépare les cas d’utilisation
dans le locataire.
Rubriques
Pour Event Grid, il existe deux types de rubriques : les rubriques système, qui
proviennent des systèmes Azure (Event Hubs, stockage de grands objets binaires, etc.),
comme illustré à gauche à la figure 10.16, et les rubriques personnalisées, qui peuvent
être votre propre schéma personnalisé encapsulé dans le schéma Event Grid.
tags = {
environment = "Production"
}
}
Veillez à modifier le nom de la rubrique, car elle est globalement unique dans l’ensemble
de la région Azure dans laquelle vous effectuez le déploiement. Une fois ce déploiement
Terraform appliqué, une nouvelle rubrique Event Grid sera créée avec le nom https://<event-
grid-topicname>.<topic-location>.eventgrid.azure.net/api/events; ou, dans notre cas, https://
myeventgrid-topic.east-us.eventgrid.azure.net/api/events. Vous pourrez trouver la clé d’accès
pour la rubrique en exécutant az eventgrid topic key list --resourcegroup
example-resources --name my-eventgrid-topic.
event = EventGridEvent(
data={"team": "azure-sdk"},
subject="Door1",
event_type="Azure.Sdk.Demo",
data_version="2.0"
)
credential = DefaultAzureCredential("<access-key>")
endpoint = `https://my-eventgrid-topic.east-us.eventgrid.azure.net/api/events"
client = EventGridPublisherClient(endpoint, credential)
client.send(event)
Un certain nombre d’exemples intéressants sur la façon de coder avec Event Grid sont
disponibles dans la bibliothèque cliente Azure Event Grid pour Python.
Résumé 263
CHAPITRE 11
Sans serveur
Jusqu’à présent, nous nous sommes largement concentrés sur les concepts sur site, ainsi
que sur la discussion et la mise en œuvre de leurs équivalents basés sur le cloud. Dans ce
chapitre, nous approfondirons un nouveau type d’architecture informatique connu sous le
nom de « sans serveur » et qui est profondément lié au cloud computing. Plus précisément,
nous examinerons les plateformes sans serveur courantes, notamment les applications de
fonctions Azure, Knative, KEDA et OpenFaaS.
265
Le paysage de l’informatique sans serveur, comme mentionné précédemment, est un espace
raisonnablement nouveau qui a innové rapidement. Outre les grands fournisseurs de
services cloud qui proposent une plateforme de fonction, d’autres sociétés Internet comme
Cloudflare, Netlify et Twilio fournissent également des fonctionnalités sans serveur.
L’exemple précédent crée un écouteur d’événement pour événement de type « extraction » (qui
est un HTTP GET), et lorsque cet événement est déclenché, la fonction handleRequest
est appelée. La fonction analyse un en-tête de requête HTTP, CF-Connecting-IP, c’est-
à-dire l’IP qui fait la demande à la fonction sans serveur. La fonction répond alors avec
l’adresse IP à l’origine de la demande.
Nous ne le couvrirons pas en détail dans ce livre mais, au-delà des cadres et des fournisseurs
de services cloud principaux qui proposent des offres sans serveur, les fournisseurs de
réseau de périphérie (ou CDN) offrent également une fonctionnalité sans serveur ou de
« calcul en périphérie ». Cette fonctionnalité est devenue extrêmement populaire dans des
entreprises comme Cloudflare.
1. Nous allons commencer par ouvrir le portail Azure et cliquer sur Créer sous Application
de fonction.
2. Nous allons maintenant remplir les paramètres de base de l’application de fonction :
a. Nous allons créer un nouveau groupe de ressources appelé serverless-test.
b. Le nom DNS de notre application sera ourtestfunctionapp.azureweb sites.
net.
c. Nous exécuterons du code (une fonction) au lieu d’un conteneur.
d. Le langage sera Python v3.9.
e. L’application de fonction sera déployée dans la région Est des États-Unis.
3. Dans l’onglet Hébergement :
a. Nous allons créer un nouveau compte de stockage appelé functionstorageaccount.
Comme les noms de compte de stockage sont uniques au niveau mondial, vous
devrez choisir votre propre nom.
b. Dans la mesure où nous exécutons Python, nous devons exécuter Linux.
c. 19 ptEnfin, nous utiliserons le plan de consommation dans le cadre de cet exemple.
4. Dans l’onglet Surveillance :
a. Nous désactiverons Application Insights.
b. Nous cliquerons ensuite sur Examiner + Créer.
Maintenant que nous avons créé notre application de fonction, nous devons créer une
fonction. Visual Studio Code a une extension, Azure Functions, qui simplifie la création, le
test et la publication d’une fonction :
1. Si vous n’avez pas installé Visual Studio Code, vous pouvez le télécharger à partir de la
page de téléchargement de Visual Studio Code.
2. Une fois que vous aurez installé Visual Studio Code, vous devrez installer l’extension
Azure Functions.
3. Cliquez sur l’icône Azure dans la barre d’activité sur le côté gauche de l’écran, ce qui
affichera la fenêtre Azure Functions. Cliquez sur Créer un nouveau projet.
4. Une boîte de dialogue apparaîtra dans laquelle vous devrez choisir un répertoire local
dans lequel enregistrer votre code.
7.
Testez votre fonction en appuyant sur F5 sur votre clavier, puis en accédant
à http:// localhost:7071/api/HttpExample.
8. Pour déployer sur Azure, vous devrez cliquer sur le bouton Se connecter à Azure dans
la fenêtre Azure Functions.
9. Cliquez sur le bouton Télécharger, qui vous permettra de télécharger votre fonction sur
l’application que vous avez créée précédemment.
Maintenant que nous avons examiné les offres natives d’Azure, discutons des applications
de fonction déployées avec Kubernetes.
Architecture de Knative
Knative a deux modes de fonctionnement :
• Knative Serving utilise Kubernetes pour déployer des fonctions ou des conteneurs sans
serveur et a une prise en charge complète de la mise à l’échelle automatique (y compris
jusqu’à zéro Pods). Il a également l’avantage de prendre en charge les solutions de mise
en réseau du cloud comme Gloo et Istio.
• Knative Eventing permet aux développeurs de développer des applications qui
reposent sur une architecture orientée événements. Dans le cadre d’un déploiement
d’événements, vous pouvez préciser les producteurs d’événements (sources) auxquelles
il est nécessaire de répondre.
Si vous souhaitez utiliser l’une des intégrations réseau (Kourier, Ambassador, Contour,
Istio), vous pouvez suivre les instructions de la couche réseau.
3. Vous devez maintenant créer votre application. Nous utiliserons la bibliothèque Flask
de Python pour créer une application simple :
Import logging
import os
app = Flask(__name__)
Log =
@app.route('/', methods=['POST'])
def hello_world():
return f'Hello world. Data {request.data}\n'
4. Vous avez maintenant besoin d’une image Docker contenant votre application sans
serveur :
FROM python:3.7-slim
WORKDIR /app
COPY . .
6. Maintenant, définissez votre service sans serveur dans un fichier appelé hello-world.yaml :
apiVersion: serving.knative.dev/v1
kind: Service
metadata:
name: helloworld
namespace: default
spec:
template:
metadata:
name: helloworld
spec:
containers:
- image: docker.io/test/helloworld:v1
8. À ce stade, votre fonction sans serveur sera déployée. Vous pourrez trouver l’URL de la
fonction en exécutant :
$ kubectl get ksvc hello-world --output=custom-columns=NAME:.metadata.name, \
URL:.status.url
Knative 273
Installation et exécution de Knative Eventing sur Kubernetes
Dans cette section, nous allons installer les composants de Knative Eventing et écrire un
système d’événements simple :
À ce stade, les composants d’événements seront installés. Nous allons réutiliser notre
image Docker de la section précédente. Cependant, nous allons configurer Knative
afin de pouvoir envoyer un message HTTP à un bus de messages dans Knative au
lieu de publier sur un serveur d’applications HTTP. Lorsque le message atteint le bus
de messages, il déclenche notre serveur d’applications Python. Dans un exemple plus
compliqué, vous pouvez définir une rubrique Kafka comme source d’événements.
3. Créez un fichier knative-eventing.yaml :
# Namespace for sample application with eventing enabled
apiVersion: v1
kind: Namespace
metadata:
name: knative-samples
labels:
eventing.knative.dev/injection: enabled
---
# A default broker
apiVersion: eventing.knative.dev/v1
kind: Broker
metadata:
name: default
namespace: knative-samples
annotations:
# Note: you can set the eventing.knative.dev/broker.class annotation to change
# the class of the broker.
# The default broker class is MTChannelBasedBroker, but Knative also supports
# use of the other class.
eventing.knative.dev/broker.class: MTChannelBasedBroker
spec: {}
---
# hello-world app deployment
apiVersion: apps/v1
kind: Deployment
metadata:
name: hello-world
namespace: knative-samples
spec:
replicas: 1
selector:
matchLabels: &labels
app: hello-world
Knative 275
id: 536808d3-88be-4077-9d7a-6a3f162705f79
time: 2021-11-09T06:21:26.09471798Z
datacontenttype: application/json
Extensions,
Knativearrivaltime: 2021-11-09T06:21:26Z
knativehistory: default-kn2-trigger-kn-channel.knative-samples.svc.cluster.local
traceparent: 00-971d4644229653483d38c46e92a959c7-92c66312e4bb39be-00
KEDA
KEDA signifie Kubernetes Event-Driven Autoscaling (Mise à l’échelle pilotée par les
événements Kubernetes). KEDA vous permet de mettre à l’échelle n’importe quel conteneur
dans Kubernetes en fonction du nombre d’événements entrants. KEDA est un module
complémentaire de Kubernetes et il utilise l’Horizontal Pod Autoscaler (HPA) pour mettre
à l’échelle en fonction de différentes sources d’événements, y compris Apache Kafka,
Azure Event Hubs et le streaming NATS.
Architecture KEDA
Une architecture KEDA type est représentée à la figure 11.3, où KEDA interagit directement
avec le serveur API Kubernetes, HPA et la source du déclencheur configurée.
Le composant KEDA remplit les rôles suivants :
Contrôleur et dimensionneur
Le contrôleur et le dimensionneur augmenteront ou diminueront le nombre de Pods
en fonction du signal de l’adaptateur de métriques.
Adaptateur de métriques
L’adaptateur de métriques agit comme un serveur de métriques Kubernetes qui
fournit des informations de longueur de file d’attente ou de décalage de flux à l’agent.
Le dimensionneur utilise ces informations pour faire augmenter ou diminuer les
conteneurs.
Vous pouvez voir tous les dimensionneurs KEDA dans la documentation sur les
dimensionneurs.
Après cela, votre cluster Kubernetes sera prêt pour le déploiement de fonctions.
Dans l’exemple suivant, nous allons créer un système d’événements de démonstration de
faisabilité avec une file d’attente Azure Service Bus. Nous allons produire des messages
vers la file d’attente Azure Service Bus à l’aide d’un script Python, puis utiliser KEDA pour
mettre à l’échelle un travail de consommation Python :
KEDA 277
2. Vous devrez obtenir les valeurs codées en Base64 de la chaîne de connexion et le nom
de la file d’attente en exécutant :
$ echo -n "<connection string>" | base64
$ echo -n "<queue name>" | base64
4. Créez un deuxième fichier, appelé keda.yaml, qui créera votre ScaledJob. Il exécutera
une image Docker (Docker.pkg.github.com/prabdeb/sample-python-keda-
service-bus-scaler/consumer:latest) lorsqu’il sera déclenché :
apiVersion: keda.sh/v1alpha1
kind: TriggerAuthentication
metadata:
name: auth-service-bus-sample-job
spec:
secretTargetRef:
- parameter: connection
name: sample-job-secret
key: servicebus-connectionstring
---
apiVersion: keda.sh/v1alpha1
kind: ScaledJob
metadata:
name: servicebus-queue-so-sample-job
namespace: default
spec:
jobTargetRef:
parallelism: 1 # max number of desired pods
completions: 1 # desired number of successfully finished pods
activeDeadlineSeconds: 600 # Specifies the duration in seconds relative to the
startTime that the job may be active before the system tries to terminate it;
value must be positive integer
backoffLimit: 6 # Specifies the number of retries before marking this job failed.
Defaults to 6
Template:e
metadata:
labels:
app: sample-keda-job
spec:
containers:
- name: sample-keda-job
image: docker.pkg.github.com/prabdeb/sample-python-keda-service-bus-scaler/
consumer:latest
env:
- name: SERVICE_BUS_CONNECTION_STR
7. Vous pouvez tester votre déploiement KEDA en exécutant un script de test. Vous devez
d’abord configurer l’environnement Python :
$ python3 -m venv .
$ source bin/activate
$ pip3 install logger
$ pip3 install azure-servicebus
8. Vous devez maintenant créer votre programme qui envoie des messages à la file d’attente
Azure Service Bus. Vous devrez modifier connection_string et queue_name :
KEDA 279
import os
import sys
import time
import yaml
from logger import logger
from azure.servicebus import ServiceBusClient, ServiceBusMessage
def send_a_list_of_messages(sender):
messages = [ServiceBusMessage(f"Message in list {i}") for i in range(1000)]
sender.send_messages(messages)
logger.info("Sent a list of 1000 messages")
def main():
with open("azure-service-bus.yaml", 'r') as stream:
config = yaml.safe_load(stream)
queue = ServiceBusClient.from_connection_string(conn_str=connection_string, \
queue_name=queue_name)
with queue:
sender = queue.get_queue_sender(queue_name=queue_name)
with sender:
send_a_list_of_messages(sender)
if __name__ == "__main__":
main()
Vous pouvez voir les messages ingérés, puis traités dans la file d’attente Azure Service Bus
(figure 11-4).
OpenFaaS
OpenFaaS est un autre service de fonction axé sur les événements pour Kubernetes qui
vous permet d’écrire des fonctions dans n’importe quel langage, puis de les emballer dans
des conteneurs Docker ou compatibles OCI.
Architecture d’OpenFaaS
L’architecture de référence OpenFaaS (comme illustré à la figure 11-5) est raisonnablement
similaire à Keda. Toutefois, OpenFaaS s’appuie sur des métriques de Prometheus pour agir
comme un signal de mise à l’échelle automatique.
Installation d’OpenFaaS
OpenFaaS dispose de trois méthodes d’installation recommandées :
• Utiliser arkade
• Utiliser helm
• Installer avec Flux ou ArgoCD
Pour être cohérents avec le reste du livre, nous allons déployer OpenFaaS à l’aide de Helm :
1.
Créez les espaces de noms (un premier pour les services de base OpenFaaS
et un deuxième pour les fonctions) :
$ kubectl apply -f https://raw.githubusercontent.com/openfaas/faas-netes/master/ \
namespaces.yml
OpenFaaS 281
3. Enfin, déployez OpenFaaS :
$ helm repo update \
&& helm upgrade openfaas --install openfaas/openfaas \
--namespace openfaas \
--set functionNamespace=openfaas-fn \
--set generateBasicAuth=true
Maintenant que nous avons installé OpenFaaS, nous allons écrire une fonction OpenFaaS.
5. En dernier lieu, dans votre fichier helloworld.yml, vous définirez les métadonnées
relatives à votre fonction. http://127.0.0.1:31112 est l’adresse par défaut du serveur de
passerelle/API OpenFaaS :
provider:
name: openfaas
gateway: http://127.0.0.1:31112
6. Créez l’image sans serveur et poussez-la vers le registre Harbor que vous avez créé
au chapitre 2 :
$ faas-cli build -f ./hello-world.yml
$ faas-cli push -f ./hello-world.yml
8. L’étape précédente génère une URL que vous pouvez utiliser pour les tests. Utilisez curl
pour la tester :
$ curl -X POST 127.0.0.1:31112/function/hello-world -d "My name is Michael"
Hello world! My name is Michael
Par défaut, OpenFaaS utilise les requêtes par seconde (rps) comme mécanisme pour
effectuer la mise à l’échelle automatique. Vous pouvez trouver plus d’informations sur la
configuration de la mise à l’échelle automatique d’OpenFaaS sur la page de documentation
de la mise à l’échelle automatique.
Vous disposerez alors d’une fonction OpenFaaS en cours d’exécution sur Kubernetes. Vous
pouvez également exécuter OpenFaaS en dehors de Kubernetes à l’aide de faasd. Vous
trouverez plus d’informations sur la page de déploiement d’OpenFaaS.
Enfin, OpenFaaS est créé au-dessus de la HPA Kubernetes. Vous trouverez plus
d’informations sur les tests de charge et la mise à l’échelle de votre fonction OpenFaaS sur
la page du tutoriel OpenFaaS Kubernetes.
Résumé
Bien que l’approche sans serveur ne convienne absolument pas à tout le monde, lorsqu’elle
est utilisée dans les bons cas de figure, elle peut offrir des avantages importants. L’espace
sans serveur est toujours en évolution, mais il y a très peu d’obstacles qui entravent son
utilisation, ce qui en fait une technologie passionnante. Dans ce chapitre, nous avons exploré
quatre façons différentes d’exécuter des fonctions sans serveur sur Azure. Tout d’abord,
nous avons examiné les applications de la fonction Azure, puis nous avons vu trois grands
projets CNCF : Knative, KEDA et OpenFaaS. À ce stade, nous avons décrit les principaux
piliers de l’infrastructure native du cloud. Au chapitre 12, nous reverrons rapidement ce que
vous avez appris au cours de cette découverte.
Résumé 283
CHAPITRE 12
Conclusion
Nous sommes arrivés à la fin du livre et nous allons donc passer en revue notre parcours.
Tout au long de ce livre, nous avons cherché à fournir une ressource unique que vous
pouvez utiliser pour créer et exécuter une infrastructure native du cloud dans Azure. Bien
qu’Azure ait été notre priorité, vous pouvez également appliquer ces connaissances pour
créer et exploiter votre propre environnement natif du cloud sur différentes plateformes de
fournisseurs cloud. Passons en revue ce que vous avez appris jusqu’à présent.
Nous avons commencé cet ouvrage en revenant sur la façon dont le monde de l’infrastructure
et des services a évolué au fil du temps grâce à l’introduction du cloud. Pour tirer pleinement
parti de ce que le cloud peut offrir, nous devons mettre au point des solutions natives du
cloud et pas seulement les adapter rétroactivement au cloud. Nous avons vu que le cloud
natif est la solution pour exploiter pleinement la puissance du cloud.
Au chapitre 2, nous avons présenté les tremplins qui permettent de concevoir un
environnement natif du cloud moderne à l’aide d’Azure. Nous avons créé un compte Azure
et nous avons fait nos premiers pas avec Ansible, Terraform et Packer. En les employant
comme outils clés, nous pouvons activer les services prêts pour la production de manière
automatisée. Nous avons utilisé Microsoft Azure comme fournisseur de cloud et, tout au
long du livre, nous avons utilisé à la fois des services natifs du cloud et Azure pour illustrer
la façon dont les infrastructures modernes sont conçues et prises en charge.
Au chapitre 3, nous vous avons présenté le conteneur et le runtime de conteneur, qui
constituent les principes fondamentaux d’un monde natif du cloud moderne. Nous avons
abordé les couches d’abstraction qui composent l’écosystème de conteneurs.
Nous avons ensuite vu le puissant orchestrateur Kubernetes, au chapitre 4 et au chapitre 5,
dans lesquels nous avons mis en évidence la façon dont cet outil important peut être utilisé
dans l’infrastructure cloud moderne afin de faciliter les opérations de la plateforme pour les
applications natives du cloud. Kubernetes a conduit à la création et à l’adaptation de la Cloud
Native Computing Foundation, en devenant le premier projet diplômé. Cela a entraîné
285
beaucoup de simplification du monde de la conteneurisation et une meilleure adaptation
de l’écosystème natif du cloud. Nous avons examiné les différents composants et concepts
qui rendent ce système opérationnel à grande échelle et nous avons appris à créer le cluster
Kubernetes à la fois manuellement et en utilisant Azure AKS en tant que service géré.
À ce stade, nous avons vu les bases d’une infrastructure native du cloud composée du strict
minimum. L’étape suivante a consisté à ajouter une manière d’obtenir des informations sur les
applications et les infrastructures. Donc, au chapitre 6, nous avons introduit le concept des
trois piliers de l’observation, afin de vous permettre de découvrir cette énorme infrastructure
et cette pile d’applications. En créant des systèmes observables, vous disposez d’un contrôle
renforcé sur les systèmes distribués complexes qui interagissent au-delà des limites. Dans ce
chapitre, nous avons également examiné l’observabilité, qui est de plus en plus nécessaire dans
l’environnement natif du cloud. Avec les trois piliers de l’observation et une introduction aux
méthodes préférées de journalisation, de surveillance et de suivi pour les systèmes distribués
modernes sur Azure, nous avons conclu ce chapitre en présentant brièvement la façon dont
Azure propose ses solutions intégrées pour effectuer des tâches similaires avec Azure Monitor.
Lorsque nous parlons de limites et de frontières, nous sommes confrontés au problème de
la communication de service à service dans cet environnement en mutation dynamique.
Pour résoudre ce problème, nous avons présenté la découverte et le maillage des services au
chapitre 7. Ces fonctionnalités permettent de rechercher des services et de communiquer
avec eux efficacement. Nous avons également présenté en détail la nécessité de mettre en
place des maillages de services et des proxies afin de contrôler efficacement l’environnement
global où résident vos microservices. Nous avons abordé CoreDNS comme DNS par défaut,
en remplaçant kube-dns, dans l’environnement Kubernetes. Nous avons vu les maillages
de services à l’aide d’Istio, qui utilise Envoy comme plan de données pour obtenir des
informations utiles sur les services et fournit l’ensemble complet de fonctionnalités du
maillage de services Istio. Vers la fin du chapitre, nous avons présenté Kiali, qui fournit une
console de gestion complète sur un maillage de services basé sur Istio.
Au chapitre 8, nous sommes passés au problème de la gestion des stratégies et de la mise
en réseau dans les environnements natifs du cloud. Nous vous avons présenté deux outils
principaux : Calico et Flannel, qui servent d’interface de réseau de conteneurs. Nous avons
également expliqué comment vous pouvez appliquer des stratégies à l’échelle de la pile à
l’aide de la gestion des stratégies ouverte. Nous avons examiné la norme CNI et la façon
dont elle est le fondement d’autres plateformes telles que Flannel et Cilium. Nous avons
examiné comment ces systèmes peuvent être utilisés pour fournir une connectivité et une
sécurité réseau à votre infrastructure cloud. Nous avons également examiné les mécanismes
de stratégie non-réseau pour la gestion de votre infrastructure cloud via la stratégie Azure,
ainsi que la stratégie pour les applications via l’agent de stratégie ouverte.
Au chapitre 9, nous avons examiné comment le stockage est perçu et conçu dans les
environnements natifs du cloud à l’aide de Vitess en tant que base de données distribuée.
Nous avons également abordé Rook, un orchestrateur de stockage étendu qui peut vous
aider à réduire la charge liée à la gestion d’un système de stockage distribué mettent
notamment en place la mise à l’échelle et la réparation automatiques. Dans ce chapitre,
nous avons examiné pourquoi il est avantageux d’utiliser des systèmes de données
Et ensuite ?
Le paysage CNCF est relativement vaste et il contient un grand nombre de projets qui sont
constamment conçus et soutenus par de nombreuses grandes entreprises (figure 12-1). Ces
projets sont créés à partir de zéro, en tenant compte de l’évolutivité et de la fiabilité.
Figure 12-1. Le paysage CNCF
Et ensuite ? 287
Figure 12-2. Paysage sans serveur de la CNCF
Le paysage sans serveur CNCF met en évidence l’informatique sans serveur et le modèle
de programmation associé, ainsi que les formats de messages. Bien que l’informatique
sans serveur soit largement disponible depuis un certain temps, le développement de cette
approche implique un large éventail de possibilités. Vous pouvez explorer l’informatique
sans serveur si votre charge de travail est asynchrone, sporadique, sans état et hautement
dynamique en termes d’évolution des exigences de l’entreprise. Vous pouvez également
commencer à utiliser différents services Azure et voir comment ils se comportent par
rapport aux technologies CNCF.
La plupart de ces projets sont open source et le résultat des efforts de nombreux ingénieurs
qui contribuent activement à la communauté. L’open source apporte également une grande
quantité de contrôle de la qualité à la conception globale de ces projets. Cela signifie que
les technologies natives du cloud sont bien gérées dans le monde entier et sont facilement
adaptables. Il est également important de noter que la plupart de ces technologies natives
du cloud sont le résultat de problèmes difficiles qui dont dus être résolus efficacement. Par
conséquent, il est tout aussi important de prendre des risques et de poser des questions
difficiles afin d’obtenir une compréhension approfondie de vos systèmes qui finiront par
vous conduire à trouver les bonnes solutions pour résoudre des problèmes complexes.
Le paysage natif du cloud ne cesse de croître et nous vous encourageons à l’explorer encore
davantage afin de l’utiliser pleinement. Nous vous souhaitons bonne chance.
289
options de stockage et de base de données, 220 Azure Storage Explorer, 220
services de messagerie, 234 azure_sd_config, 135
Azure Cloud Shell (voir Cloud Shell) AzureDisk, 84
Azure Container Instances (ACI), 60-64 AzureFile, 83
déploiement, 61-64
mises en garde dans l'exécution, 60
Azure Event Grid, 234, 261-263
B
backend, 15
bibliothèque client pour Python, 262
backends de transport (Flannel), 208
critères lors du choix, 253
balises
déclenchement de fonctions sans serveur, 266
configuration dans l’outil de suivi Jaeger, 156
déploiement et utilisation de grilles
création pour des images Docker, 48
d’événements, 262
banque de données (Calico), 194
écosystème Event Grid, 261
bases de données distribuées, 219-224, 286
terminologie différente des autres plateformes, 261
besoin d’architecture native dans le Cloud, 219
Azure Event Hubs, 234, 258-261
My SQL distribués et partitionné, à l’aide de
architecture, 258
Vitess, 221-224
concepts, 259
options de base de données Azure, 220
critères lors du choix, 253
Bases de données NoSQL
gestion avec Terraform, 259
Cassandra, 224
Kafka et, 243
exploitation des bases de données SQL en tant
Azure Files, 82
que, 221
Azure Function Apps, 268-271
bases de données SQL, exploitation de manière
architecture, 269
NoSQL, 221
création d’une application de fonction, 270
Bash, 18
langages de programmation pris en charge, 268
bibliothèques client
plans, 269
pour le suivi distribué, 153
Azure Functions, création d’une fonction, 270
Prometheus, 126
Azure Key Vault, 250
bin packing, 36, 68
Azure Kubernetes Service (AKS), 286
BIRD (Calico), 194
configuration réseau, y compris Calico, 197
blocs de serveurs dans CoreDNS, 167
contrôleur d’entrées d’Application Gateway, 92
boucle de rapprochement (gestionnaire de
création et gestion d’un cluster Kubernetes, 111
contrôleur Kube), 70
déploiement de Calico via l’installation AKS, 196
exécution de charges de travail statiques sur, 220
installation Cilium sur, 202 C
installation d'Istio sur, 175 Calico, 193-200
prise en charge des plug-ins Azure VNet, 191 architecture de base, 194
Azure Monitor, 159, 286 avantages de l’utilisation, 193
Azure Pipeline, 33 déploiement, 195-197
Azure Service Bus, 234, 253-258 installation de calicoctl, 196
concepts, 254-255 installation manuelle de Calico sur le cluster
espaces de noms, 254 Kubernetes, 196
files d’attente, rubriques et abonnements, 254 mise en œuvre de la stratégie de sécurité, 198-
création d’un système d’événements avec une 200
file d'attente Service Bus utilisation, 197
critères lors du choix, 253 activation du plan de données eBPF, 197
envoi/réception de messages dans la file calicoctl, 194
d’attente activation de eBPF avec, 198
file d'attente, 277-281 Cassandra, 224
gestion avec Terraform, 255-258 déploiement du cluster Cassandra à l’aide de
Python, 258 Rook, 225-226
290 | Index
certificats stockage, 101
création de certificat auto-signé, 180 création des images de machine pour les
génération d’un certificat TLS pour les nœuds machines de travail et de contrôleur, 100
de contrôleur Kubernetes avec cfssl, 107 création d'un groupe de ressources, 100
sécurisation d’entrée Kubernetes avec un certificat création d'un réseau virtuel Azure, 102
et une clé TLS encodés en base 64, 94 déploiement et configuration des nœuds de
TLS, 250 contrôleur avec Ansible, 106-109
certificats SSL, 52 déploiement et configuration des nœuds de
cgroup, 40 travail avec Ansible, 109
cgroups (groupes de contrôle), 38 génération du fichier kubeconfig pour
contrôle des fonctionnalités Linux, 40 l’accès à distance et la validation de
chiffrement des données de cluster Kubernetes au cluster, 110
repos, 107 création dans Azure à l'aide d'AKS, 111
CIDR (Classless Inter-Domain Routing) déploiement d’applications et de services à l’aide
réseau Flanelle et pod CIDR, 208 de Helm, 113-119
sécurité de CIL pour, 200 composants de Helm, 114
Cilium, 190, 200-207 création de tableaux pour vos applications, 118
déploiement sur le cluster Kubernetes, 201-204 gestion des versions Helm, 117
installation d’AKS Cilium, 202, 202 installation et gestion de Helm, 114-117
installation de Cilium auto-gérée, 201 CNCF (voir Cloud Native Computing Foundation)
installation de Hubble, 203 CNI (Container Network Interface), 190-193, 286
intégration avec votre Cloud, 204-207 avantages de l’utilisation, 191
observabilité, 206 exemple de configuration, 190
pare-feu hôte, 204-206 fonctionnement avec Azure, 191
Citadel (Istiod), 174 implémentation Cilium de son propre, 200
classes de stockage, 82, 83 plug-in CNI Calico, 194
clients (messagerie), 239 primitives gérées par, 190
cloud projets, 192
défis de, 2 command apply (Terraform), 14, 16, 24, 26
parcours vers, 1 commande apply (kubectl), 80, 87
Cloud Native Computing Foundation (CNCF), 4, 285 application d’un manifeste de tâche, 97
CloudEvents, 244 commande cluster-info (kubectl), 77
orchestrateurs de conteneur, 41 commande curl, 145
paysage de streaming et de messagerie, 238 commande delete de pod (kubectl), 84
paysage sans serveur, 266, 287 commande describe (kubectl), 77
paysage, 287 describe deployment, 88
projets de base de données, 219 description de l’état d'un Job, 97
Cloud Shell, 17, 18 vérification du proxy sidecar en cours
création d’un principal de service à utiliser avec d’exécution dans un pod, 178
Terraform, 18 commande destroy (Terraform), 16, 27
CloudEvents (CNCF), 244 commande dig, 168, 170
ClusterRole, 208 commande docker build, 48
ClusterRoleBinding, 208 utilisation des options, 49
clusters (Kubernetes) commande edit (kubectl), 87, 228
création à partir de zéro dans Azure, 99-111 commande get (kubectl), 77
configuration de la mise en réseau et du get hpa, 89
routage des pods, 109 get svc, 91
création d’adresses IP publiques pour commande get nodes (kubectl), 76
l’équilibreur de charge, 102-104 -o wide flag, 76
création d’instances de travail et de commande init (Terraform), 16
contrôleur, 104-106 commande logs (kubectl), 78, 146
création d’un backend de compte de commande mise à l'échelle automatique (kubectl), 89
Index | 291
commande plan (Terraform), 24 KEDA, 276
commande run (kubectl), 79 contrôleurs d’admission (Kubernetes), 177
communication inter-processus, 233 copie en écriture (CoW), 40
complexité opérationnelle, 3 CoreDNS, 286
compte de stockage et blob, création à partir de installation and configuration, 167-169
Terraform, 24 plug-in propre à Azure, 171
comptes de stockage, 220 présentation de, 165
compteurs (Prometheus), 131 processus de requête, 166
concepteurs, 29 Corefile, 167
conditionnement, avantages des conteneurs pour, 37 courtiers, 234
confd (Calico), 194 et clustering, 240
config (Helm), 114 CRI-O, 43
ConfigMap, 208
configuration ipPools, 196
containerd, 42
D
DaemonSets, 75
Containers Kata, 49
Flannel CNI, 208
conteneur sidecar, 72
Fluentd, 147
conteneurisation d'applications, 35-66, 285
déploiement sur le cluster Kubernetes, 148
autres plateformes de conteneurs, 49-50
utilisation en production, 94
avantages de l’utilisation de conteneurs, 35-37
versus ReplicaSets, 94
conditionnement et déploiement, 37
débit, amélioration de la messagerie, 234
isolation, 36
débogabilité, manque de, sans serveur, 268
sécurité, 36
découverte de service, 68, 89, 134, 164-172, 286
composants de l’exécution d’un conteneur, 40-43
à propos, 164
orchestrateurs de conteneur, 41
configurations de découverte de services, 135
plateformes logicielles de conteneur, 41
etcd, 229
Docker, 46-49
dans Kubernetes, avec CoreDNS, 169-171
exécution de Docker sur Azure, 60-66
DNS Azure, 171
primitives de conteneur de base, 37-40
installation et configuration CoreDNS, 167-169
spécification OCI, 43-46
présentation de CoreDNS, 165
conteneurs, 43
déploiements
Azure Monitor, 159
automatique, avec Kubernetes, 68
hébergement de microservices, 67
avantages des conteneurs pour, 37
contexte (dans Kubernetes), 78
objet Deployment dans Kubernetes, 73, 84
contrats de niveau de service (SLA), 7
utilisation dans des environnements de
contrôle d’accès en fonction du rôle (RBAC)
production, 86
rôles dans Flannel, 208
déploiements sans interruption de service, 86
utilisation dans etcd, 231
dérive de configuration, 10
contrôles d’intégrité dans Kubernetes, 80
désinstallation d'une version Helm, 118
sonde de démarrage, 81
développement
sondes de disponibilité, 80
axé sur l’observation, 124
sondes de préparation, 81
cycles de développement plus rapides sans
contrôles de validation pour le cluster Kubernetes
serveur, 268
dans Azure, 110
développement futur, 287
contrôleur d'entrée, 74
DevOps, 8
application Gateway pour Azure Kubernetes
Azure DevOps et infrastructure en tant que
Service , configuration, 92
code, 33
contrôleurs
dimensionneurs (KEDA), 276
création d’instances de contrôleur pour le
directive EXPOSE (Dockerfile), 47
cluster Kubernetes dans Azure, 104-106
directive source (Fluentd), 140
déploiement et configuration des nœuds de
paramètre @label, 144
contrôleur Kubernetes avec Ansible, 106-109
disponibilité
292 | Index
de services PaaS, 221 échantillonnage contextuel, 153
etcd, 231 échantillonnage, 153
Disque Azure, 82 effets (stratégie Azure), 211
disques de stockage dans Azure, 82 Elasticsearch
disques gérés, 219 déploiement à l’aide de Helm sur Kubernetes, 148
disques SSD (Solid State Drive), 230 écriture des enregistrements sur un point de
distribution (message), 241 terminaison de cluster avec un plug-in
DNS Fluentd, 141
adresses IP et noms dans un cluster, 170 Enregistrements de type A pour services dans un
DNS Azure, 171 cluster, 170
gestion de DNS de clusters (voir CoreDNS) enregistrements SRV DNS, 231
limitation du DNS de sortie aux serveurs DNS entrées, 74
publics Google avec Cilium, 205 avec plusieurs chemins pour un domaine, 93
mappage du service Kubernetes au nom DNS, 91 objet Ingress Kubernetes, utilisation en
observation du trafic DNS avec Cilium et production, 92
Hubble, 206 Envoy (plan de données), 174, 286
DNS Azure, 171 injection automatique de proxy sidecar, 177
Docker Swarm, 41 équilibrage de charge
Docker, 42, 46-49 automatisation par des orchestrateurs de
création de votre première image Docker, 46-48 conteneurs, 68
exécution de tous les composants Jaeger dans contrôleur d’entrées dans Kubernetes, 74
une image de conteneur unique, 155 dans Kubernetes, 68
exécution sur Azure, 60-66 HTTP, effectué par l’objet Ingress Kubernetes, 92
exécution du moteur de conteneur Docker, équilibrage de charge de la couche 7 dans
65-66 Kubernetes, 92
utilisation d'Azure Container Instances, équilibrage de charge HTTP dans Kubernetes, 92
60-64 équilibreurs de charge
image contenant une application sans serveur, 273 création d’IP publiques pour l’équilibreur de
meilleures pratiques d’utilisation, 48 charge Kubernetes dans Azure, 102-104
moteur d’exécution, 43 IP de cluster, port de nœud et équilibreur de
stockage d'images Docker dans un registre de charge dans un nœud Kubernetes, 91
conteneurs, 59 espaces de noms, 39
Dockerfiles, 46 composants Istio sur AKS, 176
création, 47 dans Azure Service Bus, 254, 255
défini, 48 dans Kubernetes, 74
domaine de cluster (Kubernetes), 170 obtention d’informations sur, avec kubectl, 77
domaine d'échec dans Vitess, 224 état
domaines, 170 dans Terraform, 15
(voir aussi CoreDNS ; DNS) définition pour un conteneur, spécification
dans Azure Event Grid, 261 OCI, 45
entrée avec plusieurs chemins pour, 93 détermination pour le cluster Kubernetes, 71
durabilité des messages, 241 état du réseau virtuel téléchargé par Terraform
modèle de file d’attente durable, 242 sur le compte de stockage, 27
exécution de charges de travail statiques
sur AKS, 220
E etcd, 71, 229-231
eBPF (Berkeley Packet Filter étendu)
architecture opérationnelle, 229
activation en tant que plan de données Calico, 197
disponibilité et sécurité, 231
prise en charge par Calico, 193
mise à l’échelle et correction automatiques, 230
utilisation avec la version du noyau ultérieure à
plateforme matérielle, 230
4.16, 198
étiquettes (Kubernetes), 74
utilisation par le projet Cilium, 200
Index | 293
étiquetage des pods, 87 backends de transport pris en charge, 208
istio-injection, 177 Flask, 46, 66
obtention d’informations sur, avec kubectl, 78 utilisation pour créer une application Knative
étiquettes (Prometheus), 126 Serving, 272
étiquetage, 136 Fluentd, 138-146
filtrage des métriques avec, 130 agissant en tant que couche de journalisation, 138
exemple de bloc de ressources (Terraform), 15 déploiement à l’aide de DaemonSet, 95
exportateurs (Prometheus), 126 @include directive, 144
ExternalName, 91 installation td-agent, 139
instruction filter, 142
instruction label, 143
F instruction match, 141
faas-cli, utilisation pour créer et déployer une
instruction source, 140
fonction sans serveur
instruction système, 143
faasd, 283
fonction, 282
failureThreshold, 81
fonctionnalité de calcul en périphérie, 267
Felix (Calico), 194
fonctionnalités du processus, contrôle Linux de, 40
fichier .dockerignore, 49
fonctionnalités, contrôle Linux pour processus ou
fichier Chart.yaml, 119
fournisseur de ressources Microsoft.
fichier custom-resources.yaml, 196
PolicyInsights, 211
fichier d’inventaire (Ansible), 32
fournisseurs (Terraform), 14
fichier kubeconfig, 78
exemple de bloc fournisseur, 15
génération pour l’accès à distance et la
function irate, 130
validation de cluster, 110
téléchargement pour le cluster AKS, 112
fichiers journaux, 122 G
affichage pour CoreDNS, 168 Galley (Istiod), 174
configuration dans l’outil de suivi Jaeger, 156 georéplication dans TiKV, 226
ingestion des journaux et analyse de gestion des pods, 78-85
données, exemple de cas d’utilisation de contrôles d'intégrité, 80
messagerie, 235-237 limites des ressources, 81
file d’attente de publication et d’abonnement basé volumes, 82
sur la mémoire, 237 gestion des stratégies, 189, 286
file d’attente durable dans la messagerie, 242 Open Policy Agent (OPA), 214-218
exemple de cas d’utilisation de messagerie, solution de sécurité et de stratégie de réseau de
ingestion des journaux et analyse de Calico, 193-200
données, 235-237 Stratégie Azure, 210-213
génération 1, sans files d’attente, 235 gestionnaire de contrôleur Kube, 70
génération 2 : avec les files d’attente Cloud et gestionnaire de packages pour Kubernetes
le stockage d’objets, 236 (voir Helm)
modèle de file d’attente simple dans la GlobalNetworkPolicy (Calico), 199
messagerie, 242, 253 groupes de clients, 259, 260
files d'attente, 234 groupes de gestion, 12
dans Azure Service Bus, 254, 255 définition d'une stratégie Azure sur, 189, 210
envoi/réception de messages dans la file stratégie Azure appliquée, 211
d’attente dans Python, 258 groupes de ressources, 12
fin des fichiers journaux, événements de lecture création avec Terraform, 22
Fluentd à partir de, 141 création, 100
Flannel, 207-210 dans Azure DNS, 171
déploiement, 207 Registre de conteneur Azure, 56
exemple d'architecture, 210
utilisation, 208
294 | Index
informatique serverless, 265-283, 287
H à propos, 265
Harbor, 51-54
avantages de, 267
configuration pour l’installation, 52
Azure Function Apps, 268-271
création d'une image Packer pour déployer
architecture de référence des fonctions sans
Harbor, 53
serveur d’Azure, 269
installation, 51
création d’une application de fonction, 270
vérification de l'installateur, 52
fonctions sans serveur, 266
stockage des images Docker dans, 59
inconvénients potentiels, 268
HDInsight, 243
KEDA, 276-281
Helm, 113-119
architecture, 276
histogrammes (Prometheus), 133
installation sur Kubernetes, 277-281
Horizontal Pod Autoscaler (HPA), 88, 230
OpenFaaS, 281-283
hôtes
architecture, 281
installation et configuration de Prometheus
écriture d'une fonction OpenFaaS, 282-283
sur, 127
installation sur Kubernetes, 281
recherche des hôtes pour être récupérés par
paysage sans serveur CNCF, 266, 287
Prometheus, 134-136
plateforme Knative, 272-276
HTTPS
architecture Knative, 272
exposition des points de terminaison aux
installation et exécution de Knative Eventing
services Kubernetes sur les pods, 74
sur Kubernetes 274-276
utilisation avec Harbor, 52, 54
installation et exécution de Knative Serving
Hubble
sur Kubernetes, 272
installation, 203
infrastructure anti-fragile, 9
observabilité avec Cilium, 206
infrastructure en tant que code (IaC), 7-33, 285
avantages, 8, 9
I Azure DevOps et, 33
idempotence prise en main d’Azure et de l’environnement de
infrastructure en tant que code, 9 développement, 11-13
modèles ARM, 28 création du compte Azure, 12
image de conteneur, 37 installation d'Azure CLI, 13
(voir aussi images [conteneur]) notions de base d’Azure et préparation de
spécification d’image OCI, 44 l'environnement, 11
images (conteneur) infrastructure immuable, 10, 29
création de votre première image Docker, 46-48 infrastructure native Cloud, 2
spécification d’image OCI, 44 adoption avec Azure, 4
stockage d'images Docker dans un registre, 59 développement futur dans, 287
images de machine développer et exécuter avec Azure, 285
création avec Packer, 29-31 obtention d’informations sur les applications et
création pour les machines de travail et de l’infrastructure, 286
contrôleur dans Kubernetes, 100 philosophie, 10
implémentation de la messagerie NAT, 234 initialDelaySeconds, 80
exploration de la messagerie avec, 244-253 initiatives (stratégie Azure), 211
architecture du protocole NATS, 244-248 inspecteur Grafana, 252
avantages de NATS, 244 instance de pilote de placement (DP), 228
déploiement de NATS sur Kubernetes, 251 instances (dans Prometheus), 127
persistance de NATS avec JetStream, 249 instruction filter (Fluentd), 142
sécurité de NATS, 249 plug-ins supplémentaires, 142
fonctionnalités de streaming, 238 instruction label (Fluentd), 143
IMS, 253 instruction match (Fluentd), 141
@include directive (Fluentd), 144 instruction système (Fluentd), 143
Index | 295
interface de ligne de commande (CLI) interface utilisateur, accès, 181
affichage du groupe de ressources Terraform à journaux, métriques et suivis fournis, 186
partir de, 23 passerelle, service virtuel et règle de
azure-cli, 255 destination, 180
calicoctl dans Calico, 194 tableau de bord indiquant le trafic entrant, 182
installation d'Azure CLI, 13 tableau de bord montrant l’injection
Internet des objets (IoT), utilisation de la automatique de proxy sidecar dans l’espace
messagerie, 234 de noms par défaut, 182
isolation assurée par les conteneurs, 36 Kibans, 149
Istio, 159, 286 kit de ressources de l'infrastructure à clé publique/
architecture, 175 Transport Layer Security (PKI/TLS) de Cloud
gestion des maillages de services à l’aide de (PKI/TLS), 107
Kiali, 179-186 kit de ressources PKI/TLS, 107
présentation de, 174 Knative, 272-276
Istiod (plan de contrôle), 174 architecture, 272
installation et exécution de Knative Eventing
sur Kubernetes 274-276
J installation et exécution de Knative Serving sur
jauges (Prometheus), 132
Kubernetes, 272
JetStream (NATS), 244, 244
kube-apiserver, 70
persistance avec, 249
kubectl, 76-98
journalisation
Informations générales et commandes liées aux
courtiers et, 240
clusters, 76
de plusieurs serveurs NATS, 245
installation de Flannel, 207
journalisation au niveau du cluster, 146
installation de Hubble via, 203
journalisation dans le monde Cloud natif, 138-149
installation du binaire sur OS X et Linux, 108
à l’aide de Fluentd, 138-146
téléchargement et installation de Calico, 196
exécution de Fluentd sur Kubernetes, 146-149
vérification des ressources créées pour le tableau
journalisation, 286
Tomcat dans Helm, 116
analyse des journaux et requêtes de journaux
kube-dns vs. CoreDNS, 165
avec Azure Monitor, 160
kubelets, 42, 71
exécution du conteneur de journalisation dans
extraction des nœuds kubelet à l’aide de
Kubernetes, 95
Prometheus, 137
JSON
kube-proxy, 71
définitions de stratégie Azure, 210
désactivation du déploiement de, 198
lecture des hôtes par Prometheus à partir du
Kubernetes en production, 85-98
fichier inventory.json, 134
DaemonSets, 94
utilisation avec Terraform, 14
Horizontal Pod Autoscaler – HPA (échelle
horizontale de pod), 88
K objet Ingress, 92
Kafka, 234 objets de déploiement, 86
fonctionnalités de streaming, 238 ReplicaSets, 85
présentation, 243 tâches, 96
KEDA – Kubernetes Event-Driven Autoscaling Kubernetes Event-Driven Autoscaling – Mise à
(Mise à l’échelle pilotée par les événements l’échelle pilotée par les événements Kubernetes
Kubernetes), 276-281 (voir KEDA)
architecture, 276 Kubernetes, 4, 41, 67-98, 285
installation de KEDA sur Kubernetes, 277-281 composants, 69-72
Kiali (console de gestion pour Istio), 179-186, 286 nœuds de travail, 71
découverte du tableau de bord, 183 plan de contrôle, 70
exposition à Internet, 180 contrôleurs d’admission, 177
installation de Kiali sur le cluster Kubernetes, 179 création d'un cluster dans Azure, 99-120
296 | Index
création d'un cluster à partir de zéro, 99-111 limitation de débit, 153
déploiement d’applications et de services à limites de ressources (Kubernetes), 81
l’aide de Helm, 113-119 Linux
utilisation d'Azure Kubernetes Service, 111 étiquettes SELinux, 37
découverte de service avec CoreDNS, 169-171 image de machine, en s’appuyant sur Azure avec
déploiement de Calico via l’installation AKS, 196 Packer, 29
déploiement de NATS sur, 251 primitives de conteneur, 37-40
déploiement de TiKV sur, 228-229 prise en charge de Calico pour, 193
déploiement de Vitess sur, 223-224 réduction de l’accès du conteneur aux API du
déploiement d'Open Policy Agent sur, 215 noyau, 36
etcd utilisé comme backend de découverte de livraison des messages, au mois une fois 241
services dans, 229 fourni par les services de messagerie Azure, 253
Flannel CNI, 207-210 livraison des messages, une fois maximum, 241
Fluentd sur, 146-149 livraison des messages, une seule fois, 241, 249
fonctions prêtes à l'emploi offertes, 68 locataires, 11
installation de KEDA sur, 277-281 logiciel de conteneur, 41
installation de Kiali sur le cluster, 179 logiciel en tant que service (SaaS), 2, 2
installation d'Istio sur AKS, 175 Loki, outil d’agrégation de journaux, 149
installation d'OpenFaaS sur, 281 LXC (conteneurs Linux), 49
installation et exécution de Knative Eventing LXD (logiciel de gestion de conteneurs), 50
sur, 274-276
installation et exécution de Knative Serving
sur, 272
M
machines virtuelles
installation manuelle de Calico sur le
Azure Monitor pour, 159
cluster, 196
Azure, prise en charge des plug-ins VNet
Interface Runtime du conteneur, mise en œuvre
Azure, 191
CRI-O de, 43
magasin clé-valeur transactionnel (voir TiKV)
numéronyme K8s, 68
magasins de clé-valeur
objets serveur API, 72-76
etcd, magasin de clé-valeur distribué, 229
observation, exploitation et gestion des clusters
TiKV, 226
avec kubectl, 76-98
maillage des services, 172-187, 286
Kubernetes en production, 85-98
architecture générale, 172
orchestrateur de stockage Rook, 224-226
défini, 164
plateforme Knative, 272
injection automatique de proxy sidecar, 177
Prometheus sur, rôles de découverte de
installation d'Istio sur AKS, 175
services, 136-138
Istio, gestion à l’aide de Kiali, 179-186
remplacement de kube-dns par CoreDNS, 165
plan de contrôle, 173
ressources pour apprentissage supplémentaire, 75
plan de données, 173
service de fonction axé sur les événements
Présentation d’Istio, 174
OpenFaaS pour, 281
ManagedImageId, 101
stratégie Azure pour, 213
manifestes (pod), 79
configuration des sondes de préparation et de
L disponibilité, 81
Label-Selector, 74 limites des ressources dans, 81
Langage CRuby (Fluentd), 138 MariaDB, base de données Azure pour, 220
langage de programmation Erlang/OTP, 243 mémoire
langage de programmation Ruby, implémentation limite maximale dans le manifeste de pods, 81
C de, 138 technique de gestion, copie en écriture, 40
langage HashiCorp (HCL), 14 Mesos, 41
langage propre au domaine, HCL, 14 messagerie, 233-263, 287
Langage Rego, 214 bases des plateformes de messagerie, 238
liaison, 70 besoin de, 233-235
Index | 297
raisons de l'implémentation de la communications entre routage et sécurité,
messagerie, 234 dans l'ingestion des journaux et l'analyse de
exemple de cas d’utilisation, ingestion des données, exemple de cas d’utilisation de
journaux et analyse de données, 235-237 messagerie, 237
génération 1, sans files d’attente, 235 entre, 172
génération 2 : avec les files d’attente Cloud et maillage de service gérant la communication
le stockage d’objets, 236 entre,
génération 3 : avec file d’attente de maillage de service Istio simplifiant la
publication et d’abonnement basé sur la communication entre, 174
mémoire, 237 passage d’une architecture monolithique à, 10
messagerie Cloud avec NAT, 244-253 sécurité, 163
modèles courants, 242-243 mise à l’échelle automatique
file d’attente durable, 242 approches de machine virtuelle, 234
file d’attente simple, 242 Azure, 231
publication et abonnement, 242 en serverless, 265, 268
notions de base, 238-242 etcd et, 230
courtiers et clustering, 240 KEDA, 276-281
distribution de message, 241 OpenFaaS, 281, 283
durabilité et persistance, 241 mise à l’échelle horizontale avec les pods, 73
producteurs et consommateurs, 239 mise à l’échelle, 234
sécurité, 242 (voir également mise à l’échelle automatique)
présentation des plateformes de messagerie files d’attente de messages mise à l’échelle
Cloud natives populaires horizontalement, 237
Apache Kafka, 243 mise à niveau d’une version Helm, 117
CNCF CloudEvents, 244 mise en réseau, 189-218, 286
plateformes, 243-244 CNI (Container Network Interface), 190-193
RabbitMQ, 243 avantages de l’utilisation, 191
services de messagerie Azure, 253 fonctionnement avec Azure, 191
Azure Event Grid, 261-263 projets CNI, 192
Azure Event Hubs, 258-261 configuration de pods dans le cluster
Azure Service Bus, 253-258 Kubernetes sur Azure, 109
choisir parmi, 253 création d’un réseau virtuel Azure à partir de
métriques, 122 Terraform, 25-102
à partir de points de terminaison de intégrations de réseau pour Knative
surveillance NATS, 248 Serving, 272
adaptateur de métriques dans KEDA, 276 outil de mise en réseau Cilium, 200-207
Azure Monitor, 160 déploiement de Cilium, 201-204
métriques Cilium sur le trafic DNS et HTTP, 206 solution de sécurité et de stratégie de réseau de
Prometheus avec le maillage de service Istio, 182 Calico, 193-200
surveillance avec Prometheus dans le Cloud déploiement de Calico, 195-197
composants et architecture de mise en œuvre de la stratégie de sécurité
Prometheus, 125-127 Calico, 198-200
installation et configuration de utilisation de Calico, 197-198
Prometheus, 127 système d’infrastructure réseau (OSI) de
instrumentation des applications, 130-134 couche 3 pour Kubernetes, 207-210
monde natif, 125-138 modèles
node_exporter, 129 dans ReplicaSets Kubernetes, 85
Prometheus sur Kubernetes, 136-138 des fournisseurs de Cloud pour la mise en
recherche d'hôtes, 134-136 œuvre de l'IaC, 8
microservices, 67 modèles Terraform et ARM, 28
avantages de, 163 Packer, 29
298 | Index
modèles Azure Resource Manager (ARM), 8 avec Cilium, 200, 206
Terraform et, 28 développement piloté par, 124
modèles de monodiffusion, multidiffusion et de journalisation dans le monde Cloud
diffusion, 240 natif, 138-149
modèles de publication/abonnement, 234, 242 Fluentd sur Kubernetes, 146-149
dans NATS, 245 journalisation avec Fluentd, 138-146
file d’attente de publication et d’abonnement présentation de, 121-124
basé sur la mémoire, 237 piliers de, journaux, métriques et suivi, 122
prise en charge par Azure Service Bus, 253 suivi distribué dans le monde Cloud natif, 150-159
modes de mise en œuvre de la stratégie réseau architecture du système de suivi général et
(Cilium), 204 ensemble de suivi, 153
module d’extension forward (Fluentd), 140, 141 concepts de suivi clé, 151-153
déploiement de la fonction Knative Serving sur suivi des normes, des outils et des
Kubernetes, 273 instruments de code, 154-159
écriture de votre première fonction sur-ensemble de la surveillance, 123
OpenFaaS, 282-283 surveillance des métriques avec Prometheus
fonctions (sans serveur), 266 dans un monde Cloud natif
grand nombre de, 268 composants et architecture de
module d’extension http (Fluentd), 140 Prometheus, 125-127
modules (Terraform), 15 installation et configuration de Prometheus, 127
modules d’extension d’entrée (Fluentd), 140 instrumentation des applications, 130-134
récupération des journaux d’événements monde Cloud natif, 125-138
provenant de sources externes, 140 node_exporter, 129
MTAs (agents de transfert de messages), 239 Prometheus sur Kubernetes, 136-138
clustering, 240 recherche d'hôtes, 134-136
MutatingAdmissionController, 177 utilisation de Kiali pour les maillages de
MySQL services Istio, 179
Azure Database pour, 220
distribués et partitionné, Vitess, 221-224
navigateur d’expression (Prometheus), 128
O
Open Policy Agent (OPA), 214-218
API clés servis par, 214
N déploiement de stratégie avec, 216-218
NetworkPolicy (Calico), 199 déploiement sur Kubernetes, 215
NFS – Network File System (système de fichiers intégrations, page Écosystème OPA, 215
réseau), 224 OpenCensus, 154
nœud de contrôle, 32 OpenFaaS, 281-283
nœuds architecture, 281
création de nœuds d'instance de travail et de création de votre première fonction, 282-283
contrôleur pour le cluster Kubernetes dans installation sur Kubernetes, 281
Azure, 104-106 OpenSSL, 250
node_exporter (Prometheus), 129 OpenTelemetry, 154
rôle de nœud, 136 instrumentation du code avec, 157
nœuds de travail (Kubernetes), 71 OpenTracing, 154
création pour un cluster dans Azure, 104-106 instrumentation du code d'application avec, 155
déploiement et configuration avec Ansible, 109 opérateur (Kiali), 180
nœuds gérés, 32 opération asynchrone (messagerie), 235
nom du registre (Azure Container Registry), 56 orchestrateur de stockage Rook, 224-226
nom métrique (Prometheus), 126 architecture, 224
observabilité, 121-161, 286 déploiement sur Kubernetes, 225-226
à l’aide d’Azure Monitor, 159 orchestrateurs (conteneur), 41, 67
au-delà de trois piliers, 123 (voir aussi Kubernetes)
Index | 299
orchestrateurs de conteneur, 40 pipelines CI/CD
(voir aussi Kubernetes ; orchestrateurs) applications de fonction d’Azure et, 269
orchestration de conteneur, 68 Pipelines Azure, 33
outil cfssl, 107 plan (Terraform), 14, 16
outil de suivi Jaeger, 154 plan de contrôle (Kubernetes), 70
instrumentation du code à l’aide des normes de plan de contrôle (maillage de services), 173
suivi et Jaeger, 154-159 Istiod, 174
outil de traçage Zipkin, 154 plan de données (maillage de services), 173
outils IaC de premier plan, 13 Envoy, utilisation par Istio, 174
Ansible, 31 planificateur Kube, 70
Packer, 29-31 planificateurs, 67
Terraform, 14-28 fonctions de planification dans Kubernetes,
altérations et tolérances, 95
planificateur Kube, 70
P plateforme en tant que service (PaaS), 2
Packer, 29-31, 285
Azure, 11
création d’images de contrôleur et d’instances
Docker, 46
de travail, 100
services de stockage et de base de données
création d’une image Linux sur Azure, 29
Azure, 220
création d'une image pour déployer Harbor, 53
plateformes de conteneur
installation de Docker CE via l’image Packer, 65
Containers Kata, 49
installation, 29
Docker, 46-49
paires de clés, génération pour l’authentification
LXC et LXD, 49
Nkey, 250
plateformes communes, 42
paramètre de stockage, modification pour le cluster
playbooks (Ansible), 31
TiKV, 228
plug-in de cache (CoreDNS), 168
partitionnement
plug-in d'erreurs (CoreDNS), 168
fonctions de partitionnement automatique de
plug-in file (Fluentd), 141
TiKV, 226
plug-in filter_geoip (Fluentd), 143
prise en charge de Vitess pour, 221
plug-in filter_record_transformer (Fluentd), 142
partitionnement logique, 74
plug-in filter_stdout (Fluentd), 143
partitions (message), 259
plug-in in_exec (Fluentd), 141
passerelle (Kiali), 180
plug-in in_syslog (Fluentd), 140
performance
plug-in in_tail (Fluentd), 141
amélioration de la messagerie, 234
plug-in in_unix (Fluentd), 141
de services PaaS, 221
plug-in log (CoreDNS), 168
fonctions sans serveur et, 266
plug-in out_copy (Fluentd), 142
périodes, 151
plug-in out_elasticsearch (Fluentd), 141
en suivi pour le service de réservation de films, 157
plug-in stdout (Fluentd), 142
période de demande entrante et sortante, 154
plugins de sortie (Fluentd), 141
periodSeconds, 80
plug-ins IPAM, CNI, 192
persistance (messages), 241
plug-ins Main (CNI), 192
JetStream NATS, 246, 249
plug-ins Meta (CNI), 192
protocole de publication et d’abonnement et, 244
pods Nginx, 79
PersistenceVolumeClaims (PVCs), 82, 84
Pods, 72
Pilot (Istiod), 174
configuration de la mise en réseau et du routage
pilotage, 286
de pod pour le cluster Kubernetes dans
de serveurs NAT, 246
Azure, 109
infrastructure et applications modernes natives
disponibilité pendant les mises à jour, 88
du Cloud, 125
gestion avec kubectl, 78-85
(voir aussi Prometheus)
création de pods à l’aide de la syntaxe
observabilité en tant que sur-ensemble de, 123
300 | Index
déclarative dans les manifestes de pods, 79 rôle d’entrée, 138
création de pods avec la commande run, 79 rôle de nœud, 136
injection automatique de proxy sidecar, 178 rôle de pod, 137
proxy du sidecar Istio sur, 176 rôle de points de terminaison, 137
Point de terminaison TCP pour Fluentd, 140 rôle de service, 137
Points de terminaison HTTP, définition et rôles, 136-138
exposition des métriques à l’aide de, 130 recherche d'hôtes, 134-136
points de terminaison privés, 58 utilisation d’Ansible, 134
Portail Azure utilisation d'azure_sd_config, 135
affichage du déploiement de Service Bus, 257 utilisation d'un fichier JSON ou YAML, 134
affichage du réseau virtuel en cours de création, 26 PromQL, 128
création de compte Azure via, 12 propagation de contexte distribué, 152
création de locataires AAD avec, 11 propagation du contexte, 152
création d'un cluster AKS, 111 protocole de messagerie SMTP, exemple de système
création d'une instance de conteneur Azure, 61 de mise en file d’attente, 240
icône Cloud Shell dans votre compte, 18 protocole gRPC (Google Remote Procedure Call), 227
interaction d'Azure CLI avec, 13 protocole Raft, 226, 227
recherche d’Azure Container Registry, 55 utilisation par etcd, 229
utilisation pour créer une application de protocoles et modèles de messagerie, 253
fonction, 270 provisionneurs, 29
vérification de la création d’images de machine proxys de sidecar (maillage de service), 172, 172
Packer dans, 30 injection automatique de proxy Envoy, 177
vérification de la création du groupe de pushgateway (Prometheus), 126
ressources Terraform, 22 Python, 32
ports bibliothèque Flask, 272
serveur de zone DNS, 167 configuration de l’environnement Python pour
services dans Kubernetes, 90 tester
affichage du mappage de port, 91 déploiement KEDA, 279
PostgreSQL, base de données Azure pour, 220 file d’attente Azure Service Bus, envoi/réception
PowerShell, 18 de messages, 258
principal de service, création pour Terraform, 18 paquet nats-py, 252
Prise en charge protocole MQTT, NAT Jetstream, 244 producteur utilisant le paquet Python azure-
producteurs et consommateurs (messagerie), 239 eventgrid, 262
modèle de file d’attente simple, 242
producteurs, 259
programmes de Berkeley Packet Filter (BPF), 40
Q
quotas de ressources, 74
(voir aussi eBPF)
projets open source (CNCF), 288
Prometheus, 125-138 R
composants et architecture, 125-127 RabbitMQ, 234
tâches et instances, 127 fonctionnalités de streaming, 238
installation and configuration, 127 présentation, 243
installation avec Istio, 182 redirection de port, 148
instrumentation des applications, 130-134 déploiement local de redirection Kibana, 149
compteurs, 131 Redis, 124, 157
histogrammes, 133 Azure Cache pour, 220
jauges, 132 réétiquetage (dans Prometheus), 136
résumé, 133 références
node_exporter, 129 exécution d'etcd sur les références Azure, 230
exécution sur Kubernetes, service de Registre de conteneur Azure, 57
découverte référentiel de tableau et interactions avec les
Index | 301
clients, 113 réseaux virtuels, 64
composants, 114 CNI fonctionnant avec Azure, 191
création de tableaux pour vos applications, 118 création d’un réseau virtuel Azure à partir de
déploiement de Elasticsearch sur Kubernetes, 148 Terraform, 25-27
déploiement de Kibana sur Kubernetes, 149 création d’un réseau virtuel Azure pour
gestion des versions, 117 héberger le cluster Kubernetes, 102
installation de FaaS sur Kubernetes, 281 DNS dans, 171
installation de KEDA sur Kubernetes, 277 résilience, renforcement avec la messagerie, 234
installation de Kiali sur Kubernetes, 179 ressource personnalisée (Kiali), 180
installation de NATS sur Kubernetes, 251 restauration d'une version Helm, 118
installation de TiKV sur Kubernetes, 228 résumé (Prometheus), 133
installation d'Istio sur AKS, 175 RocksDB, 227
installation et gestion, 114-117 rôle d’entrée, 138
installation d’un tableau Helm sur rôle de pod, 137
Kubernetes, 115 rôle de points de terminaison, 137
modification des valeurs par défaut du rôle de service, 137
tableau, 116 routage
recherche de référentiels Helm, 115 Calico, 194
Référentiel GitHub pour ce livre, 20 CIDR, 208
référentiel PingCap, 228 CNI, 190
référentiels (Helm), 114 configuration de pods dans le cluster
ajout d’un référentiel de tableau, 114 Kubernetes sur Azure, 109
recherche, 115 dans Istio, 174, 174
régions, 12 dans les entrées Kubernetes, 93
choix de la région pour Azure Container dans les espaces de noms Linux, 39
Registry, 56 dans les maillages de service, 172, 173
Registre de conteneur Azure, 55-59 Fluentd, 140, 143
registre de services, 164 Kiali dans Istio, 180, 185
registres de conteneurs, 50-59 rubriques
produits natifs du Cloud actuels, 50 dans Azure Event Grid, 261
stockage des images Docker dans, 59 dans Azure Service Bus, 254, 255
stockage d'images sécurisé avec Harbor, 51-54 runtimes (conteneur), 42
règle de destination (Kiali), 180 runtimes de conteneur, 42
règles d’autorisation de couche 3 et de couche 4
(Cilium), 204
activation de la visibilité, 206
S
Seccomp (SECure COMPuting), 40
Règles de visibilité de la couche 7 dans Cilium, 205
Seccomp-BPF, 40
réparation automatique, etcd, 230
secrets
réplicas, nombre à créer dans Kubernetes
paires de clés partagées en tant que secret
ReplicaSets, 85
Kubernetes, 250
ReplicaSets, 73
spécification du support TLS pour l’entrée
DaemonSets vs., 94
Kubernetes avec un objet Secret, 94
gestion des objets Deployment, 87
sécurité
Kubernetes en production, 85
etcd TLS et RBAC, 231
réplication
fourni par les conteneurs, 36
fonctionnalités TiKV pour, 226
messagerie, 242
modification du paramètre de réplicas pour le
NATS, 249
cluster TiKV, 228
Authentification basée sur Nkey, 250
requêtes HTTP GET, 266
authentification TLS, 250
réseau virtuel Azure (VNet), plug-ins connectant
outil de mise en réseau Cilium, 200
des conteneurs à, 191
stratégie de sécurité Calico, mise en
302 | Index
œuvre, 198-200 mise à jour du chemin d'accès à l’emplacement
sélecteurs (étiquette), 74 de la clé SSH pour les machines de travail et
dans ReplicaSets, 85 de contrôleur, 104
séries chronologiques, données stockées StatefulSets, 75
Prometheus en tant que, 126 stockage blob, 15, 23
Serveur API création de stockage blob Azure, 24
kube-apiserver, 70 stockage d'objets, 236
utilisation d’objets Kubernetes, 72-76 stockage Hadoop Distributed File System
annotations, 74 (HDFS), 220
contrôleur d'entrée, 74 stockage, 219-232, 286
DaemonSets, 75 base de données distribuée, 219
déploiements, 73 (voir aussi bases de données distribuées)
espaces de noms, 74 clés, 250
étiquettes et sélecteurs, 74 création d’un backend de compte de stockage
Pods, 72 pour le cluster Kubernetes dans Azure, 101
ReplicaSets, 73 etcd, 229-231
services, 73 magasin clé/valeur etcd, 71
StatefulSets, 75 messages, 241
Tâches, 75 objets de stockage dans Kubernetes, 84
serveur Tomcat, déploiement avec Helm, 116 options d'Azure pour, 220
serveur web Nginx orchestrateur de stockage Rook pour
déploiement de la nouvelle version, 87 Kubernetes, 224-226
utilisation avec Azure Container Instances, 64 TiKV (Titanium Key-Value), 226-229
serveurs stratégie Azure, 189, 210-213
NATS création de votre propre stratégie, 212-213
clustering, 245 démarrage rapide, 210-212
pilotage, 246 initiatives, 211
utilisation du serveur NATS Docker, 246 modes ou effets d'application des
serveur Prometheus, 126 politiques, 211
service virtuel (Kiali), 180 stratégies intégrées, 210
services fonctions clés, 210
compte de service Kubernetes pour Flannel, 208 limites, 213
objet Service dans Kubernetes, 73 pour Kubernetes, 213
utilisation dans des environnements de streaming, 287
production, 89 messagerie vs., 238
sans serveur, définition dans un fichier, 273 serveur de diffusion (stan) NAT, installation sur
shells Kubernetes, 251
Bash et PowerShell, 18 Streams (NATS), 244
Cloud Shell, 17 suivi, distribué, dans le monde Cloud
sonde de démarrage, 81 natif, 150-159, 286
sondes de disponibilité, 80 architecture du système de suivi général et
sondes de préparation, 81 ensemble de suivi, 153
sondes, 80 concepts de suivi clé, 151-153
(voir aussi contrôle d'intégrité dans Kubernetes) échantillonnage, 153
spécification de runtime (OCI), 45 périodes, 151
spécification OCI (Open Container Initiative), 43-46 propagation du contexte, 152
spécification d’image, 44 consommation de données de suivi avec
spécification de runtime, 45 Azure Monitor, 160
SSH suivi des normes, des outils et des instruments
configuration d'accès aux machines à l’aide de code, 154-159
d’OPA, 216-218 syntaxe déclarative
génération d’une paire de clés SSH, 105 Azure CLI pour scripter de façon déclarative
Index | 303
l'infrastructure Cloud Azure, 25
dans Kubernetes, 68, 73, 74 modèles ARM, 28
infrastructure, 13 gestion d’Azure Event Hubs avec, 259
langage déclaratif, Rego, 214 gestion d’Azure Service Bus avec, 255-258
modèles ARM, 28 installation, 17
utilisation des manifestes de pods pour la terminologie de base, 14
création de pods dans Kubernetes, 79 utilisation de base et configuration de
utilisation par Terraform, 14 l’infrastructure avec, 20
syscalls, filtrage, 40 TiKV (Titanium Key-Value), 226-229
système d’événements, Knative Eventing, 274-276 architecture, 226
système de stockage Ceph, 224 déploiement sur Kubernetes, 228-229
systèmes d’exploitation, conteneurs en cours TLS (Transport Layer Security)
d’exécution sur, 35, 43 authentification, utilisation dans NATS, 250
inspection des connexions chiffrées TLS avec
Cilium, 207
T kit de ressources PKI/TLS pour les certificats
tableaux (Helm), 114
TLS, 107
création pour vos applications, 118
spécification en créant l’objet Secret
éléments dans le répertoire de tableau, 118
Kubernetes, 94
modification de fichiers dans le répertoire
utilisation du chiffrement TLS dans etcd, 231
de tableau, 119
tolérances (fonction de planification de
installation sur Kubernetes, 115
Kubernetes), 95
modification des valeurs par défaut du
traces, 123
tableau, 116
assemblage, 154
restauration d’un tableau déployé, 118
défini, 152
tâches (Kubernetes), 75
trafic ICMP, autorisation avec Calico, 199
objet Job, création et gestion des pods, 96
type NodePort, 90
tâches (Prometheus), 127
types de métriques quatre cœurs, 126
td-agent (Fluentd)
Typha (Calico), 194
changement de configuration, 145
installation, 139
Terraform, 14-28, 285 U
charge de travail, 16 utilitaire mkcert, 250
commandes courantes, 17
configuration de l’accès au compte Azure, 18
configuration de la mise en réseau et du routage
V
variable ARM_ACCESS_KEY, 101
de pod pour le cluster Kubernetes dans
variables d’environnement, configuration pour
Azure, 109
Terraform sur machine locale, 19
création d’IP publiques pour l’équilibreur de
versions (Helm), 114
charge Kubernetes dans Azure, 102-104
gestion, 117
création d’un backend de compte de stockage
désinstallation d’une version, 118
pour le cluster Kubernetes dans Azure, 101
mise à niveau d’une version, 117
création d’un cluster AKS, 111
restauration d'une version, 118
création d’un groupe de ressources pour le
vérification d’une version, 117
cluster Kubernetes dans Azure, 100
virtualisation d’infrastructure, 191
création d'instance de travail et de contrôleur pour
virtualisation, 1
le cluster Kubernetes dans Azure, 104-106
CNI permettant une véritable virtualisation
création d'un réseau virtuel Azure, 102
d’infrastructure, 191
déploiement d'Azure Container Registry via, 58
Visual Studio code, extension Azure Functions, 270
déploiement d'Azure Event Grids, 262
Vitess, 221-224
exploration de l’infrastructure Azure avec 23
architecture, 222
création de stockage blob Azure, 24
avantages de l’utilisation, 221
création d'un réseau virtuel et d'instances
304 | Index
déploiement sur Kubernetes, 223-224
volume persistant (PV), 82, 84
Y
YAML, 32
statique, 83
Prometheus lisant les hôtes à partir d’un fichier
volumes (Kubernetes), 82
statique, 134
classe de stockage, dynamique, 83
PersistentVolumeClaims (PVC), 82
volume persistant, statique, 83 Z
vtcld, 222 zones (DNS), 165, 167
vtctl, 222 DNS Azure, 171
VTGate, 222
VTTablet, 222
vue cartographique de l’application (Azure
Monitor), 160
vue Diagnostics de transaction (Azure Monitor), 160
VXLAN
utilisation avec Calico, 197
utilisation avec Flannel, 208
W
Windows
mise en réseau, CNI Azure et, 191
prise en charge de Calico pour le plan de
données HNS Windows, 193
X
XDP, 198
Index | 305
À propos des auteurs
Nishant Singh est un ingénieur senior spécialisé dans la fiabilité du site chez LinkedIn. Son
travail consiste à améliorer la fiabilité du site, tout en privilégiant la réduction du temps
moyen de détection (MTTD) et du temps moyen de réponse (MTTR) face aux incidents.
Avant de rejoindre LinkedIn, il était ingénieur DevOps chez Paytm et Gemalto, et consacrait
son temps à la création de solutions personnalisées pour les clients, ainsi qu’à la gestion et
la maintenance des services sur le Cloud public. Nishant s’intéresse vivement à l’ingénierie
de la fiabilité des sites et à la création de systèmes distribués.
Michael Kehoe est un ingénieur senior chargé de la sécurité du personnel chez Confluent.
Auparavant, il était chargé de la réponse aux incidents, de la récupération d’urgence, de
l’ingénierie de la visibilité et des principes de fiabilité en tant qu’ingénieur senior de fiabilité
de site chez LinkedIn. Dans le cadre de ses fonctions chez LinkedIn, il a mené les efforts
de l’entreprise pour automatiser la migration vers Microsoft Azure. Michael est spécialisé
dans la gestion d’une grande infrastructure système, comme le démontre son travail chez
LinkedIn (applications, automatisation et infrastructure) et à l’Université du Queensland
(réseaux). Il a également consacré du temps à la création de petits satellites à la NASA et à
l’écriture de logiciels d’environnements thermiques à Rio Tinto.
Colophon
L’animal qui se trouve sur la page de couverture de Cloud Native Infrastructure with
Azure est un geai de Steller (Cyanocitta stelleri), un geai à crête trouvé dans l’ouest de
l’Amérique du Nord et centrale. Les geais de Steller résident généralement dans les
forêts de conifères, mais peuvent également être rencontrés dans les forêts de feuillus.
Nommé d’après Georg Wilhelm Steller, le naturaliste allemand qui a découvert cette espèce
pour la première fois en 1741, ce geai de couleur bleue est distinct du geai bleu de l’est de
l’Amérique du Nord, avec la crête noire exceptionnelle qui le caractérise.
Les geais de Steller sont omnivores ; leur régime alimentaire se compose principalement de
noix, de graines de pin, de glands, de baies et d’autres fruits additionnés d’insectes, de petits
rongeurs et d’œufs.
Bien que le statut de conservation du geai de Steller soit répertorié comme étant peu
préoccupant, la plupart des animaux figurant sur les couvertures O’Reilly sont menacés et
ils tous sont importants pour le monde entier.
L’illustration de la couverture est de Karen Montgomery, basée sur une gravure d’illustration
antique de l’histoire naturelle royale de Lydekker. Les polices de couverture sont Gilroy
Semibold et Guardian Sans. La police de texte est Adobe Minion Pro ; la police d’en-tête est
Adobe Myriad Condensed ; et la police de code est Ubuntu Mono de Dalton Maag.
Apprenez des experts.
Devenez-en un vous-même.
Livres | Cours en ligne en direct
Réponses instantanées | Événements virtuels
Vidéos | Apprentissage interactif