Comment mettre à l’échelle une application Node.js avec MongoDB sur Kubernetes à l’aide de Helm

introduction

Kubernetes est un système permettant d'exécuter à grande échelle des applications conteneurisées modernes. Grâce à ce logiciel, les développeurs peuvent déployer et gérer des applications sur des clusters de machines. Et bien qu'il puisse être utilisé pour améliorer l'efficacité et la fiabilité des configurations d'applications à une seule instance, Kubernetes est conçu pour exécuter plusieurs instances d'une application sur plusieurs groupes de machines.

Lors de la création de déploiements multiservices avec Kubernetes, de nombreux développeurs choisissent d'utiliser le gestionnaire de packagesHelm. Helm rationalise le processus de création de plusieurs ressources Kubernetes en proposant des graphiques et des modèles qui coordonnent les interactions de ces objets. Il propose également des graphiques prédéfinis pour les projets open source populaires.

Dans ce didacticiel, vous déploierez une applicationNode.js avec une base de données MongoDB sur un cluster Kubernetes à l'aide de graphiques Helm. Vous utiliserez lesofficial Helm MongoDB replica set chart pour créer unStatefulSet object composé de troisPods, unHeadless Service et troisPersistentVolumeClaims. Vous allez également créer un graphique pour déployer une application Node.js à répliques multiples à l'aide d'une image d'application personnalisée. La configuration que vous construirez dans ce didacticiel reflétera la fonctionnalité du code décrit dansContainerizing a Node.js Application with Docker Compose et sera un bon point de départ pour créer une application Node.js résiliente avec un magasin de données MongoDB qui peut évoluer avec vos besoins.

Conditions préalables

Pour compléter ce tutoriel, vous aurez besoin de:

[[step-1 -—- cloning-and-packaging-the-application]] == Étape 1 - Clonage et empaquetage de l'application

Pour utiliser notre application avec Kubernetes, nous aurons besoin de la conditionner afin que leskubelet agent puissent extraire l'image. Avant d'empaqueter l'application, cependant, nous devrons modifier les MongoDBconnection URI dans le code de l'application pour nous assurer que notre application peut se connecter aux membres du jeu de réplicas que nous allons créer avec le graphique Helmmongodb-replicaset .

Notre première étape sera de cloner lesnode-mongo-docker-dev repository à partir desDigitalOcean Community GitHub account. Ce référentiel comprend le code de la configuration décrite dansContainerizing a Node.js Application for Development With Docker Compose, qui utilise une application de démonstration Node.js avec une base de données MongoDB pour montrer comment configurer un environnement de développement avec Docker Compose. Vous pouvez trouver plus d'informations sur l'application elle-même dans la sérieFrom Containers to Kubernetes with Node.js.

Clonez le référentiel dans un répertoire appelénode_project:

git clone https://github.com/do-community/node-mongo-docker-dev.git node_project

Accédez au répertoirenode_project:

cd node_project

Le répertoirenode_project contient des fichiers et des répertoires pour une application d'informations sur les requins qui fonctionne avec l'entrée utilisateur. Il a été modernisé pour fonctionner avec les conteneurs: les informations de configuration sensibles et spécifiques ont été supprimées du code de l’application et refactorisées pour être injectées au moment de l’exécution, et l’état de l’application a été transféré dans une base de données MongoDB.

Pour plus d'informations sur la conception d'applications conteneurisées modernes, consultezArchitecting Applications for Kubernetes etModernizing Applications for Kubernetes.

Lorsque nous déploierons le graphique Helmmongodb-replicaset, il créera:

  • Un objet StatefulSet avec trois pods - les membres des MongoDBreplica set. Chaque pod aura une PersistentVolumeClaim associée et conservera une identité fixe en cas de replanification.

  • Un jeu de réplicas MongoDB constitué des pods du StatefulSet. L'ensemble comprendra un primaire et deux secondaires. Les données seront répliquées du primaire vers les secondaires, garantissant que les données de nos applications restent hautement disponibles.

Pour que notre application puisse interagir avec les répliques de base de données, l'URI de connexion MongoDB dans notre code doit inclure les noms d'hôte des membres du jeu de réplicas ainsi que le nom du jeu de réplicas lui-même. Nous devons donc inclure ces valeurs dans l'URI.

Le fichier de notre référentiel cloné qui spécifie les informations de connexion à la base de données est appelédb.js. Ouvrez ce fichier maintenant en utilisantnano ou votre éditeur préféré:

nano db.js

Actuellement, le fichier contient desconstants référencés dans l'URI de connexion à la base de données au moment de l'exécution. Les valeurs de ces constantes sont injectées à l'aide de la propriétéprocess.env de Node, qui renvoie un objet contenant des informations sur votre environnement utilisateur au moment de l'exécution. La définition dynamique de valeurs dans notre code d'application nous permet de découpler le code de l'infrastructure sous-jacente, ce qui est nécessaire dans un environnement dynamique sans état. Pour plus d'informations sur la refactorisation du code d'application de cette manière, consultezStep 2 deContainerizing a Node.js Application for Development With Docker Compose et la discussion correspondante dansThe 12-Factor App.

Les constantes de l'URI de connexion et de la chaîne d'URI se présentent comme suit:

~/node_project/db.js

...
const {
  MONGO_USERNAME,
  MONGO_PASSWORD,
  MONGO_HOSTNAME,
  MONGO_PORT,
  MONGO_DB
} = process.env;

...

