Souplesse et définition de besoins
L'histoire d'un conteneur se lit de la première à la dernière page, et des fois ça se termine plus tôt que prévu. Un conteneur est rarement seul, son interaction avec ses camarades est tout aussi importante. Dans cet article nous vous proposons d'explorer l'ensemble du cycle de vie d'un groupe de conteneurs.
Pourquoi les conteneurs ?
Les conteneurs permettent de bien ranger ses applications, sans mettre le bazar tout autour, en laissant une grande liberté sur les logiciels et leurs versions.
La pile logicielle sera la même entre le dev, l'intégration continue, la préprod et la prod.
Pour l'hébergement, les conteneurs offrent la même souplesse : ils peuvent être déployés dans différents contextes : du gros nuage tout géré, à l'hébergement premium dans la DMZ du client.
En choisissant la conteneurisation, vous facilitez le développement, le déploiement, et vous garder la possibilité de choisir un hébergement en profitant des ses spécificités, sans pour autant vous faire cadenasser.
Déploiement
Dans la vraie vie, on ne déploie pas des conteneurs, mais des grappes de conteneurs. Pour l'instant, c'est peu normalisé : il y a Compose , le standard de fait, les manifests de Kubernetes (qui sont de bien bas niveau), Helm , qui est lié à Kubernetes, et des pistes du coté du CNCF pour normaliser un peu tout ça.
Comme tout est web, on a besoin de définir les routes HTTP vers les différents services de notre grappe, c'est intimement lié à la définition de ladite grappe.
Les développeurs organisent leurs services, en ajoutent, en enlèvent, les mettent à jour en respectant tranquillement leur cycle de vie.
Hébergement
À partir de la description des services, l'hébergeur peut faire des choix et des évolutions, liées à la sécurité, aux incidents et aux problématiques de montée en charge. Tout ceci se passe au fil de l'eau, enfin des incidents.
Plain old Docker
Selon l'échelle où l'on travaille, et la maturité de son application pour gérer la distribution, du "bon vieux Docker" est tout à fait pertinent pour héberger votre application. Kubernetes, Nomad , Swarm, ça reste du Docker, même s'il peut y avoir des pinaillages d'implémentation en tapant sur containerd , la couche logicielle juste en dessous de Docker (et juste au-dessus de runc ).
Surveiller
Comme c'est l'application qui définit sa topologie et réclame des services, ça va bouger au fil du temps, que ce soit les mises à jour ou l'arrivée/départ des services.
Docker fournit une api pour suivre le flot d'évènements , qui est utilisée par la commande docker events
.
Ressources
Telegraf et Prometheus savent surveiller la consommation des conteneurs, par contre, attention, ils sont assez naïfs et surveillent les conteneurs un à un, sans notion de projet. Comme les conteneurs sont basés sur des fonctionnalités de Linux, il suffit de surveiller ses couches basses pour avoir un joli rangement : les cgroups sont fait pour ça.
Monitoring
Docker propose la notion de healthcheck , une commande à lancer sur ledit conteneur pour dire s'il est en vie. C'est une fausse bonne idée. Un conteneur doit rester léger, et il n'a pas à embarquer le client nécessaire pour valider le bon fonctionnement du service rendu.
La notion de Liveness est plus saine, et on la retrouve dans Træfik avec son Health Check . Le conteneur n'a pas à fournir le code pour vérifier qu'il est en vie, il doit juste déclarer une URL pour le faire. URL qui sera utilisée par le répartiteur de charge, et par l'outil de suivi de performance (Telegraf et ses amis).
Les mesures métiers sont un parfait complément aux mesures systèmes (pour estimer un prix au kilo). Pour ça, il faut des endpoints Prometheus si on a du code asynchrone, ou utiliser du statsd qui est maintenant une norme aux multiples implémentations.
Pour les services distribués, et un suivi des performances sur la chaine de services (et pas chacun isolement), il faut utiliser du tracing , du simple Jaeger ou suivre les tentatives de normalisation de Google avec son opentelemetry .
Journaux
Docker permet de router le flot de journaux de chaque conteneur, mais on n'a pas la notion de projet. Par contre, le routage vers un service spécialisé est gérable par Docker lui-même, le CNCF recommande Fluentbit , mais il en existe d'autres.
Loguer dans STDOUT, tel que le recommande le Twelve factors est facile, mais rien n'égale la qualité du log qualifié et centralisé (le protocole Fluentbit pour causer à un ELK par exemple, ou le prometteur Loki ).
Pour les incidents, tous les logs du monde ne pourront pas remplacer la gestion de contexte et de dédoublonnage de Sentry .
Crash et cycle de vie
Pour le cycle de vie, pour savoir si un serveur se vautre, s'il est automatiquement relancé, si Docker le déclare indémmarable, c'est plus flou. Sur place, l'information est disponible, docker inspect
fonctionne très bien sur un conteneur éteint. Donc, rien n'empêche d'avoir un service pour ranger tout ça dans l'inévitable Sentry.
L'API events
de Docker, est trop bas niveau pour être facilement utilisable dans différents services, il est pratique d'avoir une bibliothèque pour disposer d'un motif visiteur : docker-visitor . Il maintient la liste des conteneurs en place, et suit les modifications en déclenchant un évènement à chaque changement.
Avec ça, il est possible de développer ShepherD , qui va faire du ménage en supprimant les conteneurs éteints après un temps de carence, mais surtout surveiller les conteneurs qui ne s'éteignent pas correctement (avec un exit code différent de 0, la convention UNIX, ou marqué comme victime de l'OOM killer). Ce berger va remonter les éléments suivants pour chaque conteneur crashé:
- Nom, version,
labels
du conteneur - L'état du conteneur fraichement décédé
- Les dernières lignes de ses logs
- Une sélection de compteurs de consommation de ressources, tel que remonté par Cgroup
Toutes ces informations sont envoyées dans Sentry, qui va, comme d'habitude, ranger et dédoublonner, pour pouvoir corriger sereinement, sans aller tripoter un des noeuds de la prod. Le pire du pire étant d'attendre devant son écran l'arrivée du prochain incident avec son contexte si unique.
Autonomie et découverte
En se basant sur un mélange de déclaratif et de suivi d'évènements, il est possible d'avoir en même temps une liberté sur la définition des applications, et d'avoir systématiquement les outils nécessaires aux suivis de l'hébergement et aux corrections rapides, pour ne pas briser l'élan des cycles courts de micro déploiement.