OSS NextGen comme son nom l’indique est une nouvelle version d’OSS. Celle-ci se base sur une infrastructure multisite à base de Proxmox VE, Terraform, Packer, Ansible et Kubernetes. Nous avons un serveur de production par site (Toulouse, Paris, Marseille et Lille) et un serveur de backup (Paris).

Compétences mise en oeuvre

Veuillez consulter le Tableau de compétences

Les tâches que j’ai réalisées

J’ai principalement travaillé sur le développement de la plateforme OSS NextGen ainsi qu’à l’intégration des applications à la plateforme.

Concernant le développement de la plateforme, j’ai travaillé avec Brice pour apprendre à utiliser et à développer avec Terraform ainsi qu’à réapprendre comment on utilise et on configure des applications sur Kubernetes.

Après ça, j’ai commencé à l’aider sur le développement de la plateforme en commençant par la partie Packer qui est restée inchangée. Puis j’ai travaillé sur la création de VM avec Terraform, d’abord pour faire du Kubernetes, puis nous sommes partis sur la configuration d’une VM socle sur Docker. Après ça on a décidé de partir sur une version Kubernetes du socle et d’y incorporer d’autres applications sur le cluster derrière.

Fonctionnement des différents logiciels

Kubernetes

Kubernetes est un ordonnanceur de conteneur, dans la configuration qu’on utilise on le déploie avec container.d comme moteur de conteneur (C’est celui utilisé sous Docker aussi). Voici un schéma qui explique son fonctionnement (Source: Wikipedia):

image

Sous Kubernetes il existe plusieurs manières pour faire des configurations :

  • La création manuelle de manifests
  • L’utilisation d’Helm chart
  • Terraform
  • Kustomize
  • CI/CD

Un manifest c’est un fichier de configuration en YAML, voici un exemple pour la déclaration d’un namespace :

apiVersion: v1
kind: Namespace
metadata:
    name: my-namespace

Et pour créer un service :

apiVersion: v1
kind: Service
metadata:
    name: my-service
    namespace: my-namespace
spec:
    selector:
    app: my-app
    ports:
    - protocol: TCP
        port: 80
        targetPort: 80
    type: ClusterIP    

Un service avec une IP fixe de sortie (Ex pour NGINX):

apiVersion: v1
kind: Service
metadata:
    name: nginx-service
    namespace: my-namespace
spec:
    type: LoadBalancer
    loadBalancerIP: 192.168.1.240  
    selector:
    app: nginx
    ports:
    - protocol: TCP
        port: 80
        targetPort: 80    

Un fichier de déploiement (Ex pour NGINX):

apiVersion: apps/v1
kind: Deployment
metadata:
    name: nginx-deployment
    namespace: my-namespace
spec:
    replicas: 3
    selector:
    matchLabels:
        app: nginx
    template:
    metadata:
        labels:
        app: nginx
    spec:
        containers:
        - name: nginx
        image: nginx:latest
        ports:
        - containerPort: 80

Voici un exemple sous forme d’un docker compose :

services:
    nginx:
        image: nginx:latest
        ports:
            - "8080:80"
        networks:
            my_network:
                ipv4_address: 172.28.0.10
networks:
    my_network:
        driver: bridge
        ipam:
            config:
            - subnet: 172.28.0.0/16

Les Helm Chart sont des manifests sous forme de templates configurables à l’aide d’un seul fichier en format YAML (values.yml), voici un exemple avec le Helm Chart "Hello-World" :

helm repo add examples https://helm.github.io/examples
helm install hello examples/hello-world

Pour déployer les applications et le socle, on utilise les providers Kubernetes et Helm fournis par HashiCorp pour déployer le code.

Packer

Packer est une solution d’Hashicorp permettant la création d’une golden image. Une golden image est une template d’une machine virtuelle qui sert de base pour toutes les instances créées à partir de cette template.

Par exemple, sur Proxmox VE, nous avons trois manières de créer des templates :

  • Utilisation d’images CloudInit, comme ce qui a été fait plus haut sur OSS.

  • Utilisation de Packer avec des ISO configurés à l’aide de preseed (fichier de configuration pour automatiser l’installation de Debian).

  • Installation manuelle de Debian sur une VM, suivie d’une reconfiguration à chaque copie de la VM template.

Voici comment le processus fonctionne avec Packer :

1.Terraform génère les mots de passe pour la VM (utilisateur et root) et crée un fichier preseed en fonction du template.

2.Terraform appelle Packer. Packer contacte l’API de Proxmox, télécharge l’ISO de Debian 12, démarre la VM et configure l’installation de Debian en utilisant le fichier preseed.

3.Une fois l’installation terminée, Packer tente de se connecter à la VM via SSH pour vérifier son bon fonctionnement. Si la connexion est réussie, Packer éteint la VM et la convertit en template sur Proxmox.

4.Terraform est informé que la tâche est terminée et récupère la template générée. Il copie cette template pour créer le nombre de VM nécessaires (par exemple, 6 pour 3 Master et 3 Worker).

