Rapport Test Infrastructures NixOS 2021-2022

=Rappel du sujet et cahier des charges=

L’objectif est d’expérimenter et de manipuler une technologie récente : NixOS et le projet de recherche NixOS-Compose. Nix est un outil de gestion de paquets (bibliothèques, morceau logiciel offrant certaines fonctionnalités), et NixOS est un système d'exploitation Linux qui utilise Nix dans son architecture. Nous parlerons plus en détails des différentes technologiques manipulées dans la prochaine partie.

Nos expérimentations ont consistées à déployer trois projets différents : Kubernetes, ELK et Hadoop en utilisant l'outil NixOS-Compose. La partie la plus importante n'étant pas de déployer une version aboutie et complête pour chacun de projets mais de documenter nos expériences pour fournir des retours utilisateurs permettant l'amélioration de NixOS-Compose.

=Technologies employées=

Nix
Nix est un gestionnaire de paquets et un langage fonctionnel qui se différencie de l'approche classique avec sa grande reproductibilité qu'il trouve incompatible avec le Filesystem Hierarchy Standard. Il dénonce l'enfer des dépendances que l'on retrouve avec cette approche où l'on ne peut pas déterminer les versions utilisées. Nix repose sur son store, où il stocke toutes les dérivations pour chaque paquet. Ces dérivations contiennent des informations sur toutes les dépendances (d'autres dérivations) et les instructions de build. Le nom de la dérivation indique le nom du paquet et un hash qui la rend unique mais surtout qui l'identifie : une même dérivation produira toujours la même sortie.

Avec cette approche, Nix permet plusieurs choses, notamment :
 * La reproductibilité due au déterminisme des dérivations
 * La possibilité d'utiliser plusieurs versions d'un même paquet en parallèle
 * Comme le nom de la dérivation l'identifie, il est possible de mettre en cache la sortie et la récupérer sans avoir à la reconstruire

Nixpkgs est un répertoire en ligne contenant de nombreux paquets (80 000 actuellement) construits à partir de dérivations fournies par la communauté et accessibles à tous.

NixOS
NixOS est une distribution GNU/Linux reposant sur Nix en tant que gestionnaire de paquets mais également de gestionnaire de configuration. L'ensemble du système et toutes les configurations sont considérés comme des dérivations. Cela permet entre autres de faire des restorations du système à des versions précédentes simplement, chaque modification du système occasionne la création d'une nouvelle version atomique. Par ailleurs, le système d'exploitation hérite ainsi de la propriété déterministe et reproductible que Nix offre.

NixOS-test est une librairie de test qui permet, à partir d'un ensemble de fichiers de configuration Nix, de fournir une interface python pour manipuler ces configurations sur une/des machines virtuelles avec QEMU.

NixOS-Compose
NixOS-Compose est un projet de l’équipe Datamove qui étend l’utilisation de NixOS vers d’autres supports que les machines virtuelles, comme notamment la plateforme Grid'5000 et des solutions de conteneurs comme Docker.

Kubernetes
Kubernetes est un orchestrateur de conteneurs permettant de déployer, mettre à l'échelle et surveiller des applications conteneurisées sur un cluster de machines. Développé en Go et rendu open source en 2015 par Google inspiré de leur solution privée Borg, Kubernetes est maintenant l'outil central du monde du DevOps dans l'industrie. Il apporte une couche d'abstraction au dessus d'un datacenter, dont la mise en place a également été facilitée par le cloud, pour fournir une plateforme de déploiement fortement disponible aux développeurs. Kubernetes dispose également d'un large écosystème d'outils et plugins améliorant différents aspects de son utilisation : routage, monitoring, sécurité, gitops, déploiements (vert/bleu, canary...), serverless etc. En cette qualité, Kubernetes est une plateforme de choix dans le cadre d'expériences nécessitant notamment un certain nombre de services ou applications, comme dans le cas d'architectures microservices par exemple. De plus, malgré ses nombreux atouts, Kubernetes est une solution souvent difficile et longue à mettre initialement en place pour cause d'une configuration complexe liée à l'architecture microservice de la plateforme elle-même. (Il faut reconnaître qu'avec le cloud il est maintenant très simple de déployer un cluster Kubernetes, Terraform est notamment un concurrent potentiel de NixOS-Compose)