const url = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?authSource=admin`;
...

Conformément à l'approche 12FA, nous ne souhaitons pas coder en dur les noms d'hôte de nos instances de réplica ou le nom de notre jeu de réplicas dans cette chaîne d'URI. La constanteMONGO_HOSTNAME existante peut être étendue pour inclure plusieurs noms d'hôte - les membres de notre jeu de répliques - donc nous la laisserons en place. Cependant, nous devrons ajouter une constante de jeu de réplicas auxoptions section de la chaîne URI.

AjoutezMONGO_REPLICASET à la fois à l'objet constant URI et à la chaîne de connexion:

~/node_project/db.js

...
const {
  MONGO_USERNAME,
  MONGO_PASSWORD,
  MONGO_HOSTNAME,
  MONGO_PORT,
  MONGO_DB,
  MONGO_REPLICASET
} = process.env;

...
const url = `mongodb://${MONGO_USERNAME}:${MONGO_PASSWORD}@${MONGO_HOSTNAME}:${MONGO_PORT}/${MONGO_DB}?replicaSet=${MONGO_REPLICASET}&authSource=admin`;
...

L'utilisation desreplicaSet option dans la section options de l'URI nous permet de passer le nom du jeu de répliques, qui, avec les noms d'hôte définis dans la constanteMONGO_HOSTNAME, nous permettra de nous connecter à l'ensemble membres.

Enregistrez et fermez le fichier une fois l’édition terminée.

Une fois vos informations de connexion à la base de données modifiées pour fonctionner avec des jeux de réplicas, vous pouvez désormais empaqueter votre application, créer l'image avec la commandedocker build et la pousser vers Docker Hub.

Construisez l'image avecdocker build et l'indicateur-t, ce qui vous permet de marquer l'image avec un nom mémorable. Dans ce cas, marquez l'image avec votre nom d'utilisateur Docker Hub et nommez-lanode-replicas ou un nom de votre choix:

docker build -t your_dockerhub_username/node-replicas .

Le. dans la commande spécifie que le contexte de construction est le répertoire courant.

Il faudra une minute ou deux pour construire l'image. Une fois terminé, vérifiez vos images:

docker images

Vous verrez la sortie suivante:

OutputREPOSITORY                              TAG                 IMAGE ID            CREATED             SIZE
your_dockerhub_username/node-replicas   latest              56a69b4bc882        7 seconds ago       90.1MB
node                                    10-alpine           aa57b0242b33        6 days ago          71MB

Ensuite, connectez-vous au compte Docker Hub que vous avez créé dans les conditions préalables:

docker login -u your_dockerhub_username

Lorsque vous y êtes invité, entrez le mot de passe de votre compte Docker Hub. La connexion de cette manière créera un fichier~/.docker/config.json dans le répertoire de base de votre utilisateur non root avec vos informations d'identification Docker Hub.

Poussez l'image de l'application vers Docker Hub avec lesdocker push command. N'oubliez pas de remplaceryour_dockerhub_username par votre propre nom d'utilisateur Docker Hub:

docker push your_dockerhub_username/node-replicas

Vous disposez maintenant d'une image d'application que vous pouvez extraire pour exécuter votre application répliquée avec Kubernetes. La prochaine étape consistera à configurer des paramètres spécifiques à utiliser avec le graphique MongoDB Helm.

[[step-2 -—- creating-secrets-for-the-mongodb-replica-set]] == Étape 2 - Création de secrets pour l'ensemble de répliques MongoDB

Le graphiquestable/mongodb-replicaset fournit différentes options en ce qui concerne l'utilisation de Secrets, et nous en créerons deux à utiliser avec notre déploiement de graphique:

  • Un secret pour nosreplica set keyfile qui fonctionnera comme un mot de passe partagé entre les membres du jeu de réplicas, leur permettant d'authentifier les autres membres.

  • Un secret pour notre utilisateur administrateur MongoDB, qui sera créé en tant queroot user sur la base de donnéesadmin. Ce rôle vous permettra de créer des utilisateurs ultérieurs avec des autorisations limitées lors du déploiement de votre application en production.

Une fois ces secrets en place, nous pourrons définir nos valeurs de paramètre préférées dans un fichier de valeurs dédié et créer l'objet StatefulSet et le réplica MongoDB définis avec le graphique Helm.

Commençons par créer le fichier de clés. Nous utiliserons lesopenssl command avec l'optionrand pour générer une chaîne aléatoire de 756 octets pour le fichier de clés:

openssl rand -base64 756 > key.txt

La sortie générée par la commande sera encodée enbase64, assurant une transmission uniforme des données, et redirigée vers un fichier appelékey.txt, en suivant les instructions indiquées dans lesmongodb-replicaset chart authentication documentation. Leskey itself doivent comporter entre 6 et 1 024 caractères, composés uniquement de caractères de l'ensemble base64.

Vous pouvez maintenant créer un secret appelékeyfilesecret en utilisant ce fichier aveckubectl create:

kubectl create secret generic keyfilesecret --from-file=key.txt

Cela créera un objet Secret dans lesdefaultnamespace, car nous n'avons pas créé d'espace de noms spécifique pour notre configuration.

Vous verrez la sortie suivante indiquant que votre secret a été créé:

Outputsecret/keyfilesecret created

Supprimerkey.txt:

rm key.txt

Sinon, si vous souhaitez enregistrer le fichier, assurez-vous querestrict its permissions et ajoutez-le à votre.gitignore file pour le garder hors du contrôle de version.

Ensuite, créez le secret pour votre utilisateur administrateur MongoDB. La première étape consistera à convertir votre nom d’utilisateur et votre mot de passe en base64.

Convertissez votre nom d'utilisateur de base de données:

echo -n 'your_database_username' | base64

Notez la valeur que vous voyez dans la sortie.

Ensuite, convertissez votre mot de passe:

echo -n 'your_database_password' | base64

Notez également la valeur dans la sortie.