5.Terraform génère un inventaire Ansible en fonction des adresses IP fournies par le DHCP aux VM, puis copie le dossier template pour la configuration de Kubernetes et démarre le playbook Ansible.

Fonctionnement de Terraform

Terraform est un outil d’infrastructure as code développé par HashiCorp. Il permet de définir, déployer et gérer des infrastructures à l’aide de fichiers de configuration. Voici les étapes clés de son fonctionnement :

1.Définition de l’infrastructure : Vous écrivez des fichiers de configuration en utilisant le langage de configuration de Terraform (HCL - HashiCorp Configuration Language). Ces fichiers décrivent les ressources que vous souhaitez créer et gérer, comme des machines virtuelles, des réseaux, des bases de données, etc.

2.Initialisation : Avant d’exécuter des commandes Terraform, vous devez initialiser votre répertoire de travail en utilisant la commande terraform init. Cela télécharge les plugins nécessaires pour interagir avec les différents fournisseurs de services (comme AWS, Azure, Google Cloud, etc.).

3.Planification : Vous utilisez la commande terraform plan pour générer un plan d’exécution. Ce plan montre les actions que Terraform effectuera pour aligner votre infrastructure réelle avec la configuration définie dans vos fichiers. Cela inclut la création, la mise à jour ou la suppression de ressources.

4.Application : La commande terraform apply exécute le plan généré précédemment, appliquant les modifications nécessaires pour créer, mettre à jour ou supprimer des ressources. Terraform utilise les API des fournisseurs de services pour effectuer ces actions.

5.Gestion de l’état : Terraform maintient un fichier d’état (par défaut nommé terraform.tfstate) qui garde une trace des ressources actuelles gérées par Terraform. Ce fichier est crucial pour suivre les modifications et pour appliquer les changements de manière cohérente.

6.Destruction : Si vous souhaitez supprimer les ressources, vous pouvez utiliser la commande terraform destroy. Cette commande lit l’état actuel et supprime toutes les ressources définies dans vos fichiers de configuration.

Installation de Proxmox VE

Pour installer Proxmox VE sur un serveur ou un PC, il suffit de télécharger le fichier ISO sur le site officiel de Proxmox. Sous GNU/Linux et Windows il existe de multiple utilitaires et méthodes pour installer une ISO sur une clef USB. Du moment que l’ISO est présente sur la clef USB, allez dans le Boot Menu de la carte mère (cela change en fonction du modèle, veuillez vous référer au manuel du serveur ou de votre carte mère, du constructeur du PC).

Après ça suivez l’installateur de Proxmox VE en fonction de vos préférences.

Une fois Proxmox VE installé, pour utiliser le code présent sur mon dépôt Git pour le déploiement d’un cluster Kubernetes, vous devez passer en mode "Cluster" sur Proxmox VE en fonction de cette documentation : https://pve.proxmox.com/wiki/Cluster_Manager

Déploiement d’un cluster Kubernetes

La configuration et l’installation manuelle de Kubernetes peuvent être assez fastidieuses. Nous utilisons donc Kubespray pour créer et configurer un cluster Kubernetes. Kubespray permet de configurer de nombreuses options de base, telles que le LoadBalancer pour l’attribution d’IP en sortie, l’Ingress, etc. Nous avons également configuré MetalLB pour gérer les adresses IP en sortie et NGINX Ingress Controller pour faire un reverse proxy pour les services déployés dans Kubernetes, ainsi que pour les services externes.

Voici un schéma Mermaid qui résume le déploiement d’un cluster Kubernetes :

flowchart TD %% Packer Configuration A1[Create User and Root password] --> A2[Generate Debian Preseed file] G1 -->|Depends on| B1[Create Kubernetes Master VMs] G1 -->|Depends on| B2[Create Kubernetes Worker VMs] %% Proxmox VM Creation B1 -->|Depends on| C1[Create Ansible Directory] B2 -->|Depends on| C1 C1 -->|Depends on| C2[Generate Ansible Inventory] %% Kubernetes Cluster Creation C2 -->|Depends on| D1[Wait for 30 Seconds] D1 -->|Depends on| D2[Execute Ansible to Create Kubernetes Cluster] %% Kubeconfig Extraction D2 -->|Depends on| E1[Copy Kubeconfig to postconfig Local Directory] E1 --> F1[Output Kubeconfig Path] %% Ansible Execution D2 -->|Runs| D3[Run Ansible Playbook to Setup Cluster] %% Packager Build A2 -->|Runs| G1[Run Packer to Build Debian Image] G1 --> H1[Build Debian Base Image] H1 -->|Uses| H2[Debian ISO as source] %% Dependencies and Triggering B1 -.->|Triggers| C1 B2 -.->|Triggers| C1 C1 -.->|Triggers| C2 C2 -.->|Triggers| D1 D2 -.->|Triggers| E1