Dans le cadre de notre projet, être en mesure de fournir un cluster Kubernetes de la taille voulue, simplement, rapidemment et de manière reproductible, est un objectif très intéressant, non seulement pour l'aspect apprentissage mais également pour son utilisation dans le contextes d'expériences scientifiques avec NixOS-Compose. Kubernetes est en lui même un solution qui permet une forte reproductibilité au niveau des déploiements internes, mais c'est la phase de déploiement des machines et de bootstrap du cluster qui manque cette qualité, et c'est là que nous nous positionnons.

ELK
"ELK" est l'acronyme de trois projets open source : Elasticsearch, Logstash et Kibana.

Elasticsearch
Elasticsearch est un outil de recherche et d'analyse de données fonctionnant de manière distribuée et basé sur [Apache Lucene](https://lucene.apache.org/). Créé par Shay Banon en 2004, au fil des années, Elasticsearch n'a cessé d'évoluer et aujourd'hui c'est l'outil de référence pour réaliser une recherche performante sur une large quantité de données.

Technologiquement parlant, il s'agit d'une base de données programmée en Java et spécialisée dans la recherche et l'indexation de documents. Si Elasticsearch est aussi performant c'est grâce à son fonctionnement en mode distribué. La tâche de recherche est exécutée en parallèle par plusieurs nœuds Elasticsearch, ce qui améliore la réactivité du système. Elasticsearch a aussi la force d'être facilement configurable et mis à l'échelle.

Logstash
Logstash est un outil écrit en Java et en Ruby permettant de **centraliser des traces** provenant de plusieurs systèmes, de les analyser et de les stocker. Conceptuellement, Logstash peut être vu comme un "pipe" où les données rentrent d'un bout, et sont traitées avant de ressortir de l'autre bout. Logstash est plus qu'un simple "pipe" puisqu'il peut prendre une multitude de sources différentes en entrées et renvoyées les données traitées vers différentes sorties. Il sert généralement à filtrer/analyser des messages avant de les envoyer à Elasticsearch qui va, lui, se charger de les stocker et de les indexer.

Kibana
Kibana est un outil permettant la visualisation de données écrit en JavaScript est la dernière composante majeure de la stack ELK. Il est similaire à d'autres outils de visualisation tel que [Grafana](https://grafana.com/), mais a la particularité d'être spécialisé pour une utilisation au sein de la stack ELK. Le rôle de Kibana est donc de récupérer les données indexées par Elasticsearch et de les rendre visuellement exploitables pour un humain.

Beats
Bien que la stack ELK soit l'acronyme des trois projets majeurs dont nous avons parlé précédemment, ELK est consistué d'un autre projet nommé Beats. Il y a d'ailleurs quelques discussions autour du renommage de la stack ELK en stack BELK pour inclure le projet Beats. Beats est une plateforme réunissant une multitude de petits outils permettant d'expédier des données vers Logstash ou Elasticsearch. Chaque outil vise un type de données spécifiques. On retrouvera par exemple l'outil Filebeat pour l'expédition de traces systèmes, Metricbeat pour les métriques, Packetbeat pour le réseau ou encore Heartbeat pour le monitoring. Cette liste est non exhaustive, il existe plein d'autres beats, chacun spécialisé pour des données de nature différente.

Hadoop
Hadoop est un framework open source Java destiné à faciliter la création d'applications distribuées (au niveau du stockage des données et de leur traitement) et scalables permettant aux applications de travailler avec des milliers de nœuds et des masses importantes de données. Ainsi chaque nœud est constitué de machines standard regroupées en grappe. Hadoop fonctionne avec de nombreux modules ou services conçus selon l'idée que les pannes matérielles sont fréquentes et qu'en conséquence elles doivent être gérées automatiquement par le framework. Cet aspect de redondance n'est pas traité dans ce projet.

=Architectures techniques=

Kubernetes
L'architecture de Kubernetes est distribuée sous forme de microservices avec plusieurs composants, chacun responsable d'une certaine tâche pour contrôler le cluster et les applications qui y vivent. Tout d'abord, les composants sont à séparer en deux groupes: le control plane, tête pensante du cluster, et les composants des nodes, responsables de faire fonctionner les conteneurs. Une machine est dite nœud maître dès lors qu'elle est membre du control plane (elle exécute les composants du control plane, seule ou en communication avec les autres maîtres). Une machine peut à la fois être maître et exécuter des conteneurs (control plane et *Node*), ce n'est toutefois pas recommandé au vu de l'importance du rôle du control plane.