Ouvrez un fichier pour le secret:

nano secret.yaml

[.Remarque]##

Note: Les objets Kubernetes sont destypically defined utilisantYAML, ce qui interdit strictement les tabulations et nécessite deux espaces pour l'indentation. Si vous souhaitez vérifier le formatage de l'un de vos fichiers YAML, vous pouvez utiliser unlinter ou tester la validité de votre syntaxe en utilisantkubectl create avec les--dry-run et--validate drapeaux:

kubectl create -f your_yaml_file.yaml --dry-run --validate=true

En général, c'est une bonne idée de valider votre syntaxe avant de créer des ressources aveckubectl.

Ajoutez le code suivant au fichier pour créer un secret qui définira unuser et unpassword avec les valeurs encodées que vous venez de créer. Assurez-vous de remplacer les valeurs factices ici par votre propre nom d'utilisateur et mot de passeencoded:

~/node_project/secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: mongo-secret
data:
  user: your_encoded_username
  password: your_encoded_password

Ici, nous utilisons les noms de clés attendus par le graphiquemongodb-replicaset:user etpassword. Nous avons nommé l'objet secretmongo-secret, mais vous êtes libre de le nommer comme vous le souhaitez.

Enregistrez et fermez le fichier une fois l’édition terminée.

Créez l'objet Secret avec la commande suivante:

kubectl create -f secret.yaml

Vous verrez la sortie suivante:

Outputsecret/mongo-secret created

Encore une fois, vous pouvez soit supprimersecret.yaml, soit restreindre ses autorisations et l'ajouter à votre fichier.gitignore.

Une fois vos objets Secret créés, vous pouvez passer à la spécification des valeurs de paramètres que vous utiliserez avec le graphiquemongodb-replicaset et à la création du déploiement MongoDB.

[[step-3 -—- configuration-the-mongodb-helm-chart-and-creating-a-deployment]] == Étape 3 - Configuration du graphique de barre MongoDB et création d'un déploiement

Helm est livré avec un référentiel activement maintenu appeléstable qui contient le graphique que nous utiliserons:mongodb-replicaset. Pour utiliser ce graphique avec les secrets que nous venons de créer, nous allons créer un fichier avec des valeurs de paramètres de configuration appelémongodb-values.yaml, puis installer le graphique à l'aide de ce fichier.

Notre fichiermongodb-values.yaml reflétera largement lesvalues.yaml file par défaut dans le référentiel de graphiquesmongodb-replicaset. Nous allons cependant apporter les modifications suivantes à notre dossier:

  • Nous allons définir le paramètreauth surtrue pour nous assurer que nos instances de base de données commencent parauthorization enabled. Cela signifie que tous les clients devront s'authentifier pour accéder aux ressources et aux opérations de la base de données.

  • Nous allons ajouter des informations sur les secrets que nous avons créés à l'étape précédente afin que le graphique puisse utiliser ces valeurs pour créer le fichier de clés du jeu de réplicas et l'utilisateur admin.

  • Nous allons réduire la taille des PersistentVolumes associés à chaque pod dans le StatefulSet pour utiliser lesminimum viable DigitalOcean Block Storage unit, 1 Go, bien que vous soyez libre de le modifier pour répondre à vos besoins de stockage.

Cependant, avant d'écrire le fichiermongodb-values.yaml, vous devez d'abord vérifier que vous avez créé et configuré unStorageClass pour provisionner les ressources de stockage. Chacun des pods de votre base de données StatefulSet aura une identité persistante et unPersistentVolumeClaim associé, qui provisionneront dynamiquement un PersistentVolume pour le pod. Si un pod est replanifié, le volume persistant sera monté sur le nœud sur lequel le pod est programmé (bien que chaque volume doit être supprimé manuellement si son pod ou StatefulSet associé est définitivement supprimé).

Comme nous travaillons avecDigitalOcean Kubernetes, notre StorageClassprovisioner par défaut est défini surdobs.csi.digitalocean.com -DigitalOcean Block Storage - que nous pouvons vérifier en tapant:

kubectl get storageclass

Si vous travaillez avec un cluster DigitalOcean, vous verrez le résultat suivant:

OutputNAME                         PROVISIONER                 AGE
do-block-storage (default)   dobs.csi.digitalocean.com   21m

Si vous ne travaillez pas avec un cluster DigitalOcean, vous devrez créer une StorageClass et configurer unprovisioner de votre choix. Pour plus de détails sur la manière de procéder, consultez lesofficial documentation.

Maintenant que vous vous êtes assuré d'avoir configuré une StorageClass, ouvrezmongodb-values.yaml pour l'édition:

nano mongodb-values.yaml

Vous allez définir des valeurs dans ce fichier qui vont faire ce qui suit:

  • Activer l'autorisation.

  • Référencez vos objetskeyfilesecret etmongo-secret.

  • Spécifiez1Gi pour vos PersistentVolumes.

  • Définissez le nom de votre jeu de réplicas surdb.

  • Spécifiez les répliques3 pour l'ensemble.

  • Épinglez l'imagemongo à la dernière version au moment de l'écriture:4.1.9.

Collez le code suivant dans le fichier:

~/node_project/mongodb-values.yaml

replicas: 3
port: 27017
replicaSetName: db
podDisruptionBudget: {}
auth:
  enabled: true
  existingKeySecret: keyfilesecret
  existingAdminSecret: mongo-secret
imagePullSecrets: []
installImage:
  repository: unguiculus/mongodb-install
  tag: 0.7
  pullPolicy: Always
copyConfigImage:
  repository: busybox
  tag: 1.29.3
  pullPolicy: Always
image:
  repository: mongo
  tag: 4.1.9
  pullPolicy: Always
