Ce document contient les livrables issus de la mise en place du service
Prometheus,GrafanaetAlertsManager. L’objectif est de pouvoir disposer de services, concernant la collecte de métriques, l’exposition de dashboards et la génération d’alertes avec notifications par mail. Côté architecture, un reverse proyxnginxsera en frontal pour porter le certficat wildcard*.ng-hl.comet redirigera vers le serveur adéquat. Pour le niveau de maturité niveau 2, le chiffrement TLS sera appliqué uniquement au niveau de l’exposition vers l’extérieur à savoir lenginx. Concernant le niveau 3, il faudra mettre en place des communications chiffrés via TLS au travers de certificats fournit par une PKI interne pour adopter le principe d’une architecture 0 trust.
Cette section couvre la partie reverse proxy avec
nginx. Cette machine porte le nomreverseproxysup-core.homelabavec un CNAMErps-core.homelab.
1. Création de la VM
Nous allons utiliser le template debian12-template créé lors du chapitre 4. Sur Proxmox on crée un clone complet à partir de ce template. Voici les caractéristiques de la VM :
| OS | Hostname | Adresse IP | Interface réseau | vCPU | RAM | Stockage |
|---|---|---|---|---|---|---|
| Debian 12.10 | reverseproxysup-core rps-core (CNAME) | 192.168.100.242 | vmbr1 (core) | 1 | 2048 | 20Gio |
Il faut également penser à activer la sauvegarde automatique de la VM sur Proxmox en l’ajoutant au niveau de la politique de sauvegarde précédemment créée.
2. Configuration de l’OS via Ansible
Les informations concernant Ansible sont disponibles au niveau des chapitres 7 et 8.
A présent, le playbook et les rôles ayant pour objectif d’appliquer la configuration de base de l’OS sont disponibles. Il faut se connecter en tant que l’utilisateur ansible sur le serveur ansible-core.homelab puis ajouter l’hôte rps-core.homelab au niveau du fichier d’inventaire /opt/ansible/envs/100-core/00_inventory.yml avec les éléments suivants
rps-core.homelab:
ip: 192.168.100.242
hostname: reverseproxysup-core
Pour exécuter le playbook, il faut lancer la commande suivante
ansible-playbook -i envs/100-core/00_inventory.yml -l 'rps-core.homelab,' playbooks/00_config_vm.yml
Voici le récapitulatif
TASKS RECAP **********************************************************************************************************************
vendredi 08 août 2025 23:14:22 +0200 (0:00:00.260) 0:00:14.348 *********
===============================================================================
base_packages : Installation des paquets de base -------------------------------------------------------------------------- 4.30s
dns_config : Installation du paquet systemd-resolved ---------------------------------------------------------------------- 2.05s
base_packages : Mise à jour du cache apt ---------------------------------------------------------------------------------- 1.88s
Gathering Facts ----------------------------------------------------------------------------------------------------------- 1.06s
dns_config : Autoremove et purge ------------------------------------------------------------------------------------------ 0.56s
motd : Déploiement du motd ------------------------------------------------------------------------------------------------ 0.46s
hostname_config : Modification du hostname -------------------------------------------------------------------------------- 0.44s
dns_config : Enable du daemon systemd-resolved ---------------------------------------------------------------------------- 0.39s
dns_config : Suppression du paquet resolvconf ----------------------------------------------------------------------------- 0.33s
nftables : Déploiement de la configuration de nftables -------------------------------------------------------------------- 0.31s
dns_config : Resart du daemon systemd-resolved ---------------------------------------------------------------------------- 0.30s
nftables : Valider la configuration nftables ------------------------------------------------------------------------------ 0.27s
security_ssh : Restart du daemon sshd ------------------------------------------------------------------------------------- 0.26s
dns_config : Suppression du fichier /etc/resolv.conf ---------------------------------------------------------------------- 0.20s
ipv6_disable : Désactivation de la prise en charge de l'IPv6 globalement -------------------------------------------------- 0.19s
hostname_config : Modification du fichier /etc/hosts ---------------------------------------------------------------------- 0.19s
dns_config : Configuration du DNS dans /etc/resolved.conf ----------------------------------------------------------------- 0.19s
dns_config : Création du nouveau lien symbolique vers /etc/resolv.conf ---------------------------------------------------- 0.14s
ipv6_disable : Désactivation de la prise en charge de l'IPv6 par défaut --------------------------------------------------- 0.14s
security_ssh : Activation de l'authentification par clé ------------------------------------------------------------------- 0.14s
3. Déploiement et renouvellement automatique du certificat
Afin que le mécanisme de déploiement et de renouvellement du certificat wildcard *.ng-hl.com puisse être fonctionnel, il faut modifier temporairement la configuration du service
sshpour autoriser la connexion root avec un mot de passe pour autoriser la connexion en root via la clé publiqueid_acme_puben provenance deacme-core.
Se rendre sur le serveur acme-core en tant que root puis compléter le fichier /root/acme-deploy/targets.yml
- host: rps-core.homelab
user: root
type: binary
cert_path: /etc/ssl/certs/wildcard.ng-hl.com
privkey_name: privkey.key
cert_name: fullchain.cer
reload_cmd: systemctl restart nginx
Exécuter le script /root/acme-deploy/acme-deploy.sh pour déployer le certificat et la privkey associée.
Syncing cert to rps-core.homelab...
Remote cert checksum: missing
Remote key checksum: missing
Changes detected, copying certs...
fullchain.cer 100% 2848 7.9MB/s 00:00
privkey.key 100% 227 829.2KB/s 00:00
Reloading service on rps-core.homelab...
Deployment completed for rps-core.homelab.
4. Installation et configuration de nginx via Ansible
Afin de commencer à intégrer le principe d’IaC déclarative et reproductible, je choisi d’installer et de configurer nginx pour l’instance
rps-corevia un playbook Ansible
Création du nouveau rôle reverse_proxy_sup
ansible-galaxy init roles/reverse_proxy_sup
Voici le contenu du fichier tasks/main.yml
# SPDX-License-Identifier: MIT-0
---
# tasks file for roles/reverse_proxy_sup
- name: Installation de Nginx
ansible.builtin.apt:
name: nginx
state: present
update_cache: yes
- name: Création du répertoire SSL
ansible.builtin.file:
path: "{{ reverse_proxy_ssl_dir }}"
state: directory
owner: root
group: root
mode: '0755'
- name: Création du répertoire pour les configurations Nginx
ansible.builtin.file:
path: /etc/nginx/sites-available
state: directory
owner: root
group: root
mode: '0755'
- name: Création du répertoire sites-enabled
ansible.builtin.file:
path: /etc/nginx/sites-enabled
state: directory
owner: root
group: root
mode: '0755'
- name: Déploiement de la configuration Nginx pour le vHost supervision
ansible.builtin.template:
src: supervision.conf.j2
dest: /etc/nginx/sites-available/supervision.conf
owner: root
group: root
mode: '0644'
- name: Activation de la configuration Nginx pour le vHost supervision
ansible.builtin.file:
src: /etc/nginx/sites-available/supervision.conf
dest: /etc/nginx/sites-enabled/supervision.conf
state: link
force: yes
notify: Redémarrer Nginx
Voici le contenu du fichier defaults/main.yml
# SPDX-License-Identifier: MIT-0
---
# defaults file for roles/reverse_proxy_sup
reverse_proxy_sup_domain: "supervision.ng-hl.com"
reverse_proxy_sup_ssl_dir: "/etc/ssl/certs/wildcard.ng-hl.com"
reverse_proxy_sup_cert_file: "fullchain.cer"
reverse_proxy_sup_key_file: "privkey.key"
reverse_proxy_sup_prometheus: "prometheus.ng-hl.com"
reverse_proxy_sup_grafana: "grafana.ng-hl.com"
reverse_proxy_sup_alertmanager: "alertmanager.ng-hl.com"
Voici le contenu du fichier handlers/main.yml
# SPDX-License-Identifier: MIT-0
---
# handlers file for roles/reverse_proxy_sup
- name: Redémarrer Nginx
ansible.builtin.systemd:
name: nginx
state: restarted
enabled: yes
Voici le contenu du fichier templates/supervision.conf.j2
server {
listen 80;
server_name {{ reverse_proxy_sup_domain }};
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name {{ reverse_proxy_sup_domain }};
ssl_certificate {{ reverse_proxy_sup_ssl_dir }}/{{ reverse_proxy_sup_cert_file }};
ssl_certificate_key {{ reverse_proxy_sup_ssl_dir }}/{{ reverse_proxy_sup_key_file }};
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
access_log /var/log/nginx/supervision_access.log;
error_log /var/log/nginx/supervision_error.log;
location / {
root /var/www/index.html;
}
}
Création du playbook 10_reverse_proxy_sup.yml
---
- name: Configuration du reverse proxy pour la supervision
hosts: all
become: true
roles:
- nftables
- reverse_proxy_sup
Afin de vérifier que l’on applique bien une syntaxe cohérente et les bonnes pratiques Ansible, on exécute le linter ansible-lint sur notre nouveau playbook.
ansible-lint playbooks/10_reverse_proxy_sup.yml
Passed: 0 failure(s), 0 warning(s) on 11 files.
Application du playbook sur l’instance rps-core
ansible-playbook -i envs/100-core/00_inventory.yml -l 'rps-core.homelab,' playbooks/10_reverse_proxy_sup.yml
Voici le récapitulatif du passage du playbook
TASKS RECAP ***************************************************************************************************************
samedi 09 août 2025 21:10:15 +0200 (0:00:00.142) 0:00:03.828 ***********
===============================================================================
Gathering Facts ---------------------------------------------------------------------------------------------------- 1.00s
reverse_proxy_sup : Installation de Nginx -------------------------------------------------------------------------- 0.91s
nftables : Déploiement de la configuration de nftables ------------------------------------------------------------- 0.44s
nftables : Activer et démarrer le service nftables ----------------------------------------------------------------- 0.38s
reverse_proxy_sup : Déploiement de la configuration Nginx pour Prometheus, Grafana et AlertManager ----------------- 0.29s
nftables : Valider la configuration nftables ----------------------------------------------------------------------- 0.20s
reverse_proxy_sup : Création du répertoire SSL --------------------------------------------------------------------- 0.19s
reverse_proxy_sup : Activation de la configuration Nginx ----------------------------------------------------------- 0.14s
reverse_proxy_sup : Création du répertoire sites-enabled ----------------------------------------------------------- 0.14s
reverse_proxy_sup : Création du répertoire pour les configurations Nginx ------------------------------------------- 0.13s
Test de la réponse concernant la requête HTTPS sur le port 443
curl https://supervision-core.ng-hl.com
<!DOCTYPE html>
<html>
<head>
<title>Welcome to nginx!</title>
<style>
html { color-scheme: light dark; }
body { width: 35em; margin: 0 auto;
font-family: Tahoma, Verdana, Arial, sans-serif; }
</style>
</head>
<body>
<h1>Welcome to nginx!</h1>
<p>If you see this page, the nginx web server is successfully installed and
working. Further configuration is required.</p>
<p>For online documentation and support please refer to
<a href="http://nginx.org/">nginx.org</a>.<br/>
Commercial support is available at
<a href="http://nginx.com/">nginx.com</a>.</p>
<p><em>Thank you for using nginx.</em></p>
</body>
</html>
Cette section couvre la partie
Prometheus
1. Création de la VM
Nous allons utiliser le template debian12-template créé lors du chapitre 4. Sur Proxmox on crée un clone complet à partir de ce template. Voici les caractéristiques de la VM :
| OS | Hostname | Adresse IP | Interface réseau | vCPU | RAM | Stockage |
|---|---|---|---|---|---|---|
| Debian 12.10 | prometheus-core | 192.168.100.245 | vmbr1 (core) | 2 | 4096 | 20Gio + 10Gio |
Il faut également penser à activer la sauvegarde automatique de la VM sur Proxmox en l’ajoutant au niveau de la politique de sauvegarde précédemment créée.
Ajout du second disque de 10Gio sur le lv
/dev/debian12-vg/debian12-var-lv
2. Configuration de l’OS via Ansible
Les informations concernant Ansible sont disponibles au niveau des chapitres 7 et 8.
A présent, le playbook et les rôles ayant pour objectif d’appliquer la configuration de base de l’OS sont disponibles. Il faut se connecter en tant que l’utilisateur ansible sur le serveur ansible-core.homelab puis ajouter l’hôte prometheus-core.homelab au niveau du fichier d’inventaire /opt/ansible/envs/100-core/00_inventory.yml avec les éléments suivants
prometheus-core.homelab:
ip: 192.168.100.245
hostname: prometheus-core
Il est nécessaire d’ajouter les droits sudo sur l’utilisateur ansible au niveau du fichier /etc/sudoers.d/ansible avec les éléments ci-dessous. Il s’agit d’un oubli au niveau du template. (À corriger plus tard).
ansible ALL=(ALL) NOPASSWD: ALL
Pour exécuter le playbook, il faut lancer la commande suivante
ansible-playbook -i envs/100-core/00_inventory.yml -l 'prometheus-core.homelab,' playbooks/00_config_vm.yml
Voici le récapitulatif
TASKS RECAP **********************************************************************************************************************
vendredi 01 août 2025 21:32:25 +0200 (0:00:00.199) 0:00:06.948 *********
===============================================================================
Gathering Facts ----------------------------------------------------------------------------------------------------------- 1.00s
dns_config : Autoremove et purge ------------------------------------------------------------------------------------------ 0.58s
base_packages : Installation des paquets de base -------------------------------------------------------------------------- 0.46s
dns_config : Installation du paquet systemd-resolved ---------------------------------------------------------------------- 0.45s
motd : Déploiement du motd ------------------------------------------------------------------------------------------------ 0.44s
hostname_config : Modification du hostname -------------------------------------------------------------------------------- 0.42s
base_packages : Mise à jour du cache apt ---------------------------------------------------------------------------------- 0.39s
dns_config : Enable du daemon systemd-resolved ---------------------------------------------------------------------------- 0.38s
dns_config : Suppression du paquet resolvconf ----------------------------------------------------------------------------- 0.34s
dns_config : Resart du daemon systemd-resolved ---------------------------------------------------------------------------- 0.29s
nftables : Déploiement de la configuration de nftables -------------------------------------------------------------------- 0.29s
nftables : Valider la configuration nftables ------------------------------------------------------------------------------ 0.20s
ipv6_disable : Désactivation de la prise en charge de l'IPv6 globalement -------------------------------------------------- 0.20s
dns_config : Suppression du fichier /etc/resolv.conf ---------------------------------------------------------------------- 0.19s
hostname_config : Modification du fichier /etc/hosts ---------------------------------------------------------------------- 0.19s
dns_config : Configuration du DNS dans /etc/resolved.conf ----------------------------------------------------------------- 0.19s
ipv6_disable : Désactivation de la prise en charge de l'IPv6 par défaut --------------------------------------------------- 0.14s
dns_config : Création du nouveau lien symbolique vers /etc/resolv.conf ---------------------------------------------------- 0.14s
security_ssh : Désactivaction de l'authentification par mot de passe ------------------------------------------------------ 0.14s
security_ssh : Activation de l'authentification par clé ------------------------------------------------------------------- 0.14s
3. Installation et configuration de Prometheus
Avant de procéder aux opérations ci-dessous, il est nécessaire d’installation
podmansur le serveur. Nous n’utilisons pasdockerpar soucis de compatibilité avecnftables.
sudo apt install podman -y
Configuration de podman pour que l’espace disque utilisé soit situé au niveau de la partition /var et non pas /home
sudo mkdir -p /var/lib/containers
sudo chown -R ngobert:ngobert /var/lib/containers
mkdir -p ~/.config/containers
Création du fichier ~/.config/containers/storage.conf
[storage]
driver = "overlay"
runroot = "/var/run/containers/storage"
graphroot = "/var/lib/containers/storage"
Restart du daemon podman
sudo systemctl restart podman
Une image prometheus est disponible sur DockerHub. Nous allons utiliser cette image pour héberger notre instance prometheus
Création du volume Docker pour la persistence de la données
sudo podman volume create prometheus-data
Création du répertoire /opt/prometheus
sudo mkdir -p /opt/prometheus
Modification du propriétaire et du groupe sur le répertoire précemment créé
sudo chown ngobert:ngobert /opt/prometheus
Création du fichier de configuration /opt/prometheus/prometheus.yml
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
# - "first.rules"
# - "second.rules"
alerting:
alertmanagers:
- static_configs:
- targets:
- localhost:9093
scrape_configs:
- job_name: prometheus-core
static_configs:
- targets: ['prometheus-core.homelab:9090']
- job_name: admin-core
static_configs:
- targets: ['admin-core.homelab:9090']
Exécution du container
sudo podman run -d \
-p 9090:9090 \
--name prometheus \
--network prometheus-network \
-v /opt/prometheus:/etc/prometheus \
-v prometheus-data:/prometheus \
docker.io/prom/prometheus \
--config.file=/etc/prometheus/prometheus.yml
Modification du fichier de configuration nftables /etc/nftables.conf pour autoriser les requêtes sur le port de prometheus tcp:9090 en provenance de rps-core. De plus, il faut autoriser le traffic forwardé via l’interface podman0 qui est le bridge par défaut pour les containers podman
#!/usr/sbin/nft -f
table inet filter {
chain input {
type filter hook input priority 0;
policy drop;
iif lo accept
ct state established,related accept
ip protocol icmp accept
ip saddr {{ 192.168.100.252, 192.168.100.250, 192.168.100.248 }} iifname "ens19" tcp dport 22 accept
ip saddr 192.168.100.242 tcp dport 9090 accept
}
chain forward {
type filter hook forward priority 0;
policy drop;
iifname "podman0" accept
oifname "podman0" accept
}
chain output {
type filter hook output priority 0;
policy accept;
}
}
Vérification de la syntaxe du fichier /etc/nftables.conf et restart du daemon nftables
sudo nft -c -f /etc/nftables.conf
sudo systemctl restart nftables
4. Ajout du vHost pormetheus.ng-hl.com sur le rps
Ajout du vHost
prometheus.ng-hl.comau niveau du reverse proxyrps-core. On passe encore une fois par Ansible pour réaliser les opérations.
Ajout du fichier templates/prometheus.conf.j2
server {
listen 80;
server_name {{ reverse_proxy_sup_prometheus }};
return 301 https://$host$request_uri;
}
server {
listen 443 ssl;
server_name {{ reverse_proxy_sup_prometheus }};
ssl_certificate {{ reverse_proxy_sup_ssl_dir }}/{{ reverse_proxy_sup_cert_file }};
ssl_certificate_key {{ reverse_proxy_sup_ssl_dir }}/{{ reverse_proxy_sup_key_file }};
ssl_protocols TLSv1.2 TLSv1.3;
ssl_ciphers HIGH:!aNULL:!MD5;
access_log /var/log/nginx/supervision_access.log;
error_log /var/log/nginx/supervision_error.log;
location / {
proxy_pass http://prometheus-core.homelab:9090/;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
}
}
Rajout des actions au niveau du fichier tasks/main.yml
- name: Déploiement de la configuration Nginx pour le vHost Prometheus
ansible.builtin.template:
src: prometheus.conf.j2
dest: /etc/nginx/sites-available/prometheus.conf
owner: root
group: root
mode: '0644'
- name: Activation de la configuration Nginx pour le vHost Prometheus
ansible.builtin.file:
src: /etc/nginx/sites-available/prometheus.conf
dest: /etc/nginx/sites-enabled/prometheus.conf
state: link
force: yes
notify: Redémarrer Nginx
5. Ajout des métriques Prometheus pour tous les serveurs (actions manuelles)
Nous allons utiliser NodeExporter pour mettre à disposition des métriques systèmes classiques tels que le CPU, la mémoire, l’utilisation de l’espace disque, etc. depuis nos serveurs clients afin que le serveur Prometheus puissent venir scraper les données et les intégrer dans sa base de données.
Cette section décrit les opérations manuelles pour l’installation du daemon
node_exporteret la configuration dePrometheuspour intégrer le scraping. Nous intégrons ces actions au sein d’un rôle Ansible dans la section suivante.
Se connecter sur le serveur admin-core. C’est sur ce serveur que l’on va réaliser les opérations.
Téléchargement de la version 1.6.1 de node_exporter
cd /tmp/ && wget https://github.com/prometheus/node_exporter/releases/download/v1.6.1/node_exporter-1.6.1.linux-amd64.tar.gz
Décompression de la tarball
tar xvf node_exporter-1.6.1.linux-amd64.tar.gz
Copie du binaire dans /usr/local/bin
sudo cp node_exporter-1.6.1.linux-amd64/node_exporter /usr/local/bin/
Création du daemon node_exporter
sudo tee /etc/systemd/system/node_exporter.service <<EOF
[Unit]
Description=Node Exporter
After=network.target
[Service]
User=node_exporter
ExecStart=/usr/local/bin/node_exporter
[Install]
WantedBy=default.target
EOF
Rechargement des daemons, activation au démarrage du système et immédiat
sudo systemctl daemon-reload
sudo systemctl start node_exporter
sudo systemctl enable node_exporter
Vérification de l’ouverture du port avec les métriques
curl http://localhost:9100/metrics
Il est important de vérifier que le flux est accepté sur le port 9100 pour les requêtes en provenance du serveur prometheus-core au niveau de nftables
Depuis le serveur prometheus-core
nc -vw 1 admin-core.homelab 9100
admin-core.homelab [192.168.100.252] 9100 (?) open
6. Ajout des métriques Prometheus pour tous les serveurs (Ansible)
Nous allons créer un playbook Ansible
01_prometheus_node_exporterpour installer et configurerNode Exportergrâce au rôlenode_exporter. Ainsi, nous allons pouvoir déployer node exporter et la configuration nécessaires sur les serveurs existants. Ce playbook sera également utilisé pour les futurs serveurs également.
Création du playbook 01_prometheus_node_exporter
---
- name: Déploiement de Node Exporter
hosts: prometheus_clients
become: true
roles:
- node_exporter
Création du rôle node_exporter
ansible-galaxy init roles/node_exporter
Contenu du fichier /defaults/main.yml
# SPDX-License-Identifier: MIT-0
---
# defaults file for roles/node_exporter
node_exporter_version: "1.6.1"
node_exporter_user: "node_exporter"
node_exporter_bin_path: "/usr/local/bin/node_exporter"
node_exporter_port: 9100
node_exporter_listen_address: "{{ ip }}"
Nous utilisons la host_var
ipdéfinie au niveau du fichier d’inventaire qui représente l’IP utilisée en interne, au sein du homelab. C’est important d’écouter uniquement sur cette interface car certains serveurs peuvent avoir des interfaces en bridge directement accessible depuis mon réseau local. Nous voulons éviter que le scraping des données soit accessible à l’extérieur du homelab.
Contenu du fichier /tasks/main.yml
# SPDX-License-Identifier: MIT-0
---
# tasks file for roles/node_exporter
- name: Création de l'utilisateur node_exporter
ansible.builtin.user:
name: "{{ node_exporter_user }}"
shell: /usr/sbin/nologin
system: true
create_home: false
- name: Téléchargement de Node Exporter
ansible.builtin.get_url:
url: >-
https://github.com/prometheus/node_exporter/releases/download/v{{ node_exporter_version }}/node_exporter-{{ node_exporter_version }}.linux-amd64.tar.gzlinux-amd64.tar.gz"
dest: "/tmp/node_exporter-{{ node_exporter_version }}.tar.gz"
mode: '0644'
- name: Décompression de Node Exporter
ansible.builtin.unarchive:
src: "/tmp/node_exporter-{{ node_exporter_version }}.tar.gz"
dest: /tmp
remote_src: true
- name: Copie du binaire dans /usr/local/bin
ansible.builtin.copy:
src: "/tmp/node_exporter-{{ node_exporter_version }}.linux-amd64/node_exporter"
dest: "{{ node_exporter_bin_path }}"
mode: '0755'
owner: root
group: root
remote_src: true
- name: Création du service systemd
ansible.builtin.copy:
dest: /etc/systemd/system/node_exporter.service
content: |
[Unit]
Description=Node Exporter
After=network.target
[Service]
User={{ node_exporter_user }}
ExecStart={{ node_exporter_bin_path }} --web.listen-address={{ node_exporter_listen_address }}:{{ node_exporter_port }}
[Install]
WantedBy=default.target
owner: root
group: root
mode: '0644'
notify: Restart node_exporter
- name: Activation et démarrage le service
ansible.builtin.systemd:
name: node_exporter
enabled: true
state: started
Contenu du fichier /handlers/main.yml
# SPDX-License-Identifier: MIT-0
---
# handlers file for roles/node_exporter
- name: Restart node_exporter
ansible.builtin.systemd:
name: node_exporter
state: restarted
Rajout du group prometheus au niveau du fichier d’inventaire /envs/100-core/00_inventory.yml
prometheus_clients:
hosts:
dns-core.homelab:
admin-core.homelab:
ansible-core.homelab:
vaultwarden-core.homelab:
gitlab-core.homelab:
prometheus-core.homelab:
grafana-core.homelab:
rps-core.homelab:
Application du linter ansible-lint sur le playbook 01_prometheus_node_exporter.yml
ansible-lint playbooks/01_prometheus_node_exporter.yml
Passed: 0 failure(s), 0 warning(s) on 6 files
Exécution sur un serveur spécifique. Penser à faire un snapshot avant l’exécution du playbook
ansible-playbook playbooks/01_prometheus_node_exporter.yml -l "dns-core.homelab"
Mise à jour du fichier de configuration /opt/prometheus/prometheus.yml sur le serveur prometheus-core
global:
scrape_interval: 15s
evaluation_interval: 15s
rule_files:
- "/etc/prometheus/rules/*.yml"
alerting:
alertmanagers:
- static_configs:
- targets:
- alertmanager-core.homelab:9093
scrape_configs:
- job_name: 'prometheus'
static_configs:
- targets: ['prometheus-core.homelab:9090']
- job_name: 'node_exporter'
static_configs:
- targets:
- admin-core.homelab:9100
- dns-core.homelab:9100
- ansible-core.homelab:9100
- acme-core.homelab:9100
- vaultwarden-core.homelab:9100
- gitlab-core.homelab:9100
- grafana-core.homelab:9100
- alertmanager-core.homelab:9100
- rps-core.homelab:9100
Cette section couvre la partie
Grafana
1. Création de la VM
Nous allons utiliser le template debian12-template créé lors du chapitre 4. Sur Proxmox on crée un clone complet à partir de ce template. Voici les caractéristiques de la VM :
| OS | Hostname | Adresse IP | Interface réseau | vCPU | RAM | Stockage |
|---|---|---|---|---|---|---|
| Debian 12.10 | grafana-core | 192.168.100.244 | vmbr1 (core) | 2 | 4096 | 20Gio + 10Gio |
Il faut également penser à activer la sauvegarde automatique de la VM sur Proxmox en l’ajoutant au niveau de la politique de sauvegarde précédemment créée.
Ajout du second disque de 10Gio sur le lv
/dev/debian12-vg/debian12-var-lv
2. Configuration de l’OS via Ansible
Les informations concernant Ansible sont disponibles au niveau des chapitres 7 et 8.
A présent, le playbook et les rôles ayant pour objectif d’appliquer la configuration de base de l’OS sont disponibles. Il faut se connecter en tant que l’utilisateur ansible sur le serveur ansible-core.homelab puis ajouter l’hôte grafana-core.homelab au niveau du fichier d’inventaire /opt/ansible/envs/100-core/00_inventory.yml avec les éléments suivants
grafana-core.homelab:
ip: 192.168.100.244
hostname: grafana-core
Pour exécuter le playbook, il faut lancer la commande suivante
ansible-playbook -i envs/100-core/00_inventory.yml -l 'grafana-core.homelab,' playbooks/00_config_vm.yml
Voici le récapitulatif
TASKS RECAP **********************************************************************************************************************
samedi 09 août 2025 23:19:15 +0200 (0:00:00.269) 0:00:14.525 ***********
===============================================================================
base_packages : Installation des paquets de base -------------------------------------------------------------------------- 3.81s
dns_config : Installation du paquet systemd-resolved ---------------------------------------------------------------------- 1.99s
base_packages : Mise à jour du cache apt ---------------------------------------------------------------------------------- 1.89s
Gathering Facts ----------------------------------------------------------------------------------------------------------- 1.07s
nftables : Activer et démarrer le service nftables ------------------------------------------------------------------------ 0.63s
dns_config : Autoremove et purge ------------------------------------------------------------------------------------------ 0.59s
motd : Déploiement du motd ------------------------------------------------------------------------------------------------ 0.46s
hostname_config : Modification du hostname -------------------------------------------------------------------------------- 0.44s
dns_config : Enable du daemon systemd-resolved ---------------------------------------------------------------------------- 0.39s
dns_config : Suppression du paquet resolvconf ----------------------------------------------------------------------------- 0.33s
nftables : Déploiement de la configuration de nftables -------------------------------------------------------------------- 0.32s
dns_config : Resart du daemon systemd-resolved ---------------------------------------------------------------------------- 0.31s
security_ssh : Restart du daemon sshd ------------------------------------------------------------------------------------- 0.27s
nftables : Valider la configuration nftables ------------------------------------------------------------------------------ 0.24s
ipv6_disable : Désactivation de la prise en charge de l'IPv6 globalement -------------------------------------------------- 0.20s
dns_config : Configuration du DNS dans /etc/resolved.conf ----------------------------------------------------------------- 0.20s
dns_config : Suppression du fichier /etc/resolv.conf ---------------------------------------------------------------------- 0.20s
hostname_config : Modification du fichier /etc/hosts ---------------------------------------------------------------------- 0.19s
dns_config : Création du nouveau lien symbolique vers /etc/resolv.conf ---------------------------------------------------- 0.14s
ipv6_disable : Désactivation de la prise en charge de l'IPv6 par défaut --------------------------------------------------- 0.14s
3. Installation et configuration de Grafana
Tout comme Prometheus, la solution Grafana va être déployée en container. Avant de procéder aux opérations ci-dessous, il est nécessaire d’installation
podmansur le serveur. Nous n’utilisons pasdockerpar soucis de compatibilité avecnftables.
sudo apt install podman -y
Configuration de podman pour que l’espace disque utilisé soit situé au niveau de la partition /var et non pas /home
sudo mkdir -p /var/lib/containers
sudo chown -R ngobert:ngobert /var/lib/containers
mkdir -p ~/.config/containers
Création du fichier ~/.config/containers/storage.conf
[storage]
driver = "overlay"
runroot = "/var/run/containers/storage"
graphroot = "/var/lib/containers/storage"
Restart du daemon podman
sudo systemctl restart podman
Une image prometheus est disponible sur DockerHub. Nous allons utiliser cette image pour héberger notre instance prometheus
Création du volume Docker pour la persistence de la données
sudo podman volume create grafana-data
Création du répertoire /opt/grafana
sudo mkdir -p /opt/grafana
Modification du propriétaire et du groupe sur le répertoire précemment créé
sudo chown ngobert:ngobert /opt/grafana
Création des répertoires nécessaires
mkdir -p /opt/grafana/provisioning/datasources
mkdir -p /opt/grafana/provisioning/dashboards
mkdir -p /opt/grafana/dashboards/node_exporter
Création du fichier de configuration /opt/grafana/provisioning/datasources/prometheus_datasources.yml
apiVersion: 1
datasources:
- name: Prometheus
type: prometheus
access: proxy
url: http://prometheus-core.homelab:9090
isDefault: true
Création du fichier de configuration /opt/grafana/provisioning/dashboards/dashboards.yml
apiVersion: 1
providers:
- name: 'Node Exporter Dashboards'
orgId: 1
folder: ''
type: file
disableDeletion: false
updateIntervalSeconds: 10
options:
path: /var/lib/grafana/dashboards/node-exporter
Création du fichier /opt/grafana/dashboards/node_exporter/node_exporter_full.json avec le contenu du fichier de ce lien
Exécution du container
sudo podman run -d \
--name grafana \
-p 3000:3000 \
-v grafana-data:/var/lib/grafana \
-v /opt/grafana/provisioning:/etc/grafana/provisioning \
-v /opt/grafana/dashboards:/var/lib/grafana/dashboards \
-e "GF_SERVER_ROOT_URL=https://grafana.ng-hl.com/" \
-e "GF_SERVER_SERVE_FROM_SUB_PATH=true" \
docker.io/grafana/grafana:latest
Modification du fichier de configuration nftables /etc/nftables.conf pour autoriser les requêtes sur le port de Grafana tcp:3000 en provenance de rps-core. De plus, il faut autoriser le traffic forwardé via l’interface podman0 qui est le bridge par défaut pour les containers podman
#!/usr/sbin/nft -f
table inet filter {
chain input {
type filter hook input priority 0;
policy drop;
iif lo accept
ct state established,related accept
ip protocol icmp accept
ip saddr {{ 192.168.100.252, 192.168.100.250, 192.168.100.248 }} iifname "ens19" tcp dport 22 accept
ip saddr 192.168.100.242 tcp dport 3000 accept
}
chain forward {
type filter hook forward priority 0;
policy drop;
iifname "podman0" accept
oifname "podman0" accept
}
chain output {
type filter hook output priority 0;
policy accept;
}
}
Vérification de la syntaxe du fichier /etc/nftables.conf et restart du daemon nftables
sudo nft -c -f /etc/nftables.conf
sudo systemctl restart nftables
Pour se connecter sur l’interface de Grafana on tape cette url https://grafana.ng-hl.com. On saisie les credentials par défaut admin/admin pour la première connexion. On peut observer que le datasource Prometheus est bien fonctionnel et que le dashboard Node Exporter Full est accessible.
Cette section couvre la partie
AlertManager. L’envoi de mail est fonctionnelle uniquement après avec mis en place le serveur mailmail-core, voir le chapitre 14.
1. Création de la VM
Nous allons utiliser le template debian12-template créé lors du chapitre 4. Sur Proxmox on crée un clone complet à partir de ce template. Voici les caractéristiques de la VM :
| OS | Hostname | Adresse IP | Interface réseau | vCPU | RAM | Stockage |
|---|---|---|---|---|---|---|
| Debian 12.10 | alertmanager-core am-core (CNAME) | 192.168.100.243 | vmbr1 (core) | 1 | 2048 | 20Gio |
Il faut également penser à activer la sauvegarde automatique de la VM sur Proxmox en l’ajoutant au niveau de la politique de sauvegarde précédemment créée.
2. Configuration de l’OS via Ansible
Les informations concernant Ansible sont disponibles au niveau des chapitres 7 et 8.
A présent, le playbook et les rôles ayant pour objectif d’appliquer la configuration de base de l’OS sont disponibles. Il faut se connecter en tant que l’utilisateur ansible sur le serveur ansible-core.homelab puis ajouter l’hôte am-core.homelab au niveau du fichier d’inventaire /opt/ansible/envs/100-core/00_inventory.yml avec les éléments suivants
am-core.homelab:
ip: 192.168.100.243
hostname: am-core
Pour exécuter le playbook, il faut lancer la commande suivante
ansible-playbook -i envs/100-core/00_inventory.yml -l 'alertmanager-core.homelab,' playbooks/00_config_vm.yml
Voici le récapitulatif
TASKS RECAP **********************************************************************************************************************
mardi 12 août 2025 12:14:58 +0200 (0:00:00.259) 0:00:14.391 ************
===============================================================================
base_packages : Installation des paquets de base -------------------------------------------------------------------------- 3.78s
dns_config : Installation du paquet systemd-resolved ---------------------------------------------------------------------- 1.99s
base_packages : Mise à jour du cache apt ---------------------------------------------------------------------------------- 1.85s
Gathering Facts ----------------------------------------------------------------------------------------------------------- 1.05s
nftables : Activer et démarrer le service nftables ------------------------------------------------------------------------ 0.63s
dns_config : Autoremove et purge ------------------------------------------------------------------------------------------ 0.60s
motd : Déploiement du motd ------------------------------------------------------------------------------------------------ 0.46s
hostname_config : Modification du hostname -------------------------------------------------------------------------------- 0.44s
dns_config : Enable du daemon systemd-resolved ---------------------------------------------------------------------------- 0.39s
dns_config : Suppression du paquet resolvconf ----------------------------------------------------------------------------- 0.33s
nftables : Déploiement de la configuration de nftables -------------------------------------------------------------------- 0.31s
dns_config : Resart du daemon systemd-resolved ---------------------------------------------------------------------------- 0.30s
security_ssh : Restart du daemon sshd ------------------------------------------------------------------------------------- 0.26s
nftables : Valider la configuration nftables ------------------------------------------------------------------------------ 0.24s
hostname_config : Modification du fichier /etc/hosts ---------------------------------------------------------------------- 0.21s
ipv6_disable : Désactivation de la prise en charge de l'IPv6 globalement -------------------------------------------------- 0.20s
dns_config : Configuration du DNS dans /etc/resolved.conf ----------------------------------------------------------------- 0.20s
dns_config : Suppression du fichier /etc/resolv.conf ---------------------------------------------------------------------- 0.19s
ipv6_disable : Désactivation de la prise en charge de l'IPv6 par défaut --------------------------------------------------- 0.14s
dns_config : Création du nouveau lien symbolique vers /etc/resolv.conf ---------------------------------------------------- 0.14s
Exécution du playbook d’installation de node_exporter
ansible-playbook -i envs/100-core/00_inventory.yml -l 'alertmanager-core.homelab,' playbooks/01_prometheus_node_exporter.yml
Voici le récapitulatif
TASKS RECAP **********************************************************************************************************************
mardi 12 août 2025 12:19:30 +0200 (0:00:00.460) 0:00:04.472 ************
===============================================================================
Gathering Facts ----------------------------------------------------------------------------------------------------------- 1.02s
node_exporter : Décompression de Node Exporter ---------------------------------------------------------------------------- 0.83s
node_exporter : Téléchargement de Node Exporter --------------------------------------------------------------------------- 0.67s
node_exporter : Activation et démarrage le service ------------------------------------------------------------------------ 0.62s
node_exporter : Restart node_exporter ------------------------------------------------------------------------------------- 0.46s
node_exporter : Copie du binaire dans /usr/local/bin ---------------------------------------------------------------------- 0.31s
node_exporter : Création du service systemd ------------------------------------------------------------------------------- 0.29s
node_exporter : Création de l'utilisateur node_exporter ------------------------------------------------------------------- 0.26s
Il faut mettre à jour le fichier de configuration
/opt/prometheus/prometheus.ymlsurprometheus-coreet relancer le containerprometheus.
3. Installation et configuration de AlertManager
Tout comme Prometheus et Grafana, la solution AlertManager va être déployée en container. Avant de procéder aux opérations ci-dessous, il est nécessaire d’installation
podmansur le serveur. Nous n’utilisons pasdockerpar soucis de compatibilité avecnftables.
sudo apt install podman -y
Configuration de podman pour que l’espace disque utilisé soit situé au niveau de la partition /var et non pas /home
sudo mkdir -p /var/lib/containers
sudo chown -R ngobert:ngobert /var/lib/containers
mkdir -p ~/.config/containers
Création du fichier ~/.config/containers/storage.conf
[storage]
driver = "overlay"
runroot = "/var/run/containers/storage"
graphroot = "/var/lib/containers/storage"
Restart du daemon podman
sudo systemctl restart podman
Création du volume pour la persistence des données
sudo podman volume create am-data
Création de la structure des répertoires
sudo mkdir -p /opt/alertmanager/{config,data}
sudo chown -R ngobert:ngobert /opt/alertmanager
Création du fichier /opt/alertmanager/config/alertmanager.yml
global:
resolve_timeout: 5m
smtp_smarthost: 'mail-core.homelab:25'
smtp_from: 'xxxxxxx'
smtp_require_tls: false
route:
receiver: 'email-alerts'
group_by: ['alertname', 'instance']
group_wait: 30s
group_interval: 5m
repeat_interval: 4h
receivers:
- name: 'email-alerts'
email_configs:
- to: 'xxxxxxx'
send_resolved: true
headers:
from: 'Homelab Supervision <xxxxxx>'
subject: '{{ range .Alerts }}[ALERTE] {{ .Labels.alertname }} - {{ .Labels.severity }} - {{ .Status }}{{ end }}'
html: |
<html>
<body style="font-family: Arial, sans-serif; color: #333;">
{{ range .Alerts }}
<div style="border:1px solid #ccc; padding:10px; margin-bottom:10px; border-radius:5px;">
<h2 style="color: {{ if eq .Status "firing" }}#d9534f{{ else }}#5cb85c{{ end }};">
{{ if eq .Status "firing" }}🚨 ALERTE{{ else }}✅ RESOLU{{ end }} : {{ .Labels.alertname }}
</h2>
<p><b>Gravité :</b> {{ .Labels.severity }}</p>
<p><b>Instance :</b> {{ .Labels.instance }}</p>
<p><b>Description :</b> {{ .Annotations.description }}</p>
<p><b>Résumé :</b> {{ .Annotations.summary }}</p>
</div>
{{ end }}
<hr>
<p style="font-size:0.9em; color:#777;">
Alerte générée par <a href="{{ .ExternalURL }}">{{ .ExternalURL }}</a>
</p>
</body>
</html>
Exécution du container
sudo podman run -d \
--name alertmanager \
-p 9093:9093 \
-v am-data:/alertmanager \
-v /opt/alertmanager/config/alertmanager.yml:/etc/alertmanager/alertmanager.yml \
docker.io/prom/alertmanager:latest \
--config.file=/etc/alertmanager/alertmanager.yml \
--storage.path=/alertmanager
Cette section couvre la partie
self-checkde la stack d’observabilité / supervision. L’objectif est d’envoyer un mail vers l’extérieur tous les jours à 9h pour valider le bon fonctionnement de la châine d’alerting (Prometheus -> AlertManager -> Mail). L’envoi de mail est fonctionnelle uniquement après avoir mis en place le serveur mailmail-core, voir le chapitre 14.
La mise en place de la persistence des données n’est pas nécessaire dès maintenant. Cependant, je choisi dès maintenant de stocker les données dans un volume et de gérer la persistence depuis pushgateway pour un futur usage.
Création du volume pushgateway-data
sudo podman volume create pushgateway-data
Exécution du container pushgateway sur le serveur prometheus-core
sudo podman run -d \
--name pushgateway \
--network prometheus-network \
-p 9091:9091 \
-v pushgateway-data:/data \
prom/pushgateway:latest \
--persistence.file=/data/pushgateway.db \
--persistence.interval=5m
Modification de la configuration de prometheus
# Elément à ajouter dans la section "scrape_configs"
- job_name: 'pushgateway'
static_configs:
- targets: ['pushgateway:9091']
Validation du fonctionnement de pushgateway et de l’intégration de la métrique dans prometheus via la requête suivante exécutée depuis le serveur prometheus-core
# Envoi de la métrique
echo "supervision_selfcheck 1" | curl --data-binary @- http://localhost:9091/metrics/job/selfcheck
# Affichage
curl -s "http://localhost:9090/api/v1/query?query=supervision_selfcheck"
{"status":"success","data":{"resultType":"vector","result":[{"metric":{"__name__":"supervision_selfcheck","exported_job":"selfcheck","instance":"pushgateway:9091","job":"pushgateway"},"value":[1755592850.958,"1"]}]}}
# Ou
curl -s "https://prometheus.ng-hl.com/api/v1/query?query=supervision_selfcheck"
{"status":"success","data":{"resultType":"vector","result":[{"metric":{"__name__":"supervision_selfcheck","exported_job":"selfcheck","instance":"pushgateway:9091","job":"pushgateway"},"value":[1755592778.682,"1"]}]}}
Création du fichier de rule /opt/prometheus/rules/selfcheck_alerts.yml
groups:
- name: selfcheck
rules:
- alert: DailySelfcheck
expr: (time() - timestamp(supervision_selfcheck{exported_job="selfcheck"})) < 600
for: 1m
labels:
severity: info
team: monitoring
annotations:
summary: "Test quotidien de la supervision ✅"
description: "Supervision OK ✅"
Sur le serveur alertmanager-core, modification de la configuration de alertmanager via le fichier /opt/alertmanager/config/alertmanager.yml
# A ajouter au niveau de la section route
routes:
- match:
alertname: "DailySelfcheck"
receiver: 'mail-selfcheck'
group_wait: 30s
group_interval: 5m
repeat_interval: 24h
# A la fin du fichier
- name: 'mail-selfcheck'
email_configs:
- to: 'xxxxxxxxxx'
send_resolved: true
headers:
from: 'Homelab Supervision <xxxxxx>'
subject: '[Supervision] 🔔 Self-check quotidien'
html: |
<html>
<body style="font-family: Arial, sans-serif; color: #333;">
{{ range .Alerts }}
<div style="border:1px solid #5cb85c; padding:10px; margin-bottom:10px; border-radius:5px;">
<h2 style="color:#5cb85c;">✅ Self-check quotidien : {{ .Labels.alertname }}</h2>
<p><b>Description :</b> {{ .Annotations.description }}</p>
<p><b>Résumé :</b> {{ .Annotations.summary }}</p>
</div>
{{ end }}
<hr>
<p style="font-size:0.9em; color:#777;">
Alerte générée par <a href="{{ .ExternalURL }}">{{ .ExternalURL }}</a>
</p>
</body>
</html>
Mise en place du cron sur prometheus-core
crontab -e
0 9 * * * echo "supervision_selfcheck 1" | curl --data-binary @- http://localhost:9091/metrics/job/selfcheck; sleep 180; curl -X DELETE http://localhost:9091/metrics/job/selfcheck