Source : https://kubernetes.io/docs/concepts/overview/components

Control plane
Le control plane est un ensemble de composants responsable du bon fonctionnement du cluster. Ces composants sont présents sur chaque nœud maître du cluster. Dans le cas d'un cluster à haute disponibilité (plusieurs maîtres), ces composants fonctionnent de manière distribuée, et nécessitent un load balancer.

Le composant principal est l'apiserver, qui est donc une API permettant la communication entre les différents composants. L'apiserver est le seul composant avec qui les autres composants communiquent. Ensuite le controller manager, regroupe les différents contrôleurs dont le rôle est de gérer les resources qui leur corresponde (le contrôleur des *Pod* veille au bon fonctionnement des Pod, pareil pour les ReplicasSet, Endpoint, Node...). Le scheduler est responsable de l'attribution des resources (machines) aux applications (Pod, Deployment...) selon les disponibilités et besoins. Enfin, etcd est une base de données distribuée de configuration qui conserve l'état du cluster. C'est une solution tiers et elle peut être exécutée sur un cluster à part des nœuds maître.

Node
Pour Kubernetes, un Node (ou nœud en français) est l'abstraction d'une machine (réelle ou virtuelle). Chaque machine représentant un Node doit faire tourner trois services: le kubelet, le kube-proxy et un environnement d'exécution de conteneurs.

Le kubelet est véritablement le responsable des conteneurs en pratique, il est le contremaître obéissant au control plane, chargé de faire appliquer ses directives. Le kubelet ordonne à l'environnement d'exécution de conteneurs et fait ses rapports de situation au control plane. Le kube-proxy est chargé de mettre en place les règles de réseau (iptables ou IPVS) pour veiller au bon fonctionnement notamment des Service et Endpoint. Enfin, l'environnement d'exécution de conteneurs peut être n'importe quel solution respectant la CRI (container runtime interface) comme containerd ou CRI-O.

