Skip to main content

Monitoring pomocí Grafana + Loki + Prometheus

Instalace

Server (ten, který sbírá data)

Prometheus

V případě Debianu a jemu podobných stačí nainstalovat balíček prometheus:

apt -y update
apt -y install prometheus

Nastavení se nachází na dvou místech:

  • /etc/default/prometheus => Nastavení jak se má server spouštět. Já do ARGS doplnil --storage.tsdb.retention.time=90d, aby se mi uchovávalo "pouze" 90 dní dat.
  • /etc/prometheus/prometheus.yml => Nastavení collectoru, sběrače dat. Zde nastavujeme odkud chceme tahat metriky a jaké.

prometheus.yml

V základu používám node_exporter na Linux a Windows s touto konfigurací. Data sbírám každou minutu, monitoruji i sám sebe a to každou minutu. Každou minutu také zpracovávám pravidla (které tady žádné nemám), alertmanager vystavuji na portu 9093 a adresy serverů ukládám do labelu instance.

# Sample config for Prometheus.

global:
  scrape_interval:     1m # Set the scrape interval. Default is every 1 minute.
  evaluation_interval: 1m # Evaluate rules every x seconds. The default is every 1 minute.
  scrape_timeout: 30s  # scrape_timeout. Global default is (10s).

  # Attach these labels to any time series or alerts when communicating with
  # external systems (federation, remote storage, Alertmanager).
  external_labels:
      monitor: 'promgraf'

# Alertmanager configuration
alerting:
  alertmanagers:
  - static_configs:
    - targets: ['localhost:9093']

# Load rules once and periodically evaluate them according to the global 'evaluation_interval'.
rule_files:
  # - "first_rules.yml"
  # - "second_rules.yml"

# A scrape configuration containing exactly one endpoint to scrape:
# Here it's Prometheus itself.
scrape_configs:

  - job_name: 'linux_nodes'
    metrics_path: /metrics
    static_configs:
      - targets:
          - localhost:9100
          - mujlinux.bali.cz
    relabel_configs:
      - source_labels: [__address__]
        regex: (.*):(9100)
        target_label: instance
        replacement: '${1}'

  - job_name: 'windows_nodes'
    metrics_path: /metrics
    static_configs:
      - targets:
          - mojewidle.bali.cz:9100
    relabel_configs:
      - source_labels: [__address__]
        regex: (.*):(9100)
        target_label: instance
        replacement: '${1}'

No.. a aby nám to celé fungovalo tak ještě potřebuji aby se Prometheus dostal ke klientům. nftables pravidlo vypadá takto:

#!/usr/sbin/nft -f
table inet filter {
        chain OUTPUT {
                tcp dport 9100 accept comment "Allow connection to prometheus exporter targets - OUT"
        }
}

Grafana + Loki

Grafanu a Lokiho instalujeme z repozitářů grafany dle našeho systému.

Pro Debian Linux potřebuji přidat repozitář s gpg klíčem a poté mohu instalovat:

echo 'deb https://apt.grafana.com stable main' | sudo tee /etc/apt/sources.list.d/grafana-oss.list
curl https://apt.grafana.com/gpg.key | gpg --dearmor > /etc/apt/trusted.gpg.d/grafana.gpg
apt -y update
apt -y install grafana loki

Grafana

Grafana má konfiguraci v /etc/grafana. Přistupujeme na <adresu serveru>:3100, takže např.: http://10.66.0.81:3100. Výchozí login je admin / admin.

Dashboard

Mnou vyrobené dashboardy ke stažení:

Cisco - Monitoring Cisco zařízení pomocí SNMP a rsyslogu.
    Download: Cisco-1760814321242.json Screenshot:
      Přehled 1 Cisco - Network devices - Dashboards - Grafana.png Rozhraní 2 Cisco - Network devices - Dashboards - Grafana.png Logy 3 Cisco - Network devices - Dashboards - Grafana.png Uptime a data o délce sběru informací 4 Cisco - Network devices - Dashboards - Grafana.png
      Provisioned datasources

      Grafaně dokážeme přednastavit zdroje dat pomocí yaml konfiguračních souborů. V následujících ukázkových souborech nastavuji Prometheus a Loki jako zdroje dat běžící na stejném serveru jako Grafana (localhost).

      Prometheus datasource
      # Configuration file version
      apiVersion: 1
      
      # Localhost loki datasource
      datasources:
        - name: Prometheus
          type: prometheus
          access: proxy
          url: http://localhost:9090
          isDefault: true
          jsonData:
            timeInterval: 60s
            timeout: 60
      
      
      Loki datasource
      # Configuration file version
      apiVersion: 1
      
      # Localhost loki datasource
      datasources:
        - name: Loki
          type: loki
          access: proxy
          url: http://localhost:3100
          jsonData:
            timeout: 60
            maxLines: 5000
      
      Authentication
      Entra ID

      🗒️ Oficiální návod je k dispozici ZDE

      Jak nastavíme přihlášení pomocí vlastní Entra ID ?

      • EntraID

        • Vytvořit App registration.
        • Authentication => [ + Add a platform ] => Web => Nastavit Redirect URI na https://grafana.example.com/login/azuread + https://<grafana.example.com
        • Certificates & secrets
          • [ + New client secret ] => < Pojmenovat si klíč a nastavit platnost (volil bych nejdelší - 24 měsíců) > => [Add]. Zkopírovat HODNOTU (Value), nikoliv Secret ID a uložit si jej někam (později jej budeme potřebovat)
          • [ + New federated credential ]:
            • Federated credential scenario: Other issuer
            • Issuer: https://login.microsoftonline.com/<TENANT-ID>/v2.0
            • Name: Nějak si to pojmenovat 🤷‍♂️
            • Description: třeba: "Grafana OAuth."
            • Audience: api://AzureADTokenExchange
        • API permissions
          • [ + Add a permission ] => Microsoft Graph => Delegated permissions => Nyní máme dvě možnosti jak nastavit oprávnění ke čtení uživatelského profilu. Buď pomocí vybrání jednotlivých oprávnění nebo obecného User.Read (Sign in and read user profile).
            • OpenId permissions

              🗒️ User.Read => Allows users to sign-in to the app, and allows the app to read the profile of signed-in users. It also allows the app to read basic company information of signed-in users.
              GroupMember.Read.All => Allows the app to list groups, read basic group properties and read membership of all groups the signed-in user has access to.

              • email (Může být použito User.Read)
              • openid (Může být použito User.Read)
              • profile (Může být použito User.Read)
            • => [ Add permissions ]
      • Grafana

        • Client Id => <Application (client) ID>
        • Client secret => Zde vyplnit Value z client secret vytvořeného v Entra Id
        • Scopes => openid, email, profile
        • FIC managed identity client Id => Zde vyplnit <Application (client) ID>
        • FIC audience => api://AzureADTokenExchange

      Loki

      Loki má konfiguraci v /etc/loki/config.yml. Má základní konfigurace:

      • Poslouchá na portu 3100
      • Ukládá data do /var/lib/loki
      • Odstraňuje data starší 90 dní
        auth_enabled: false
        
        server:
          http_listen_port: 3100
          grpc_listen_port: 9096
          log_level: warn
          grpc_server_max_concurrent_streams: 2000
        
        common:
          instance_addr: 127.0.0.1
          path_prefix: /var/lib/loki
          storage:
            filesystem:
              chunks_directory: /var/lib/loki/chunks
              rules_directory: /var/lib/loki/rules
          replication_factor: 1
          ring:
            kvstore:
              store: inmemory
        
        query_range:
          results_cache:
            cache:
              embedded_cache:
                enabled: true
                max_size_mb: 2048
        
        limits_config:
          metric_aggregation_enabled: true
          max_query_lookback: 2160h #90d
          retention_period: 2160h #90d
        
        compactor:
         working_directory: /tmp/loki/retention
         retention_enabled: true
         retention_delete_delay: 24h
         delete_request_store: filesystem
        
        schema_config:
          configs:
            - from: 2020-10-24
              store: tsdb
              object_store: filesystem
              schema: v13
              index:
                prefix: index_
                period: 24h
        
        pattern_ingester:
          enabled: true
          metric_aggregation:
            loki_address: localhost:3100
        
        ruler:
          alertmanager_url: http://localhost:9093
        
        frontend:
          encoding: protobuf
        

      ⚠️ Před Lokiho je potřeba přidat proxy s autentizací protože sám Loki tuto vrstvu nemá (viz Grafana docs). Základní zabezpečení pomocí nginx je popsáno zde. Mimo jiné je možné si jej alespoň v rámci interní sítě omezit pomocí firewallu:

      #!/usr/sbin/nft -f
      table inet filter {
             chain INPUT {
                     ip saddr 10.66.0.0/24 tcp dport 3100 accept comment "Allow Loki target from my services subnet - IN"
             }
      }
      

      rsyslog

      Tento nástroj používáme pro odchytávání logů pomocí syslogu ze zařízení jako jsou switche. rsyslog má konfiguraci v /etc/rsyslog.conf a /etc/rsyslog.d.

      • Nainstalovat:

        apt -yq install rsyslog
        
      • V /etc/rsyslog.d si vytvořit konfigurační soubor:

        • pro "nastartování vysílače" / serveru který bude zachytávat logy které do něj budeme posílat, 01-remote_server.conf:
          # Enable imudp, UDP Syslog Input Module
          # https://www.rsyslog.com/doc/configuration/modules/imudp.html
          module(load="imudp")
          input(type="imudp" port="514")
          
          # Enable imutcp, TCP Syslog Input Module
          # https://www.rsyslog.com/doc/configuration/modules/imtcp.html
          module(load="imtcp")
          input(type="imtcp" port="601")
          
          # Allow receiving from localhost and local network
          #$AllowedSender UDP, 127.0.0.1, 10.0.0.0/8
          #$AllowedSender TCP, 127.0.0.1, 10.0.0.0/8
          

          💡 Dle poznámky lze omezit z jakých adres/subnetů budeme přijímat komunikaci.

        • pro logování například Cisco switche si nastavím 10-cisco_switch.conf který bude ukládat logy do speciální podsložky a bude zde řadit klienty z určitých adres či logy obsahující určité zprávy:
          template(name="Cisco_Switch" type="string" string="/var/log/remote/cisco/%HOSTNAME%.log")
          
          :fromhost-ip, regex, "^10\.39\.\7.\.*" -?Cisco_Switch
          :msg, contains, " sw-a1269-hardcore.net.cvut.it:" -?Cisco_Switch
          
      • Povolit provoz na UDP a TCP porty v nftables (v mém případě do interních sítí):

        ip saddr 10.0.0.0/8 tcp dport 601 accept comment "Allow rsyslog on internal sites (TCP/601) - IN"
        ip saddr 10.0.0.0/8 udp dport 514 accept comment "Allow rsyslog on internal sites (UDP/514) - IN"
        

      Klient (monitorovaný server)

      Prometheus

      Balíčky Promethea jsou u Debianu a z něj vycházejících distribucí většinou přímo v repozitářích. Základem je node_exporter který nám exportuje základní údaje o stavu operačního systému (packages.debian.org)

      apt -y update
      apt -y install prometheus-node-exporter
      

      V případě používání nftables je potřeba vytvořit příchozí pravidlo pro port 9100 aby si mohl Prometheus vyzvedávat metriky.
      Příklad, ve kterém je 10.66.0.81 náš Prometheus collector (server který sbírá data a jmenuje se promgraf dle komentáře pravidla).

      #!/usr/sbin/nft -f
      table inet filter {
              chain INPUT {
                      ip saddr 10.66.0.81 tcp dport 9100 accept comment "Allow Prometheus metrics access from promgraf - IN"
              }
      

      💡 Prometheus lze nastavit, aby sbíral textové soubory jako metriky, které ale musí být v kompatibilním formátu.
      (např.: nfsd_cc{hostname="pc666-105.domena",ip="10.66.6.105",path="/srv/linux/debian/shared"} 1 jako soubor nfsd_cc.prom). Do tohoto souboru zapisujeme řádky pomocí sponge z balíčku moreutils.

      /etc/default/prometheus:

      # Set the command-line arguments to pass to the server.
      # Due to shell escaping, to pass backslashes for regexes, you need to double
      # them (\\d for \d). If running under systemd, you need to double them again
      # (\\\\d to mean \d), and escape newlines too.
      ARGS=""
      # To collect text files in this directory, add the line to ARGS variable.
      # There might be APT or some other metrics already.
      # --collector.textfile.directory="/var/lib/prometheus/node-exporter"
      

      Alloy

      Linux

      Konfiguraci Alloy bych doporučil rozložit do souborů a nastavit, aby služba brala konfiguraci ze složky místo výchozího /etc/default/config.alloy.
      Nastavení se provede přidáním cesty do proměnné CUSTOM_ARGS jako posledního parametru (pokud zde mají být i jiné přepínače, cesta musí být poslední). Následně ostraním výchozí konfiguraci v /etc/alloy/config.alloy, protože zde budu dávat vlastní configy.

      • /etc/default/alloy:

        ## Path:
        ## Description: Grafana Alloy settings
        ## Type:        string
        ## Default:     ""
        ## ServiceRestart: alloy
        #
        # Command line options for Alloy.
        #
        # The configuration file holding the Alloy config.
        #CONFIG_FILE="/etc/alloy/config.alloy"
        
        # User-defined arguments to pass to the run command.
        # Specified <PATH_NAME> to include directory: https://grafana.com/docs/alloy/latest/reference/cli/run/
        CUSTOM_ARGS="/etc/alloy"
        
        # Restart on system upgrade. Defaults to true.
        RESTART_ON_UPGRADE=true
        
      • /etc/alloy

        • 00-config.alloy - výchozí obecná nastavení

          // For a full configuration reference, see https://grafana.com/docs/alloy
          // Log only warnings and more
          logging {
            level = "warn"
          }
          
        • 01-endpoint.alloy - nastavení endpointu => Loki serveru na který se budou posílat data. více informací
          Zde se vyplňuje adresa ve tvaru: <http(s)>/<FQDN>/<Ingest endpoint>. Jako příklad uvedu svou konfiguraci:

          // Data will be sent to this loki instance
          loki.write "endpoint" {
            endpoint {
              url = "http://promgraf.in.cvut.it:3100/loki/api/v1/push"
              // basic_auth {
              //  username = "admin"
              //  password = "admin"
              // }
            }
          }
          
        • 09-journal-relabel.alloy - Základní nastavení journal collectoru (sbírání logů z systemd systémových služeb).

          // Setup journal relabel rules
          loki.relabel "journal" {
            forward_to = []
                  rule {
                          target_label  = "instance"
                          replacement = constants.hostname
                  }
                  rule {
                          source_labels = ["__journal__systemd_unit"]
                          target_label  = "unit"
                  }
          }
          
        • 10-varlog-collector.alloy - Nastavení sběru všech logů z /var/log s příponou souboru (suffixem) .log

          // Setup varlogs job with labels
          discovery.relabel "varlogs" {
          
                  // Read .log files from /var/log, recursively
                  targets = [{
                          __address__  = "localhost",
                          __path__     = "/var/log/**/*.log",
                          service_name = "varlogs",
                  }]
                  rule {
                          target_label  = "instance"
                          replacement = constants.hostname
                  }
          }
          
          // Match files defined in relabel target
          local.file_match "varlogs" {
                  path_targets = discovery.relabel.varlogs.output
          }
          
          // Send files to loki endpoint
          loki.source.file "varlogs" {
                  targets               = local.file_match.varlogs.targets
                  forward_to            = [loki.write.endpoint.receiver]
          }
          
        • 50-journal-ssh.alloy - Odesílání logů systemd jednotky (unit) ssh.service.

          loki.source.journal "ssh" {
            matches        = "_SYSTEMD_UNIT=ssh.service _SYSTEMD_UNIT=sshguard.service"
            format_as_json = true
            relabel_rules  = loki.relabel.journal.rules
            forward_to     = [loki.write.endpoint.receiver]
          }
          
        • 51-journal-monitoring.alloy - Odesílání logů systemd jednotek (units) alloy.service a prometheus-node-exporter.service. Sledujeme tímto stav služeb které nám mají za úkol poskytovat metriky a logy.

          loki.source.journal "alloy" {
            matches        = "_SYSTEMD_UNIT=alloy.service"
            format_as_json = true
            relabel_rules  = loki.relabel.journal.rules
            forward_to     = [loki.write.endpoint.receiver]
          }
          
          loki.source.journal "prometheus_node_exporter" {
            matches        = "_SYSTEMD_UNIT=prometheus-node-exporter.service"
            format_as_json = true
            relabel_rules  = loki.relabel.journal.rules
            forward_to     = [loki.write.endpoint.receiver]
          }
          
        • /etc/alloy/52-journal-journal.alloy/ - Odesílání logů systemd jednotky (unit) systemd-journald.service.

          loki.source.journal "systemd_journald" {
            matches        = "_SYSTEMD_UNIT=systemd-journald.service"
            format_as_json = true
            relabel_rules  = loki.relabel.journal.rules
            forward_to     = [loki.write.endpoint.receiver]
          }
          

      Windows

      TBD ;-)