====== Nomad Orchestrateur ====== Personnellement, j'ai choisi Nomad pour gérer les conteneurs sur mon Homelab. Il me permets une gestion simple et centralisée des conteneurs et processus. ===== Présentation ===== Site officiel: https://www.nomadproject.io/ Un orchestateur simple et flexible pour déployer et gérer des conteneurs et des binaires sur un cluster on-prem ou dans le cloud, à l'échelle. Gratuit, Automanagé, Autohebergé et Opensource ! Parfait pour la gestiuon de Conteneurs (Docker & Podman), Processus, Fichiers Jar, VM Qemu, Conteneurs LXC, ... Se reporter à la documentation pour la liste complète des éxécuteurs supportés : https://developer.hashicorp.com/nomad/docs/drivers ===== Installation ===== Dans cette installation pas-a-pas, nous serons sous Ubuntu. Cette procédure peut-etre dérivé pour Debian ou autres systèmes Linux. Note : Lors de mon installation, seul Docker était supporté. Podman est maintenant compatible mais pas encore complètement intégré : https://developer.hashicorp.com/nomad/plugins/drivers/podman Commencons par l'installation des différents pré-requis pour Docker et Nomad. sudo apt-get update sudo apt-get install software-properties-common curl ca-certificates curl gnupg lsb-release Maintenant, importer le repository des binaires Nomad. wget -O- https://apt.releases.hashicorp.com/gpg | sudo gpg --dearmor -o /usr/share/keyrings/hashicorp-archive-keyring.gpg echo "deb [signed-by=/usr/share/keyrings/hashicorp-archive-keyring.gpg] https://apt.releases.hashicorp.com $(lsb_release -cs) main" | sudo tee /etc/apt/sources.list.d/hashicorp.list Ensuite, nous pouvons installer les packages Nomad. sudo apt-get update && sudo apt-get install nomad Ajouter le Repository Docker. sudo mkdir -m 0755 -p /etc/apt/keyrings curl -fsSL https://download.docker.com/linux/ubuntu/gpg | sudo gpg --dearmor -o /etc/apt/keyrings/docker.gpg echo "deb [arch=$(dpkg --print-architecture) signed-by=/etc/apt/keyrings/docker.gpg] https://download.docker.com/linux/ubuntu $(lsb_release -cs) stable" | sudo tee /etc/apt/sources.list.d/docker.list > /dev/null Et installer les packages pour Docker. sudo apt-get update && sudo apt-get install docker-ce docker-ce-cli containerd.io docker-buildx-plugin docker-compose-plugin Activer les services pour démarrage automatique. sudo systemctl enable nomad && sudo systemctl enable docker Dernière étape, redémarrer le service Nomad pour découverte des services Docker. sudo systemctl restart nomad Vous pouvez ensuite accéder à l'interface web de gestion du cluster Nomad sur le port 4646 de la machine: http://127.0.0.1:4646/ ===== Interface Administration ===== ==== Configuration==== L'emplacement du fichier principal de configuration est le suivant : '/etc/nomad.d/nomad.hcl' Voici pour exemple mon fichier de configuration: data_dir = "/opt/nomad/data" bind_addr = "192.168.1.101" datacenter = "home" # Nom du Datacenter region = "fr" # Code Regional du datacenter name = "nomad-main" # Nom du serveur server { # Définit l'instance comme gestionnaire du cluster, avec interface web et API enabled = true bootstrap_expect = 1 } client { # Définit l'instance comme Runner, autorisé à éxécuter des jobs enabled = true servers = ["127.0.0.1"] network_interface = "enp0s25" # Déclarer les interfaces réseaux ici meta { # Attributs customisées pour ciblage des jobs usage = "LAN" specific = "MAIN" } } plugin "docker" { config { # options Docker allow_privileged = true volumes { enabled = true } } } plugin "raw_exec" { config { enabled = true # Activation du raw_exec sur l'hôte } } Vous pouvez égalementy vous reporter à la documentation sur la configuration : https://www.nomadproject.io/docs/configuration Ne pas oublier de redémarrer le service Nomad après modification pour prise en compte. ==== Utilisation ==== A titre d'exemple, nous allons lancer un conteneur 'uptime-kuma' sur le port 8080 de l'hôte sans volume persistant. Première étape, cliquer sur le bouton 'Run Job' en haut de l'interface web de votre cluster Nomad. Bouton Run job sur interface web Nomad Puis, coller le job suivant: job "Monitoring" { region = "fr" datacenters = ["home"] type = "service" group "uptime-service" { count = 1 network { port "web" { static = 8080 to = 3001 } } restart { attempts = 5 delay = "1m" } task "uptimekuma" { driver = "docker" config { image = "louislam/uptime-kuma:alpine" ports = ["web"] } resources { cpu = 50 memory = 128 } } } } En bas de la page, cliquer sur 'Plan', puis sur 'Run'. Le job va se déclencher, vous pouvez ensuite accéder au service via le port 8080 : http://127.0.0.1:8080 ===== Optimisation: Memory Oversubscription ===== Pour activer l'autorisation de dépassement mémoire, il faut déjà installer JQ. sudo apt-get install jq Ensuite, vous pouvez-vérifier le status du 'MemoryOversubscriptionEnabled' dans la confiuguration du scheduler Nomad : curl -s http://127.0.0.1:4646/v1/operator/scheduler/configuration | jq . { "SchedulerConfig": { "SchedulerAlgorithm": "binpack", "PreemptionConfig": { "SystemSchedulerEnabled": true, "SysBatchSchedulerEnabled": false, "BatchSchedulerEnabled": false, "ServiceSchedulerEnabled": false }, "**MemoryOversubscriptionEnabled**": false, "RejectJobRegistration": false, "PauseEvalBroker": false, "CreateIndex": 5, "ModifyIndex": 5 }, "Index": 5, "LastContact": 0, "KnownLeader": true, "NextToken": "" } Vouc pouvez l'activer avec la commande suivante: curl -s http://127.0.0.1:4646/v1/operator/scheduler/configuration | \ jq '.SchedulerConfig | .MemoryOversubscriptionEnabled=true' | \ curl -X PUT http://127.0.0.1:4646/v1/operator/scheduler/configuration -d @- ===== Modèles de jobs ===== Voici quelques exemples de jobs pour référence. ==== Site Web Wordpress ==== Dans cet exemple, l'éxécution de Wordpress avec une base de données MariaDB, exposant sur le port 8080. Les ressources mémoire allouées sont limités avec une autorisation de dépassement pour le serveur SQL job "Wordpress" { region = "fr" datacenters = ["home"] type = "service" constraint { # Restricted to run on a specific host group with label 'usage = LAN' attribute = "${meta.usage}" value = "LAN" } group "wordpress-service" { count = 1 network { port "frontend" { static = 8080 to = 80 } port "backend" { to = 3306 } } restart { attempts = 5 delay = "1m" } task "web-front" { driver = "docker" config { image = "wordpress:latest" ports = ["frontend"] volumes = [ # Use a custom folder here into host "/application-data/wordpress-data:/var/www/html" ] } env { WORDPRESS_DB_HOST = "${NOMAD_IP_backend}:${NOMAD_HOST_PORT_backend}" WORDPRESS_DB_USER = "user" WORDPRESS_DB_PASSWORD = "password" WORDPRESS_DB_NAME = "wordpress" } resources { cpu = 500 memory = 512 } } task "web-db" { driver = "docker" config { image = "mariadb:10.11" ports = ["backend"] volumes = [ "/application-data/wordpress-db:/var/lib/mysql" ] } user = 1000 env { MYSQL_ROOT_PASSWORD = "rootpassword" MYSQL_USER = "user" MYSQL_PASSWORD = "password" MYSQL_DATABASE = "wordpress" } resources { cpu = 300 memory = 256 } } } } ==== Batch et Prestart ==== Dans cet exemple, nous avons plusieurs points intéressants, le type Batch, le raw exec et le prestart. L'objectif principal est le lancement d'un binaire sur l'hôte avec du 'raw exec'. Le job permets ainsi l'éxécution d'une commande sur l'hôte et lis le code retour ainsi que les sorties. Le mode 'Batch' permets un lancement périodique de la commande. La fonction de 'prestart' permets l'éxécution d'une tâche avant le processus principal. Par exemple ici, la copie d'un fichier. job "DHCP" { region = "fr" datacenters = ["home"] type = "batch" priority = 90 periodic { // Launch every 24 hours cron = "@daily" // Do not allow overlapping runs. prohibit_overlap = true } group "dhcp-service" { count = 1 constraint { # Restricted to run on a specific host with label 'specific = MAIN' attribute = "${meta.specific}" value = "MAIN" } restart { attempts = 10 delay = "1m" } task "dhcpd-restart" { driver = "raw_exec" config { command = "systemctl" args = [ "restart", "isc-dhcp-server" ] } } # Prestart task partially updating conf task "dhcpd-conf" { lifecycle { hook = "prestart" sidecar = false } driver = "docker" config { image = "alpine:latest" command = "cp" args = [ "/tmpsource/dhcpd.conf", "/tmpdest/dhcpd.conf" ] volumes = [ "/etc/dhcp:/tmpdest" ] mounts = [ { type = "bind" source = "local/conf/dhcpd.conf" target = "/tmpsource/dhcpd.conf" } ] } template { data = <