Après que l’on ait déployé le cluster Kubernetes, nous mettons des applications que l’on qualifie de socle car elles sont cruciales au bon fonctionnement de la plateforme et des différents services autours :

  • Authentik : gestionnaire LDAP (Lightweight Directory Access Protocol sous Linux, sous Windows on appelle ça l’Active Directory) et SSO (Single Sign-On)
  • PowerDNS : Serveur DNS pour la définition des différentes zones d’OSS (ef-fr.dev pour OSS et .io pour le reste de Network Operations)
  • Homepage : Dashboard dynamique de toutes les applications présentes sur OSS pour OSS et pour Network Operations.

Hors des applications présentes sur le cluster Kubernetes, on utilise le provider vancluever/acme pour la génération des certificats TLS pour l’HTTPS.

Après avoir déployé tout ça, on a une dernière partie de configuration pour déployer les zones DNS sur PowerDNS.

Voici un schéma qui décrit le déploiement du socle :

flowchart TD %% Main Configuration subgraph Main A5[Longhorn Helm chart] A6[Authentik Manifests] A7[PowerDNS Manifests] A8[Ingress Manifests] A9[TLS Manifests] end %% Modules subgraph Configuration B1[Providers] B2[Variables] B3[Passwords] end %% ACME Module subgraph ACME C1[ACME Account] C2[Certificate for ef-fr.dev] C3[Certificate for ef-fr.io] end %% Helm Module subgraph Helm D1[Authentik Helm Chart] D2[Homepage Helm Chart] end %% PowerDNS Module subgraph PowerDNS E1[PowerDNS Records] E2[PowerDNS Zones] end %% Connections Configuration -->|Depends on| Main Configuration -->|Depends on| ACME Configuration -->|Depends on| Helm Configuration -->|Depends on| PowerDNS A5 -->|Depends on| A6 A5 -->|Depends on| A7 D1 -->|Depends on| A8 D2 -->|Depends on| A8 A7 -->|Depends on| A8 A9 -->|Depends on| A8 A7 -->|Depends on| E1 A7 -->|Depends on| E2 A6 -->|Triggers| D1 C2 -->|Triggers| A9 C3 -->|Triggers| A9 C1 -->|Depends on| C2 C1 -->|Depends on| C3 A5 -->|Depends on| D1 A5 -->|Depends on| D2

Code de la plateforme

Sur le dépôt GitLab, la configuration de la plateforme est disponible dans le dossier ./oss/plateforme.

Déploiement d’une applications sur Kubernetes à l’aide de Terraform

Arborescence des Fichiers

Voici l’arborescence des fichiers utilisés dans le déploiement :

    .
    ├── kubeconfig
    │   └── admin.conf
    ├── manifests.tf
    ├── outputs.tf
    ├── passwords.tf
    ├── providers.tf
    ├── README.md
    ├── terraform.tfstate
    └── variables.tf

Définition des Variables

Le fichier variables.tf contient la définition des variables utilisées dans la configuration de Terraform. Ces variables sont essentielles pour la configuration des ressources, telles que les mots de passe ou les adresses.

Gestion des Mots de Passe

Le fichier passwords.tf est utilisé pour générer des mots de passe aléatoires nécessaires au déploiement. Ces mots de passe peuvent être utilisés pour sécuriser des comptes ou des secrets dans Kubernetes.

Configuration des Providers

Le fichier providers.tf configure les fournisseurs nécessaires pour interagir avec les services cloud et Kubernetes. Il définit les paramètres de connexion comme le chemin du fichier kubeconfig.

Gestion de l’État de Terraform

Le fichier terraform.tfstate contient l’état actuel des ressources gérées par Terraform. Il est mis à jour à chaque exécution de Terraform pour refléter les changements apportés aux ressources.

Définition des Manifests

Le fichier manifests.tf définit les ressources Kubernetes à déployer. Cela inclut des ressources tels que les namespaces, les secrets, les déploiements, les services, etc... Ces manifests sont utilisés pour créer et gérer les ressources sur le cluster Kubernetes.

Déclaration des Outputs

Le fichier outputs.tf déclare les sorties de Terraform. Les sorties peuvent inclure des informations utiles sur les ressources créées, comme les adresses IP des services ou les noms des ressources. Elles sont essentielles pour le suivi et la gestion des ressources déployées.

Gestion de l’état de Terraform

Le fichier terraform.tfstate contient l’état actuel des ressources gérées par Terraform. Il est mis à jour à chaque exécution de Terraform pour refléter les changements apportés aux ressources.

Helm

Cela dépend de l’application, mais si celle-ci est disponible dans un dépôt Helm, on aura tendance à vouloir l’utiliser, la configuration sous Terraform est plutôt simple, on a juste à déclarer une ressource par release Helm (Une release sur Helm c’est comme si on parlait d’un déploiement sur Kubernetes). Seul différence par rapport à la commande Helm, c’est qu’on peut sois déclarer les variables dans la ressource Terraform, sois déclarer les variables dans un fichier (ce que je recommande).

Exemple de configuration Terraform

Sur le dépôt GitLab, la configuration d’une application en tant qu’exemple (Maddy, un serveur d’email), est présente dans le dossier ./oss/maddy.