Node Exporter: métricas de sistema com Prometheus

Node Exporter é o agente do Prometheus para métricas do sistema operacional, CPU, memória, disco, rede, filesystems e dezenas de outras. Roda como daemon leve no servidor e expõe um endpoint /metrics que o Prometheus coleta a cada 15 segundos. É o ponto de partida para monitoramento de qualquer VPS Linux.

Instalar Node Exporter como serviço systemd

Instalação direta no host (não em container) para métricas mais precisas:

bash
# Baixar a versão mais recente do Node Exporter:
NODE_EXPORTER_VERSION="1.8.2"
wget "https://github.com/prometheus/node_exporter/releases/download/v${NODE_EXPORTER_VERSION}/node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64.tar.gz"
tar xf "node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64.tar.gz"
sudo cp "node_exporter-${NODE_EXPORTER_VERSION}.linux-amd64/node_exporter" /usr/local/bin/
sudo chmod +x /usr/local/bin/node_exporter

# Criar usuário dedicado (sem shell, sem home):
sudo useradd -rs /bin/false node_exporter

# Criar serviço systemd:
sudo tee /etc/systemd/system/node_exporter.service << 'EOF'
[Unit]
Description=Prometheus Node Exporter
After=network.target

[Service]
User=node_exporter
Group=node_exporter
Type=simple
ExecStart=/usr/local/bin/node_exporter   --web.listen-address=127.0.0.1:9100   --collector.filesystem.mount-points-exclude='^/(sys|proc|dev|host|etc)($|/)'   --collector.systemd   --collector.processes

[Install]
WantedBy=multi-user.target
EOF

sudo systemctl daemon-reload
sudo systemctl enable --now node_exporter

# Verificar que está respondendo:
curl -s http://127.0.0.1:9100/metrics | head -20

Configurar scrape no Prometheus

Adicionar Node Exporter ao prometheus.yml:

yaml
# prometheus.yml — adicionar job do Node Exporter:
scrape_configs:
  - job_name: 'node'
    static_configs:
      - targets:
          - 'localhost:9100'     # mesmo servidor do Prometheus
          - '10.0.0.2:9100'     # outros servidores (IPs internos)
          - '10.0.0.3:9100'
    relabel_configs:
      # Usar hostname como label instance:
      - source_labels: [__address__]
        target_label: instance
        regex: '([^:]+)(?::\d+)?'

  # Para múltiplos servidores com descoberta por arquivo:
  - job_name: 'node-file-sd'
    file_sd_configs:
      - files:
          - '/etc/prometheus/targets/*.yml'
        refresh_interval: 1m

# /etc/prometheus/targets/servers.yml:
# - targets: ['10.0.0.2:9100', '10.0.0.3:9100']
#   labels:
#     env: production
#     datacenter: sp01

# Recarregar Prometheus após mudança:
curl -X POST http://localhost:9090/-/reload

Alertas de sistema com Node Exporter

Regras de alerta para CPU, memória e disco cheio:

yaml
# alerts/sistema.yml:
groups:
  - name: sistema
    rules:

      # CPU alta por mais de 5 minutos:
      - alert: CpuUsageAlta
        expr: |
          100 - (avg by (instance) (
            rate(node_cpu_seconds_total{mode="idle"}[5m])
          ) * 100) > 85
        for: 5m
        labels:
          severity: warning
        annotations:
          summary: "CPU acima de 85% em {{ $labels.instance }}"
          description: "Uso atual: {{ $value | printf "%.1f" }}%"

      # Memória livre abaixo de 10%:
      - alert: MemoriaLivreBaixa
        expr: |
          (node_memory_MemAvailable_bytes / node_memory_MemTotal_bytes * 100) < 10
        for: 5m
        labels:
          severity: critical
        annotations:
          summary: "Memória livre abaixo de 10% em {{ $labels.instance }}"
          description: "Livre: {{ $value | printf "%.1f" }}%"

      # Disco quase cheio (aviso aos 80%, crítico aos 90%):
      - alert: DiscoQuaseCheioCritico
        expr: |
          (
            node_filesystem_size_bytes{mountpoint="/", fstype!="tmpfs"}
            - node_filesystem_free_bytes{mountpoint="/", fstype!="tmpfs"}
          ) / node_filesystem_size_bytes{mountpoint="/", fstype!="tmpfs"} * 100 > 90
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Disco acima de 90% em {{ $labels.instance }}"

      # Servidor não responde (sem métricas):
      - alert: ServidorForaDoAr
        expr: up{job="node"} == 0
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Servidor {{ $labels.instance }} inacessível"

Coletar métricas de serviços systemd

Monitorar status de serviços com o collector systemd:

yaml
# O flag --collector.systemd habilita métricas de serviços systemd.
# Métricas disponíveis:
# node_systemd_unit_state{name="nginx.service", state="active"} 1
# node_systemd_unit_state{name="postgresql.service", state="failed"} 1

# Alertas para serviços críticos fora do ar:
# alerts/servicos.yml:
groups:
  - name: servicos-systemd
    rules:
      - alert: ServicoFalhou
        expr: |
          node_systemd_unit_state{
            name=~"nginx.service|postgresql.service|node-api.service|redis.service",
            state="failed"
          } == 1
        for: 1m
        labels:
          severity: critical
        annotations:
          summary: "Serviço {{ $labels.name }} falhou em {{ $labels.instance }}"

      - alert: ServicoParado
        expr: |
          node_systemd_unit_state{
            name=~"nginx.service|postgresql.service",
            state="active"
          } == 0
        for: 2m
        labels:
          severity: critical
        annotations:
          summary: "Serviço {{ $labels.name }} não está ativo"

# Verificar métricas do systemd:
curl -s http://localhost:9100/metrics | grep node_systemd_unit_state | grep -v "^#"

Node Exporter via Docker Compose

Usar Node Exporter em container (com acesso ao host via volumes):

yaml
# docker-compose.yml — Node Exporter em container com acesso ao host:
services:
  node-exporter:
    image: prom/node-exporter:latest
    container_name: node-exporter
    pid: host          # necessário para métricas de processo do host
    network_mode: host # usar rede do host para latência mínima
    volumes:
      - /proc:/host/proc:ro
      - /sys:/host/sys:ro
      - /:/rootfs:ro
    command:
      - '--path.procfs=/host/proc'
      - '--path.rootfs=/rootfs'
      - '--path.sysfs=/host/sys'
      - '--web.listen-address=127.0.0.1:9100'
      - '--collector.filesystem.mount-points-exclude=^/(sys|proc|dev|host|etc)($|/)'
    restart: unless-stopped

# ATENÇÃO: com network_mode: host, o container usa a rede do host diretamente.
# O port não precisa ser mapeado — já está em localhost:9100

# Verificar que coleta métricas do host (não do container):
docker exec node-exporter wget -qO- http://127.0.0.1:9100/metrics |   grep node_memory_MemTotal_bytes

Não quer configurar manualmente?

Implante o VPS Linux em menos de 5 minutos com a Runstack. Infraestrutura da OPEN Datacenter, com servidores em São Paulo.

Perguntas frequentes

Host (systemd service): mais preciso para métricas de sistema, acesso direto a /proc e /sys sem overhead de virtualização. Recomendado para produção. Container com pid: host e volumes de /proc, /sys, /: métricas quase idênticas ao host, mas com overhead mínimo de namespace. A diferença prática é negligenciável para a maioria dos casos. A vantagem do container é a facilidade de atualização com docker compose pull.

Extremamente leve: ~5-15MB de RAM, < 0.1% de CPU em operação normal. O scrape a cada 15s gera um spike mínimo de CPU enquanto lê /proc. Para VPS com 512MB de RAM: absolutamente viável. A porta 9100 deve ficar em 127.0.0.1 (não acessível externamente), o Prometheus acessa internamente.

CPU: node_cpu_seconds_total (por modo: user, system, idle, iowait). Memória: node_memory_MemAvailable_bytes, node_memory_MemTotal_bytes. Disco: node_filesystem_size_bytes, node_filesystem_free_bytes, node_disk_io_time_seconds_total. Rede: node_network_receive_bytes_total, node_network_transmit_bytes_total. Load: node_load1, node_load5, node_load15. Para dashboards prontos: importe o Grafana Dashboard ID 1860 (Node Exporter Full) que cobre todas essas métricas com painéis bem organizados.

Instale Node Exporter em cada servidor e adicione cada IP:9100 ao prometheus.yml. Para não editar manualmente: use file_sd_configs (lê de arquivo YAML com lista de targets), ou consul_sd_configs (descoberta via Consul), ou ec2_sd_configs (para AWS EC2). Com file SD: basta adicionar o novo servidor ao arquivo de targets, o Prometheus recarrega automaticamente conforme o refresh_interval configurado.

Por padrão não, a porta 9100 expõe métricas sem autenticação. Solução: bind em 127.0.0.1 (só o Prometheus local acessa) ou usar TLS + basic auth. O Node Exporter 1.5+ suporta TLS nativo e basic auth via arquivo de configuração web. Para acesso remoto seguro: use tunel SSH (ssh -L 9100:localhost:9100 servidor) ou VPN. Para UFW: sudo ufw deny 9100 e deixar apenas o Prometheus (127.0.0.1) acessar.