Non-obligatoire mais également souvent présent est un plugin de CNI (container network interface) qui met en place le plan de réseau exigé par Kubernetes (à savoir un réseau où les Pod disposent d'une adresse IP et peuvent communiquer entre eux) à ne pas confondre avec le réseau connectant les machines entre elles. On peut citer notamment Calico, Weave et celui qui est utilisé dans notre projet est Flannel (moins puissant). Parmi les addons on retrouve également un serveur DNS (nécessaire au bon fonctionnement des Services), anciennement kube-dns et maintenant plutôt coredns.

ELK
En ce qui concerne ELK, il ne s'agit non pas d'un système ou d'un outil en lui-même mais de la collaboration d'une multitude d'outils open source ayant chacun leurs particularités et un fonctionnement qui leur est propre. Pour visualiser plus aisément l'intéraction entre les différentes composantes de la stack ELK, on pourra s'intéresser à l'exemple suivant:



Source : https://fr.wikipedia.org/wiki/Logstash

Dans l'exemple ci-dessus, on distingue trois sources indépendantes: MediaWiki, des services Node.js et Hadoop. Chacune des trois sources envoie des données à une instance différente de Logstash. Les instances de Logstash ne communiquent pas entre elles, toutefois, une fois le traitement des données effectué, chaque instance envoie ses données à un nœud Elasticsearch. Dans le schéma ci-dessus, les trois nœuds font partie d'un même cluster, ce qui permet donc la mise en commun de l'intégralité des données pouvant ensuite être visualisées via Kibana.

Hadoop
Hadoop est un environement distribué de par son stockage mais également son traitement de données. C'est une suite de solution open source pour le big data. The goal is to instanciate the different kind of nodes from one of the two possible implementation below, and make them communicate to run a job on the cluster.





Source : https://www.geeksforgeeks.org/hadoop-introduction

=Réalisations techniques=

Kubernetes
L'expérience avec Kubernetes consiste avant tout à déployer un cluster Kubernetes fonctionnel, utilisable comme n'importe quel autre cluster. Pour cela nous nous reposons donc tout d'abord sur la dérivation de Kubernetes sur nixpkgs. Ensuite nous utilisons d'autres outils comme Helm et Istio pour enrichir l'expérience.

La dérivations de Kubernetes propose la version 1.21.6, avec certains aspects de configuration qui sont cependant déprécié (notamment au niveau des ports uti lisés et des flags devenus déconseillés) car non mis à jour depuis 4 ans. La configuration de cette dérivation peut se faire de deux manière: en précisant la configuration de tous les composants (cf. partie II), ou en précisant uniquement le rôle de la machine. Avec la première approche non pouvons avoir un contrôle complet sur la configuration alors que dans le second tout est plus abstrait. En revanche la deuxième manière est plus simple et plus claire. Nous avons opté pour la seconde en ajoutant un certain nombre d'options supplémentaires.

La composition de l'expérience commence avec la description des machines ainsi que leur rôle dans le cluster. Nous utilisons généralement un nœud maître et deux nœuds de travail, sachant qu'il n'est pas possible actuellement de déployer un cluster à haute disponibilité dont le bootstrap des certificats est automatisé dans le déploiement, autrement il faut le faire manuellement ce qui est hors de question dans le cadre d'un environnement reproductible.

Ensuite nous disposons d'une fonction pour générer la configuration des machines du cluster. Cette configuration contient donc le rôle du node mais également des ajustements sur les ports et addresses IP de certains composants pour permettre la bonne communication des composants entre eux.

Nous ajoutons également une machine supplémentaire hors-cluster, c'est une serveur NFS, une solution parmis d'autres pour fournir au cluster un moyen de créer des volumes (PersistentVolume) accessibles par tous les nœuds. Ce serveur est monté sur toutes les machines, ce qui permet à l'expérimentateur de soit utiliser des volumes NFS, soit des volumes locaux pour plus de simplicité.

Avec Istio nous pouvons suivre le guide d'exemple présent dans la documentation pour déployer une application microservice et vérifier le bon fonctionnement du cluster.

Cette composition est fonctionnelle pour la plateforme de nixos-test et nixos-test-driver, toutes deux reposant sur QEMU, et également sur Grid'5000 où elle dévoile son vrai potentielle car les machines sont réelles et véritablement utilisables pour administrer le cluster. Elle n'est pas fonctionnelle sur Docker pour des raisons propres à NixOS-Compose qui ne permettent pas de modifier les noms d'hôtes (/etc/hosts), ce qui empêche la dérivation de fonctionner correctement.

Certains éléments de bootstrap se révèlent être difficilement applicable lors du déploiement avec NixOS-Compose et nous reposons donc en partie sur un script d'initialisation du cluster. Ce script est créé dans la composition et accessible dans le path. Il redémarre les composants éventuellement échoués et affiche une commande à l'utilisateur permettant d'ajouter des machines au cluster, cette étape n'tant pas automatisable simplement (l'approche est la même que kubeadm).

ELK
Pour ce qui est de l'expérience ELK, une grande partie du temps a été passée à comprendre la stack ELK et ses différentes composantes. Pour réaliser une composition fonctionnelle via NixOS-Compose, nous nous sommes basés sur une composition pré-existante écrite pour NixOS-Tests. La composition a ensuite été modifiée de manière à fonctionner correctement pour les différents modes de déploiement (Docker, Grid'5000).

Hadoop
Un paquet hadoop existe deja et il s'agit principalement d'en faire sa configuration. Plusieurs configurations différentes ont été réalisées, une minimale afin de comprendre le fonctionnement général, puis une se servant de yarn afin de maitriser la multiplicité des nœuds de travail. Dans la composition minimale nous avons pu mettre, comme le premier shéma de la partie précédente, créer un node de front (namenode) ainsi qu'un datanode fonctionnant avec le filesystem.

=Gestion de projet=

Ce projet relève en partie d’un travail de recherche au vu du manque de documentation, du développement toujours en cours de l’OS et de sa faible utilisation de la part de la communauté d’utilisateurs.

Une importante partie de ce projet repose sur la communication entre notre équipe et l’équipe Datamove pour recevoir des consignes et fournir des retours. Pour fluidifier ces échanges nous avons organisé des réunions régulières et mis en place des solutions de communication en permanence à travers des outils comme Telegram et Zoom pour les réunions.

Nous avons mis en place deux types de réunions : des réunions quotidiennes avec un membre de l’équipe Datamove et des réunions hebdomadaires en équipe complète. Les réunions quotidiennes servent principalement à partager l’avancement et exprimer des éventuels blocages. Les réunions hebdomadaires visent davantage à faire un point global et à définir les prochaines étapes.

Planification
Pour ce qui est de la planification, il nous paraissait essentiel pour un projet comme le nôtre dans lequel énormément de temps est alloué à l'apprentissage d'une technologie plutôt qu'à la production réelle de code de définir une roadmap.

Cette roadmap avait pour but de planifier nos actions sur l’ensemble de la durée du projet. Nous avons fait évoluer la roadmap au fur et à mesure de notre avancement réel. Celle-ci nous a permis non seulement de travailler avec un objectif en tête mais également de partager ces objectifs avec l’équipe Datamove.

Organisation du travail
Au commencement de projet, notre objectif à tous était de se former rapidement sur Nix afin de comprendre l'étendu des possibilités de l'outil NixOS-Compose et de commencer à le tester.

Notre première tâche a consisté à écrire une composition k3s compatible avec NixOS-Compose de manière à découvrir la puissance de l'outil.

Ensuite, nous sommes chacun parti sur un projet différent dans l'optique de fournir trois expériences utilisateurs distinctes. La répartition des projets était la suivante :
 * Titouan Minier Mancini : Kubernetes
 * Corentin Humbert : Stack ELK
 * Corentin Sueur : Hadoop

Nous avons donc progressé chacun de notre côté sur nos projets respectifs tout en restant en contact constant de manière à éviter de passer trop temps bloqué sur une partie du projet. La communication a été impérative pour un tel projet au vu de sa complexité et du temps dont nous disposions pour le mener à terme.

Suivi du travail
En parallèle nous avons suivi la rédaction de carnets de route individuels où nous expliquons toutes nos actions dans la journée, avec un maximum de détails notamment sur les erreurs. L’objectif est de permettre aux membres de l’équipe Datamove de suivre notre avancée individuelle et d’aider sur les problèmes techniques éventuels. Ces carnet doivent permettre un maximum la reproductibilité des situations pour faciliter la correction.

=Outils de travail=

Au cours de notre projet, nous avons été amenés à utiliser de nombreux outils nous permettant d’échanger entre nous et avec l’équipe Datamove que ce soit pour poser des questions ou partager nos productions.


 * Communication écrite/orale :
 * Au sein du groupe : Discord
 * Avec l’équipe Datamove : Telegram, BBB, Zoom
 * Échanges d’informations :
 * Google docs, CodiMD
 * Stockage des documents et du code produit :
 * Dépôt GitLab

=Métriques logiciels=

Ce projet ne rentre pas dans le cadre d'une production logicielle, la quantité de code produit est faible car le travail est avant tout un travail de compréhension et de recherche. Nous avons produit un fichier de composition pour chaque pile logicielle, ce qui correspond à une centaine de lignes chacune. Le temps était principalement accordé à l'essai, l'avancement à tâtons pour explorer les différentes options disponibles, et à la compréhension du fonctionnement de NixOS-Compose.

Nous avons tous travaillé 35 heures par semaine, à l'exception des première semaines en parallèle avec le projet ECOM où Titouan et Corention Humbert n'étaient plus disponibles qu'à hauteur de 21 à 28 heures par semaine.

=Conclusion=

Ce projet nous a avant tout permis de découvrir l'environnement Nix et la solution NixOS-Compose, qui promet d'être intéressante et un candidat potentiel à l'*Infrastructure as Code* de demain. L'approche est différente de ce que l'on peut rencontrer avec d'autres outils comme Terraform et il est enrichissant de s'y pencher pour élargir sa pensée.

Nous avons également pu travailler sur des piles logicielles que nous ne connaissions pas forcément, ce qui a aussi été très enrichissant. Nous avons appris à utiliser ces piles logicielles et à les configurer, ce qui est généralement le plus important pour ce genre de système. Nous avons appris ou réappris des technologies, et amélioré notre capacité à appréhender un système distribué, savoir d'où viennent les problèmes et comment les résoudre.

Les compositions que nous avons pu fournir à l'issue du projet sont très satisfaisantes. Elles sont fonctionnelles et permettent à d'autres utilisateurs d'appréhender la solution NixOS-Compose. Nous avons également fourni des tutoriels et explications avec ces compositions pour exprimer des retours utilisateur au projet NixOS-Compose, ce qui, nous espérons, permettra de mettre en valeur ce beau projet.

=Démonstration=

La démonstration que nous proposons est de présenter le déploiement de chacune des piles logicielles.

Vidéo de démonstration sur Kubernetes: https://www.youtube.com/watch?v=uOh8BJPj7MU