feat: monitoring — node_exporter + ROCm sysfs collector + alertmanager webhook

Ansible roles:
- node_exporter : déploie node_exporter v1.9.1 sur storage-01 et gpu-01
  avec textfile collector + services systemd. ROCm activé sur gpu-01 uniquement
  via group_vars. Collecte métriques GPU via sysfs (temp, VRAM, utilisation)
  — pas de dépendance rocm-smi (remplacé dans ROCm 7.x)
- alertmanager_webhook : service Python sur storage-01 (:9093/webhook)
  reçoit alertes AlertManager et les route vers ask-agent monitor → Hermes

Playbooks: node_exporter + alertmanager_webhook ajoutés à storage-01 et gpu-01

Co-Authored-By: Claude Sonnet 4.6 <noreply@anthropic.com>
This commit is contained in:
alkatrazz 2026-05-13 21:01:03 +02:00
parent 857351bcf9
commit 92a882aa94
15 changed files with 354 additions and 2 deletions

View file

@ -0,0 +1,11 @@
---
node_exporter_version: "1.9.1"
node_exporter_port: 9100
node_exporter_user: node_exporter
node_exporter_install_dir: /opt/node_exporter
node_exporter_textfile_dir: /var/lib/node_exporter/textfile_collector
# ROCm scraper (gpu-01 uniquement)
rocm_exporter_enabled: false
rocm_exporter_port: 9101
rocm_scrape_interval: 30

View file

@ -0,0 +1,18 @@
---
- name: Restart node_exporter
ansible.builtin.systemd:
name: node_exporter
state: restarted
daemon_reload: true
- name: Reload nftables
ansible.builtin.systemd:
name: nftables
state: reloaded
- name: Enable rocm_scraper timer
ansible.builtin.systemd:
name: rocm_scraper.timer
enabled: true
state: restarted
daemon_reload: true

View file

@ -0,0 +1,86 @@
---
- name: Create node_exporter user
ansible.builtin.user:
name: "{{ node_exporter_user }}"
shell: /sbin/nologin
create_home: false
system: true
state: present
- name: Create textfile collector directory
ansible.builtin.file:
path: "{{ node_exporter_textfile_dir }}"
state: directory
owner: "{{ node_exporter_user }}"
group: "{{ node_exporter_user }}"
mode: '0755'
- name: Download 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.gz"
dest: "/tmp/node_exporter-{{ node_exporter_version }}.tar.gz"
mode: '0644'
- name: Extract node_exporter
ansible.builtin.unarchive:
src: "/tmp/node_exporter-{{ node_exporter_version }}.tar.gz"
dest: /tmp/
remote_src: true
creates: "/tmp/node_exporter-{{ node_exporter_version }}.linux-amd64/node_exporter"
- name: Install node_exporter binary
ansible.builtin.copy:
src: "/tmp/node_exporter-{{ node_exporter_version }}.linux-amd64/node_exporter"
dest: /usr/local/bin/node_exporter
owner: root
group: root
mode: '0755'
remote_src: true
- name: Deploy node_exporter systemd service
ansible.builtin.template:
src: node_exporter.service.j2
dest: /etc/systemd/system/node_exporter.service
mode: '0644'
notify: Restart node_exporter
- name: Enable and start node_exporter
ansible.builtin.systemd:
name: node_exporter
enabled: true
state: started
daemon_reload: true
- name: Open node_exporter port in nftables
ansible.builtin.lineinfile:
path: /etc/nftables.conf
insertafter: '# prometheus'
line: " tcp dport {{ node_exporter_port }} accept comment \"node_exporter\""
state: present
notify: Reload nftables
ignore_errors: true
- name: Deploy ROCm scraper script
ansible.builtin.template:
src: rocm_scraper.sh.j2
dest: /usr/local/bin/rocm_scraper.sh
mode: '0755'
when: rocm_exporter_enabled
- name: Deploy ROCm scraper service + timer
ansible.builtin.template:
src: "{{ item }}.j2"
dest: "/etc/systemd/system/{{ item }}"
mode: '0644'
loop:
- rocm_scraper.service
- rocm_scraper.timer
when: rocm_exporter_enabled
- name: Enable ROCm scraper timer
ansible.builtin.systemd:
name: rocm_scraper.timer
enabled: true
state: started
daemon_reload: true
when: rocm_exporter_enabled

View file

@ -0,0 +1,18 @@
[Unit]
Description=Prometheus Node Exporter
After=network.target
[Service]
User={{ node_exporter_user }}
Group={{ node_exporter_user }}
ExecStart=/usr/local/bin/node_exporter \
--web.listen-address=":{{ node_exporter_port }}" \
--collector.textfile.directory={{ node_exporter_textfile_dir }} \
--collector.systemd \
--collector.processes
Restart=on-failure
RestartSec=5s
[Install]
WantedBy=multi-user.target

View file

@ -0,0 +1,7 @@
[Unit]
Description=ROCm metrics scraper for Prometheus textfile collector
After=multi-user.target
[Service]
Type=oneshot
ExecStart=/usr/local/bin/rocm_scraper.sh

View file

@ -0,0 +1,33 @@
#!/bin/bash
# Collecte les métriques GPU AMD via sysfs (pas de rocm-smi requis)
OUTPUT="{{ node_exporter_textfile_dir }}/rocm.prom"
TMPFILE="${OUTPUT}.tmp"
{
echo "# HELP rocm_gpu_temperature_celsius GPU temperature in Celsius"
echo "# TYPE rocm_gpu_temperature_celsius gauge"
echo "# HELP rocm_gpu_utilization_percent GPU utilization percentage"
echo "# TYPE rocm_gpu_utilization_percent gauge"
echo "# HELP rocm_vram_used_bytes VRAM used in bytes"
echo "# TYPE rocm_vram_used_bytes gauge"
echo "# HELP rocm_vram_total_bytes VRAM total in bytes"
echo "# TYPE rocm_vram_total_bytes gauge"
for card in /sys/class/drm/card[0-9]; do
[ -d "$card/device" ] || continue
idx=$(basename "$card" | tr -d 'card')
labels="gpu=\"${idx}\",model=\"gfx1031\""
temp_raw=$(cat "$card/device/hwmon/hwmon"*/temp1_input 2>/dev/null | head -1)
[ -n "$temp_raw" ] && echo "rocm_gpu_temperature_celsius{${labels}} $(echo "scale=1; ${temp_raw}/1000" | bc)"
util=$(cat "$card/device/gpu_busy_percent" 2>/dev/null)
[ -n "$util" ] && echo "rocm_gpu_utilization_percent{${labels}} ${util}"
vram_used=$(cat "$card/device/mem_info_vram_used" 2>/dev/null)
[ -n "$vram_used" ] && echo "rocm_vram_used_bytes{${labels}} ${vram_used}"
vram_total=$(cat "$card/device/mem_info_vram_total" 2>/dev/null)
[ -n "$vram_total" ] && echo "rocm_vram_total_bytes{${labels}} ${vram_total}"
done
} > "$TMPFILE" && mv "$TMPFILE" "$OUTPUT"

View file

@ -0,0 +1,11 @@
[Unit]
Description=ROCm metrics scraper timer
Requires=rocm_scraper.service
[Timer]
OnBootSec=30s
OnUnitActiveSec={{ rocm_scrape_interval }}s
AccuracySec=5s
[Install]
WantedBy=timers.target