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>:3001, takže např.: http://10.66.0.81:3100. Výchozí login je admin / admin.

Dashboard

Mnou vyrobené dashboardy ke stažení:

    Linux node - Monitoring Linuxového operačního systému.
      Download: Linux node-1740661792430.json Screenshot: nginx - Monitoring webového serveru nginx s použitím GeoIP Lite databází od maxmind.
        Download: nginx-1740661550827.json Screenshot:
        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
        

        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"
               }
        }
        

        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 ;-)