extraVars: {}
metrics:
  enabled: false
  image:
    repository: ssalaues/mongodb-exporter
    tag: 0.6.1
    pullPolicy: IfNotPresent
  port: 9216
  path: /metrics
  socketTimeout: 3s
  syncTimeout: 1m
  prometheusServiceDiscovery: true
  resources: {}
podAnnotations: {}
securityContext:
  enabled: true
  runAsUser: 999
  fsGroup: 999
  runAsNonRoot: true
init:
  resources: {}
  timeout: 900
resources: {}
nodeSelector: {}
affinity: {}
tolerations: []
extraLabels: {}
persistentVolume:
  enabled: true
  #storageClass: "-"
  accessModes:
    - ReadWriteOnce
  size: 1Gi
  annotations: {}
serviceAnnotations: {}
terminationGracePeriodSeconds: 30
tls:
  enabled: false
configmap: {}
readinessProbe:
  initialDelaySeconds: 5
  timeoutSeconds: 1
  failureThreshold: 3
  periodSeconds: 10
  successThreshold: 1
livenessProbe:
  initialDelaySeconds: 30
  timeoutSeconds: 5
  failureThreshold: 3
  periodSeconds: 10
  successThreshold: 1

Le paramètrepersistentVolume.storageClass est commenté ici: la suppression du commentaire et la définition de sa valeur sur"-" désactiveraient l'approvisionnement dynamique. Dans notre cas, parce que nous laissons cette valeur indéfinie, le graphique choisira leprovisioner par défaut - dans notre cas,dobs.csi.digitalocean.com.

Notez également lesaccessMode associés à la clépersistentVolume:ReadWriteOnce signifie que le volume provisionné sera en lecture-écriture uniquement par un seul nœud. Veuillez consulter lesdocumentation pour plus d'informations sur les différents modes d'accès.

Pour en savoir plus sur les autres paramètres inclus dans le fichier, consultez lesconfiguration table inclus avec le dépôt.

Enregistrez et fermez le fichier une fois l’édition terminée.

Avant de déployer le graphiquemongodb-replicaset, vous voudrez mettre à jour le repostable avec leshelm repo update command:

helm repo update

Cela obtiendra les dernières informations graphiques du référentielstable.

Enfin, installez le graphique avec la commande suivante:

helm install --name mongo -f mongodb-values.yaml stable/mongodb-replicaset

[.Remarque]##

Note: Avant d'installer un graphique, vous pouvez exécuterhelm install avec les options--dry-run et--debug pour vérifier les manifestes générés pour votre version:

helm install --name your_release_name -f your_values_file.yaml --dry-run --debug your_chart

Notez que nous nommons Helmreleasemongo. Ce nom fera référence à ce déploiement particulier du graphique avec les options de configuration que nous avons spécifiées. Nous avons indiqué ces options en incluant l'indicateur-f et notre fichiermongodb-values.yaml.

Notez également que, comme nous n'avons pas inclus l'indicateur--namespace avechelm install, nos objets de graphique seront créés dans l'espace de nomsdefault.

Une fois que vous avez créé la version, vous verrez une sortie sur son statut, ainsi que des informations sur les objets créés et des instructions pour interagir avec eux:

OutputNAME:   mongo
LAST DEPLOYED: Tue Apr 16 21:51:05 2019
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/ConfigMap
NAME                              DATA  AGE
mongo-mongodb-replicaset-init     1     1s
mongo-mongodb-replicaset-mongodb  1     1s
mongo-mongodb-replicaset-tests    1     0s
...

Vous pouvez maintenant vérifier la création de vos pods avec la commande suivante:

kubectl get pods

Vous verrez les résultats comme suit lors de la création des pods:

OutputNAME                         READY   STATUS     RESTARTS   AGE
mongo-mongodb-replicaset-0   1/1     Running    0          67s
mongo-mongodb-replicaset-1   0/1     Init:0/3   0          8s

Les sortiesREADY etSTATUS ici indiquent que les pods de notre StatefulSet ne sont pas complètement prêts: lesInit Containers associés aux conteneurs du pod sont toujours en cours d'exécution. Étant donné que les membres StatefulSet sontcreated in sequential order, chaque pod du StatefulSet doit êtreRunning etReady avant la création du pod suivant.

Une fois que les pods ont été créés et que tous les conteneurs associés sont en cours d'exécution, vous verrez cette sortie:

OutputNAME                         READY   STATUS    RESTARTS   AGE
mongo-mongodb-replicaset-0   1/1     Running   0          2m33s
mongo-mongodb-replicaset-1   1/1     Running   0          94s
mongo-mongodb-replicaset-2   1/1     Running   0          36s

LesRunningSTATUS indiquent que vos pods sont liés à des nœuds et que les conteneurs associés à ces pods sont en cours d'exécution. READY indique le nombre de conteneurs en cours d'exécution dans un pod. Pour plus d'informations, veuillez consulter lesdocumentation on Pod lifecycles.

[.Remarque]##

Note:
Si vous voyez des phases inattendues dans la colonneSTATUS, n'oubliez pas que vous pouvez dépanner vos pods avec les commandes suivantes:

kubectl describe pods your_pod
kubectl logs your_pod

Chacun des pods de votre StatefulSet a un nom qui combine le nom du StatefulSet avec lesordinal index du pod. Parce que nous avons créé trois répliques, nos membres StatefulSet sont numérotés de 0 à 2, et chacun a unstable DNS entry composé des éléments suivants:$(statefulset-name)-$(ordinal).$(service name).$(namespace).svc.cluster.local.

Dans notre cas, le StatefulSet et lesHeadless Service créés par le graphiquemongodb-replicaset ont les mêmes noms:

kubectl get statefulset
OutputNAME                       READY   AGE
mongo-mongodb-replicaset   3/3     4m2s
kubectl get svc
OutputNAME                              TYPE        CLUSTER-IP   EXTERNAL-IP   PORT(S)     AGE
kubernetes                        ClusterIP   10.245.0.1           443/TCP     42m
mongo-mongodb-replicaset          ClusterIP   None                 27017/TCP   4m35s
mongo-mongodb-replicaset-client   ClusterIP   None                 27017/TCP   4m35s

Cela signifie que le premier membre de notre StatefulSet aura l'entrée DNS suivante:

mongo-mongodb-replicaset-0.mongo-mongodb-replicaset.default.svc.cluster.local

Comme nous avons besoin que notre application se connecte à chaque instance de MongoDB, il est essentiel de disposer de ces informations pour pouvoir communiquer directement avec les pods, plutôt qu'avec le service. Lorsque nous créons notre diagramme Helm d'application personnalisé, nous transmettons les entrées DNS de chaque pod à notre application à l'aide de variables d'environnement.

Vos instances de base de données étant opérationnelles, vous êtes prêt à créer le graphique pour votre application Node.

[[step-4 -—- creation-a-custom-application-chart-and-configuring-parameters]] == Étape 4 - Création d'un graphique d'application personnalisé et configuration des paramètres

Nous allons créer un graphique Helm personnalisé pour notre application Node et modifier les fichiers par défaut du répertoire de graphique standard afin que notre application puisse fonctionner avec le jeu de réplicas que nous venons de créer. Nous allons également créer des fichiers pour définir les objets ConfigMap et Secret pour notre application.

Tout d'abord, créez un nouveau répertoire de graphiques appelénodeapp avec la commande suivante:

helm create nodeapp

Cela créera un répertoire appelénodeapp dans votre dossier~/node_project avec les ressources suivantes:

  • Un fichierChart.yaml contenant des informations de base sur votre graphique.

  • Un fichiervalues.yaml qui vous permet de définir des valeurs de paramètres spécifiques, comme vous l'avez fait avec votre déploiement MongoDB.

  • Un fichier.helmignore avec des modèles de fichiers et de répertoires qui seront ignorés lors de l'empaquetage des graphiques.

  • Un répertoiretemplates/ avec les fichiers de modèle qui généreront les manifestes Kubernetes.

  • Un répertoiretemplates/tests/ pour les fichiers de test.

  • Un répertoirecharts/ pour tous les graphiques dont dépend ce graphique.

Le premier fichier que nous modifierons parmi ces fichiers par défaut estvalues.yaml. Ouvrez ce fichier maintenant:

nano nodeapp/values.yaml

Les valeurs que nous allons définir ici incluent:

  • Le nombre de répliques.

  • L'image d'application que nous voulons utiliser. Dans notre cas, ce sera l'imagenode-replicas que nous avons créée dansStep 1.

  • LesServiceType. Dans ce cas, nous spécifieronsLoadBalancer pour créer un point d'accès à notre application à des fins de test. Comme nous travaillons avec un cluster DigitalOcean Kubernetes, cela créera unDigitalOcean Load Balancer lorsque nous déploierons notre graphique. En production, vous pouvez configurer votre graphique pour utiliserIngress Resources etIngress Controllers pour acheminer le trafic vers vos services.

  • LestargetPort pour spécifier le port sur le pod où notre application sera exposée.

Nous n'entrerons pas de variables d'environnement dans ce fichier. Au lieu de cela, nous créerons des modèles pour les objets ConfigMap et Secret et ajouterons ces valeurs à notre manifeste de déploiement d'application, situé à~/node_project/nodeapp/templates/deployment.yaml.

Configurez les valeurs suivantes dans le fichiervalues.yaml:

~/node_project/nodeapp/values.yaml

# Default values for nodeapp.
# This is a YAML-formatted file.
# Declare variables to be passed into your templates.

replicaCount: 3

image:
  repository: your_dockerhub_username/node-replicas
  tag: latest
  pullPolicy: IfNotPresent

nameOverride: ""
fullnameOverride: ""

service:
  type: LoadBalancer
  port: 80
  targetPort: 8080
...

Enregistrez et fermez le fichier une fois l’édition terminée.

Ensuite, ouvrez un fichiersecret.yaml dans le répertoirenodeapp/templates:

nano nodeapp/templates/secret.yaml

Dans ce fichier, ajoutez des valeurs pour vos constantes d'applicationMONGO_USERNAME etMONGO_PASSWORD. Ce sont les constantes auxquelles votre application s'attend à avoir accès au moment de l'exécution, comme spécifié dansdb.js, votre fichier de connexion à la base de données. Lorsque vous ajoutez les valeurs de ces constantes, n'oubliez pas d'utiliser les valeurs base64 -encoded que vous avez utilisées précédemment dansStep 2 lors de la création de votre objetmongo-secret. Si vous devez recréer ces valeurs, vous pouvez revenir à l'étape 2 et réexécuter les commandes appropriées.

Ajoutez le code suivant au fichier:

~/node_project/nodeapp/templates/secret.yaml

apiVersion: v1
kind: Secret
metadata:
  name: {{ .Release.Name }}-auth
data:
  MONGO_USERNAME: your_encoded_username
  MONGO_PASSWORD: your_encoded_password

Le nom de cet objet Secret dépendra du nom de votre version de Helm, que vous spécifierez lors du déploiement du graphique d'application.

Enregistrez et fermez le fichier lorsque vous avez terminé.

Ensuite, ouvrez un fichier pour créer un ConfigMap pour votre application:

nano nodeapp/templates/configmap.yaml

Dans ce fichier, nous définirons les variables restantes attendues par notre application:MONGO_HOSTNAME,MONGO_PORT,MONGO_DB etMONGO_REPLICASET. Notre variableMONGO_HOSTNAME inclura l'entrée DNS pour l'instanceeach dans notre jeu de répliques, puisque c'est ce que lesMongoDB connection URI requires.

Selon lesKubernetes documentation, lorsqu'une application implémente des contrôles de vivacité et de disponibilité, lesSRV records doivent être utilisés lors de la connexion aux pods. Comme indiqué dansStep 3, nos enregistrements Pod SRV suivent ce modèle:$(statefulset-name)-$(ordinal).$(service name).$(namespace).svc.cluster.local. Puisque notre MongoDB StatefulSet implémente des contrôles de vivacité et de préparation, nous devons utiliser ces identificateurs stables lors de la définition des valeurs de la variableMONGO_HOSTNAME.

Ajoutez le code suivant au fichier pour définir les variablesMONGO_HOSTNAME,MONGO_PORT,MONGO_DB etMONGO_REPLICASET. Vous êtes libre d'utiliser un autre nom pour votre base de donnéesMONGO_DB, mais vos valeursMONGO_HOSTNAME etMONGO_REPLICASET doivent être écrites telles qu'elles apparaissent ici:

~/node_project/nodeapp/templates/configmap.yaml

apiVersion: v1
kind: ConfigMap
metadata:
  name: {{ .Release.Name }}-config
data:
  MONGO_HOSTNAME: "mongo-mongodb-replicaset-0.mongo-mongodb-replicaset.default.svc.cluster.local,mongo-mongodb-replicaset-1.mongo-mongodb-replicaset.default.svc.cluster.local,mongo-mongodb-replicaset-2.mongo-mongodb-replicaset.default.svc.cluster.local"
  MONGO_PORT: "27017"
  MONGO_DB: "sharkinfo"
  MONGO_REPLICASET: "db"

Comme nous avons déjà créé l'objet StatefulSet et le jeu de réplicas, les noms d'hôte répertoriés ici doivent être répertoriés dans votre fichier exactement comme ils apparaissent dans cet exemple. Si vous détruisez ces objets et renommez votre version de MongoDB Helm, vous devrez alors réviser les valeurs incluses dans cette carte de configuration. Il en va de même pourMONGO_REPLICASET, puisque nous avons spécifié le nom du jeu de réplicas avec notre version MongoDB.

Notez également que les valeurs répertoriées ici sont indiquées, c'est-à-direthe expectation for environment variables in Helm.

Enregistrez et fermez le fichier une fois l’édition terminée.

Une fois vos valeurs de paramètre de graphique définies et vos manifestes Secret et ConfigMap créés, vous pouvez modifier le modèle de déploiement de l'application pour utiliser vos variables d'environnement.

[[step-5 -—- integrating-environment-variables-into-your-helm-deployment]] == Étape 5 - Intégration des variables d'environnement dans votre déploiement Helm

Avec les fichiers de notre application Secret et ConfigMap en place, nous devrons nous assurer que notre application de déploiement peut utiliser ces valeurs. Nous allons également personnaliser lesliveness and readiness probes qui sont déjà définis dans le manifeste de déploiement.

Ouvrez le modèle de déploiement de l'application pour le modifier:

nano nodeapp/templates/deployment.yaml

Bien qu'il s'agisse d'un fichier YAML, les modèles Helm utilisent une syntaxe différente de celle des fichiers Kubernetes YAML standard afin de générer des manifestes. Pour plus d'informations sur les modèles, consultez lesHelm documentation.

Dans le fichier, ajoutez d'abord une cléenv aux spécifications de votre conteneur d'application, sous la cléimagePullPolicy et au-dessus deports:

~/node_project/nodeapp/templates/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
...
  spec:
    containers:
      - name: {{ .Chart.Name }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        env:
        ports:

Ensuite, ajoutez les clés suivantes à la liste des variablesenv:

~/node_project/nodeapp/templates/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
...
  spec:
    containers:
      - name: {{ .Chart.Name }}
        image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}"
        imagePullPolicy: {{ .Values.image.pullPolicy }}
        env:
        - name: MONGO_USERNAME
          valueFrom:
            secretKeyRef:
              key: MONGO_USERNAME
              name: {{ .Release.Name }}-auth
        - name: MONGO_PASSWORD
          valueFrom:
            secretKeyRef:
              key: MONGO_PASSWORD
              name: {{ .Release.Name }}-auth
        - name: MONGO_HOSTNAME
          valueFrom:
            configMapKeyRef:
              key: MONGO_HOSTNAME
              name: {{ .Release.Name }}-config
        - name: MONGO_PORT
          valueFrom:
            configMapKeyRef:
              key: MONGO_PORT
              name: {{ .Release.Name }}-config
        - name: MONGO_DB
          valueFrom:
            configMapKeyRef:
              key: MONGO_DB
              name: {{ .Release.Name }}-config
        - name: MONGO_REPLICASET
          valueFrom:
            configMapKeyRef:
              key: MONGO_REPLICASET
              name: {{ .Release.Name }}-config

Chaque variable comprend une référence à sa valeur, définie soit par unsecretKeyRef key, dans le cas des valeurs secrètes, soit parconfigMapKeyRef pour les valeurs ConfigMap. Ces clés pointent vers les fichiers Secret et ConfigMap que nous avons créés à l'étape précédente.

Ensuite, sous la cléports, modifiez la définition decontainerPort pour spécifier le port sur le conteneur où notre application sera exposée:

~/node_project/nodeapp/templates/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
...
  spec:
    containers:
    ...
      env:
    ...
      ports:
        - name: http
          containerPort: 8080
          protocol: TCP
      ...

Ensuite, modifions par défaut les contrôles de vivacité et de préparation inclus dans ce manifeste de déploiement. Ces vérifications garantissent que nos applications sont en cours d’exécution et prêtes à servir le trafic:

  • Les sondes de disponibilité évaluent si un pod est prêt à servir du trafic, en arrêtant toutes les demandes adressées au pod jusqu'à ce que les vérifications aboutissent.

  • Les sondes Liveness vérifient le comportement de base d'une application pour déterminer si l'application du conteneur est en cours d'exécution et se comporte comme prévu. Si une sonde d'activité survit, Kubernetes redémarre le conteneur.

Pour plus d'informations sur les deux, consultez lesrelevant discussion dansArchitecting Applications for Kubernetes.

Dans notre cas, nous allons construire sur leshttpGet request que Helm a fournis par défaut et tester si notre application accepte ou non les requêtes sur le point de terminaison/sharks. Leskubelet service exécuteront la sonde en envoyant une requête GET au serveur Node s'exécutant dans le conteneur du pod d'application et en écoutant sur le port8080. Si le code d'état de la réponse est compris entre 200 et 400, leskubeletconcluront que le conteneur est sain. Sinon, dans le cas d'un état 400 ou 500,kubelet arrêtera le trafic vers le conteneur, dans le cas de la sonde de disponibilité, ou redémarrera le conteneur, dans le cas de la sonde de vivacité.

Ajoutez la modification suivante auxpath indiqués pour les sondes de vivacité et de préparation:

~/node_project/nodeapp/templates/deployment.yaml

apiVersion: apps/v1
kind: Deployment
metadata:
...
  spec:
    containers:
    ...
      env:
    ...
      ports:
        - name: http
          containerPort: 8080
          protocol: TCP
      livenessProbe:
        httpGet:
          path: /sharks
          port: http
      readinessProbe:
        httpGet:
          path: /sharks
          port: http

Enregistrez et fermez le fichier une fois l’édition terminée.

Vous êtes maintenant prêt à créer votre version de l'application avec Helm. Exécutez leshelm install command suivants, qui incluent le nom de la version et l'emplacement du répertoire du graphique:

helm install --name nodejs ./nodeapp

N'oubliez pas que vous pouvez d'abord exécuterhelm install avec les options--dry-run et--debug, comme indiqué dansStep 3, pour vérifier les manifestes générés pour votre version.

Encore une fois, comme nous n'incluons pas l'indicateur--namespace avechelm install, nos objets de graphique seront créés dans l'espace de nomsdefault.

Vous verrez la sortie suivante indiquant que votre version a été créée:

OutputNAME:   nodejs
LAST DEPLOYED: Wed Apr 17 18:10:29 2019
NAMESPACE: default
STATUS: DEPLOYED

RESOURCES:
==> v1/ConfigMap
NAME           DATA  AGE
nodejs-config  4     1s

==> v1/Deployment
NAME            READY  UP-TO-DATE  AVAILABLE  AGE
nodejs-nodeapp  0/3    3           0          1s

...

Là encore, le résultat indiquera l'état de la version, ainsi que des informations sur les objets créés et sur la manière dont vous pouvez interagir avec eux.

Vérifiez l'état de vos pods:

kubectl get pods
OutputNAME                              READY   STATUS    RESTARTS   AGE
mongo-mongodb-replicaset-0        1/1     Running   0          57m
mongo-mongodb-replicaset-1        1/1     Running   0          56m
mongo-mongodb-replicaset-2        1/1     Running   0          55m
nodejs-nodeapp-577df49dcc-b5fq5   1/1     Running   0          117s
nodejs-nodeapp-577df49dcc-bkk66   1/1     Running   0          117s
nodejs-nodeapp-577df49dcc-lpmt2   1/1     Running   0          117s

Une fois que vos pods sont opérationnels, vérifiez vos services:

kubectl get svc
OutputNAME                              TYPE           CLUSTER-IP     EXTERNAL-IP       PORT(S)        AGE
kubernetes                        ClusterIP      10.245.0.1                 443/TCP        96m
mongo-mongodb-replicaset          ClusterIP      None                       27017/TCP      58m
mongo-mongodb-replicaset-client   ClusterIP      None                       27017/TCP      58m
nodejs-nodeapp                    LoadBalancer   10.245.33.46   your_lb_ip        80:31518/TCP   3m22s

LeEXTERNAL_IP associé au servicenodejs-nodeapp est l'adresse IP à laquelle vous pouvez accéder à l'application depuis l'extérieur du cluster. Si vous voyez un état<pending> dans la colonneEXTERNAL_IP, cela signifie que votre équilibreur de charge est toujours en cours de création.

Une fois que vous voyez une adresse IP dans cette colonne, accédez-y dans votre navigateur:http://your_lb_ip.

Vous devriez voir la page de destination suivante:

Application Landing Page

Maintenant que votre application répliquée fonctionne, ajoutons quelques données de test pour vérifier que la réplication fonctionne entre les membres du jeu de réplicas.

[[step-6 -—- testing-mongodb-replication]] == Étape 6 - Test de la réplication MongoDB

Avec notre application en cours d'exécution et accessible via une adresse IP externe, nous pouvons ajouter des données de test et nous assurer que celles-ci sont répliquées entre les membres de notre jeu de réplicas MongoDB.

Tout d’abord, assurez-vous d’avoir navigué sur votre navigateur jusqu’à la page de destination de l’application:

Application Landing Page

Cliquez sur le boutonGet Shark Info. Vous verrez une page avec un formulaire de saisie où vous pouvez entrer un nom de requin et une description du caractère général de ce requin:

Shark Info Form

Dans le formulaire, ajoutez un premier requin de votre choix. Pour démontrer, nous ajouteronsMegalodon Shark au champShark Name etAncient au champShark Character:

Filled Shark Form

Cliquez sur le boutonSubmit. Vous verrez une page contenant les informations sur ce requin qui vous seront renvoyées:

Shark Output

Revenez maintenant au formulaire d'informations sur les requins en cliquant surSharks dans la barre de navigation supérieure:

Shark Info Form

Entrez un nouveau requin de votre choix. Nous allons utiliserWhale Shark etLarge:

Enter New Shark

Une fois que vous cliquez surSubmit, vous verrez que le nouveau requin a été ajouté à la collection de requins dans votre base de données:

Complete Shark Collection

Vérifions que les données que nous avons entrées ont été répliquées entre les membres principaux et secondaires de notre jeu de réplicas.

Obtenez une liste de vos pods:

kubectl get pods
OutputNAME                              READY   STATUS    RESTARTS   AGE
mongo-mongodb-replicaset-0        1/1     Running   0          74m
mongo-mongodb-replicaset-1        1/1     Running   0          73m
mongo-mongodb-replicaset-2        1/1     Running   0          72m
nodejs-nodeapp-577df49dcc-b5fq5   1/1     Running   0          5m4s
nodejs-nodeapp-577df49dcc-bkk66   1/1     Running   0          5m4s
nodejs-nodeapp-577df49dcc-lpmt2   1/1     Running   0          5m4s

Pour accéder auxmongo shell sur vos pods, vous pouvez utiliser leskubectl exec command et le nom d'utilisateur que vous avez utilisé pour créer vosmongo-secret dansStep 2. Accédez au shellmongo sur le premier pod du StatefulSet avec la commande suivante:

kubectl exec -it mongo-mongodb-replicaset-0 -- mongo -u your_database_username -p --authenticationDatabase admin

Lorsque vous y êtes invité, entrez le mot de passe associé à ce nom d'utilisateur:

OutputMongoDB shell version v4.1.9
Enter password:

Vous serez déposé dans un shell administratif:

OutputMongoDB server version: 4.1.9
Welcome to the MongoDB shell.
...

db:PRIMARY>

Bien que l'invite elle-même inclue ces informations, vous pouvez vérifier manuellement quel membre du jeu de réplicas est le principal avec lesrs.isMaster() method:

rs.isMaster()

Vous verrez une sortie comme celle-ci, indiquant le nom d’hôte du principal:

Outputdb:PRIMARY> rs.isMaster()
{
        "hosts" : [
                "mongo-mongodb-replicaset-0.mongo-mongodb-replicaset.default.svc.cluster.local:27017",
                "mongo-mongodb-replicaset-1.mongo-mongodb-replicaset.default.svc.cluster.local:27017",
                "mongo-mongodb-replicaset-2.mongo-mongodb-replicaset.default.svc.cluster.local:27017"
        ],
        ...
        "primary" : "mongo-mongodb-replicaset-0.mongo-mongodb-replicaset.default.svc.cluster.local:27017",
        ...

Ensuite, passez à votre base de donnéessharkinfo:

use sharkinfo
Outputswitched to db sharkinfo

Répertoriez les collections dans la base de données:

show collections
Outputsharks

Sortir les documents de la collection:

db.sharks.find()

Vous verrez la sortie suivante:

Output{ "_id" : ObjectId("5cb7702c9111a5451c6dc8bb"), "name" : "Megalodon Shark", "character" : "Ancient", "__v" : 0 }
{ "_id" : ObjectId("5cb77054fcdbf563f3b47365"), "name" : "Whale Shark", "character" : "Large", "__v" : 0 }

Quittez le shell MongoDB:

exit

Maintenant que nous avons vérifié les données de notre primaire, vérifions qu’elles sont répliquées sur un secondaire. kubectl exec enmongo-mongodb-replicaset-1 avec la commande suivante:

kubectl exec -it mongo-mongodb-replicaset-1 -- mongo -u your_database_username -p --authenticationDatabase admin

Une fois dans le shell administratif, nous devrons utiliser la méthodedb.setSlaveOk() pour permettre les opérations de lecture à partir de l'instance secondaire:

db.setSlaveOk(1)

Basculez vers la base de donnéessharkinfo:

use sharkinfo
Outputswitched to db sharkinfo

Autorisez l'opération de lecture des documents de la collectionsharks:

db.setSlaveOk(1)

Sortir les documents de la collection:

db.sharks.find()

Vous devriez maintenant voir les mêmes informations que lorsque vous avez exécuté cette méthode sur votre instance principale:

Outputdb:SECONDARY> db.sharks.find()
{ "_id" : ObjectId("5cb7702c9111a5451c6dc8bb"), "name" : "Megalodon Shark", "character" : "Ancient", "__v" : 0 }
{ "_id" : ObjectId("5cb77054fcdbf563f3b47365"), "name" : "Whale Shark", "character" : "Large", "__v" : 0 }

Cette sortie confirme que les données de votre application sont en cours de réplication entre les membres de votre jeu de réplicas.

Conclusion

Vous avez maintenant déployé une application d'informations de requin répliquée et hautement disponible sur un cluster Kubernetes à l'aide de diagrammes Helm. Cette application de démonstration et le flux de travail décrit dans ce didacticiel peuvent servir de point de départ lorsque vous créez des graphiques personnalisés pour votre application et tirez parti du référentielstable et desother chart repositories de Helm.

Lorsque vous vous dirigez vers la production, envisagez de mettre en œuvre les éléments suivants:

Related