No description
  • Jinja 53.3%
  • Python 46.7%
Find a file
grenn 5b13a3b527 feat: check Node Exporter connectivity from Prometheus nodes
- probe metrics endpoints from each Prometheus node
- restrict server-only checks to observability_servers
- report source-target results and aggregate failures
- add standalone connectivity playbook and local tests
- document usage in README.md and usage.md
2026-09-29 14:27:53 +02:00
files/grafana/dashboards fix: set Loki logs dashboard default time range to 3 hours 2026-09-28 13:50:58 +02:00
inventory_example feat: add guarded Node Exporter migration and separate management playbooks 2026-09-28 21:31:11 +02:00
playbooks feat: check Node Exporter connectivity from Prometheus nodes 2026-09-29 14:27:53 +02:00
roles feat: check Node Exporter connectivity from Prometheus nodes 2026-09-29 14:27:53 +02:00
tests feat: check Node Exporter connectivity from Prometheus nodes 2026-09-29 14:27:53 +02:00
.gitignore feat: add guarded Node Exporter migration and separate management playbooks 2026-09-28 21:31:11 +02:00
ansible.cfg-example . 2026-08-11 17:57:19 +02:00
ARCHITEKTURA.md docs: add architecture diagrams and component port reference 2026-09-28 22:33:47 +02:00
README.md feat: check Node Exporter connectivity from Prometheus nodes 2026-09-29 14:27:53 +02:00
requirements.yml fix(requirements): correct system role 2026-08-13 14:01:38 +02:00
usage.md feat: check Node Exporter connectivity from Prometheus nodes 2026-09-29 14:27:53 +02:00

Platforma observability

Repozytorium zawiera konfigurację Ansible dla platformy observability na RHEL 9 i RHEL 10. Implementacja obejmuje przygotowanie hostów, bezpieczną obsługę storage oraz centralne komponenty etcd, PostgreSQL HA z Patroni, HAProxy, Grafana, Prometheus, Alertmanager, Loki, Alloy, rsyslog i Node Exporter.

Schemat rozmieszczenia komponentów, kierunki komunikacji i porty znajdują się w graficznym opisie architektury.

Inventory

Repozytorium zawiera wyłącznie przykładową strukturę:

inventory_example/

Przed pierwszym wdrożeniem należy utworzyć lokalne inventory:

cp -a inventory_example inventory

Katalog inventory/ jest ignorowany przez Git i ustawiony jako domyślny w ansible.cfg. Należy w nim zmienić hosty, adresy, parametry storage, repozytoria, opcjonalne mirrory registry i pozostałe wartości środowiskowe. Sekretów nie wolno przenosić do inventory_example/.

Na hoście korzystającym jeszcze ze starego układu należy przed pierwszym pobraniem tej zmiany skopiować właściwe inventory poza repozytorium:

cp -a inventories/production ../observability-inventory
test -f ../observability-inventory/hosts.ini
git pull --ff-only
ln -s ../observability-inventory inventory

Inventory może również znajdować się całkowicie poza repozytorium:

cp -a inventory_example ../observability-inventory
chmod 0750 ../observability-inventory
ln -s ../observability-inventory inventory

Dowiązanie inventory także jest ignorowane przez Git. Dzięki temu:

git pull --ff-only

aktualizuje role, playbooki i inventory_example/, ale nie zmienia lokalnego inventory używanego do wdrożeń. Nowe zmienne z przykładu należy scalać ręcznie, po wcześniejszym porównaniu:

diff -ru inventory_example/ inventory/

Ansible użyje lokalnego inventory domyślnie; można je również wskazać jawnie:

ansible-playbook -i inventory/hosts.ini playbooks/preflight.yml

Źródła obrazów i pakietów

Każda rola kontenerowa ma domyślną nazwę obrazu dostawcy i publiczne registry: quay.io albo docker.io. Nie trzeba definiować lokalnego registry. Wspólny mirror lub uporządkowaną listę registry można ustawić przez:

observability_container_registries:
  - registry-primary.example.internal
  - registry-secondary.example.internal

Pierwszy adres buduje referencję obrazu. Lista jest również zapisywana w konfiguracji Podmana. Dla pojedynczego komponentu można nadpisać jego zmienną <component>_container_registries, nazwę przez <component>_container_repository, a wersję lub digest przez odpowiednią zmienną komponentu. Pusta lista wspólna przywraca publiczne registry dostawcy.

Instalacje aplikacyjnych pakietów RPM najpierw korzystają z repozytoriów już aktywnych. Dopiero po nieudanej próbie rola sprawdza kolejno identyfikatory z <component>_package_repositories. Brak pakietu w jednym repozytorium nie kończy playbooka; błąd jest zgłaszany dopiero po wyczerpaniu całej listy. Nazwy pakietów również mają wartości domyślne i mogą zostać nadpisane w inventory.

Pełne wdrożenie i walidacja

Playbook playbooks/site.yml wdraża cały system w dwóch etapach. Część server przygotowuje hosty i storage, instaluje centralne komponenty, uzgadnia firewall oraz wykonuje końcowe walidacje klastrów i endpointów. Część integrations instaluje Alloy i Node Exporter na hostach wskazanych w inventory, podłącza je do Prometheusa, Loki i Grafany oraz zarządza dozwolonymi źródłami rsyslog.

Pełne wdrożenie:

ansible-playbook -i inventory/hosts.ini playbooks/site.yml \
  --ask-vault-pass --extra-vars /group_vars/vault.yml

Tylko platforma serwerowa:

ansible-playbook -i inventory/hosts.ini playbooks/site.yml --tags server \
  --ask-vault-pass --extra-vars /group_vars/vault.yml

Tylko dodanie lub uzgodnienie monitorowanych hostów i urządzeń:

ansible-playbook -i inventory/hosts.ini playbooks/site.yml --tags integrations \
  --ask-vault-pass --extra-vars /group_vars/vault.yml

Można również uruchamiać bezpośrednio site_server.yml albo site_integrations.yml. Po dodaniu hosta do grup alloy, node_exporter albo monitoring_network_syslog wystarczy ponowić część integracyjną.

site_server.yml wykonuje przygotowanie wspólne raz na host w bootstrap.yml. Playbooki komponentów pomijają rolę observability_common tylko na hostach, które ukończyły bootstrap w bieżącym uruchomieniu. Hosty spoza grupy bootstrapu oraz samodzielnie uruchamiane playbooki komponentów nadal wykonują przygotowanie. Polityka firewalla jest stosowana przed uruchomieniem usług i ponownie uzgadniana na końcu wdrożenia. serial: 1 nadal oznacza osobny przebieg zadań dla każdego hosta.

site_server.yml zawiera storage.yml, ale nie omija zabezpieczeń storage. Pierwsza inicjalizacja pustych, ręcznie zweryfikowanych dysków nadal wymaga jawnego:

-e observability_storage_allow_initialization=true

Bez tej wartości istniejący poprawny storage może zostać zweryfikowany lub rozszerzony, ale nowy dysk nie zostanie zainicjalizowany.

Tryb --check nie wykonuje walidacji runtime endpointów i pełnych ścieżek danych, ponieważ sprawdza konfigurację, która nie została jeszcze zastosowana. Walidacje są wykonywane podczas normalnego uruchomienia site.yml albo przez dedykowane playbooki *_validate.yml uruchomione bez --check.

Kolejność uruchamiania

Najpierw należy zainstalować wymagane kolekcje:

ansible-galaxy collection install -r requirements.yml

Następnie można wykonać walidację bez zmian systemowych:

ansible-playbook -i inventory/hosts.ini playbooks/preflight.yml

Konfigurację bazową wykonuje playbook:

ansible-playbook -i inventory/hosts.ini playbooks/bootstrap.yml

Storage jest konfigurowany oddzielnie, po sprawdzeniu mapowania urządzeń:

ansible-playbook -i inventory/hosts.ini playbooks/storage.yml

Bezpieczeństwo storage

Inicjalizacja nowych urządzeń jest domyślnie wyłączona:

observability_storage_allow_initialization: false

Wartość true wolno ustawić wyłącznie po ręcznej weryfikacji mapowania urządzeń dla konkretnego hosta. Rola zawsze odmawia działania po wykryciu partycji, obcego LVM, RAID, LUKS, istniejącego innego filesystemu, zamontowanego urządzenia lub nierozpoznanej sygnatury.

Poprawnie istniejące PV, VG, LV i XFS mogą być bezpiecznie rozszerzane bez włączania inicjalizacji.

Rozszerzanie storage systemowego

playbooks/system_storage.yml rozszerza istniejące partycje LVM na dysku systemowym, a następnie przekazuje konfigurację storage_pools do roli linux-system-roles.storage, która rozszerza LV i filesystem. Playbook nie tworzy brakujących wolumenów i nie pozwala na ich zmniejszanie.

Domyślnym dyskiem jest /dev/sda:

observability_system_disk_uuid: ""
observability_system_disk_device: /dev/sda

Na hostach, na których nazwa urządzenia może się zmieniać, można podać UUID partycji znajdującej się bezpośrednio na właściwym dysku:

observability_system_disk_uuid: "00000000-0000-0000-0000-000000000000"

UUID jest rozwiązywany przez blkid -U, a dysk nadrzędny przez lsblk. Nie należy podawać UUID filesystemu znajdującego się wewnątrz LV, ponieważ jego bezpośrednim rodzicem jest urządzenie device-mapper, a nie dysk fizyczny.

Przykład konfiguracji zgodnej z linux-system-roles.storage:

storage_safe_mode: true
storage_pools:
  - name: system_vg
    type: lvm
    state: present
    volumes:
      - name: var_lv
        size: 10 GiB
        mount_point: /var
        fs_type: xfs
        state: present

Jeżeli system_vg ma wystarczającą liczbę wolnych extentów, rozszerzane są tylko LV i filesystem. Gdy wolnego miejsca w VG brakuje, playbook dopuszcza rozszerzenie wyłącznie pojedynczego PV będącego partycją na wybranym dysku. Najpierw growpart --dry-run potwierdza możliwość wykorzystania wolnego miejsca, następnie wykonywane są growpart i pvresize. Dopiero później rola systemowa rozszerza LV i filesystem.

Zmiana tablicy partycji wymaga jawnej zgody:

observability_system_storage_allow_partition_growth: true

Sprawdzenie planu:

ansible-playbook -i inventory/hosts.ini playbooks/system_storage.yml --check --diff

Jeżeli cloud-utils-growpart nie jest jeszcze zainstalowany, pierwsze uruchomienie z --check pokaże plan instalacji pakietu i odroczy analizę partycji. Po normalnej instalacji pakietu kolejne uruchomienie --check wykona kompletną kontrolę topologii i growpart --dry-run.

Wdrożenie:

ansible-playbook -i inventory/hosts.ini playbooks/system_storage.yml

Automatyczne rozszerzenie jest odrzucane dla wielu PV w jednym VG, PV na całym dysku, partycji znajdującej się na innym dysku oraz sytuacji, w której growpart --dry-run nie potwierdzi dostępnego miejsca. Taką topologię należy obsłużyć świadomie poza tym playbookiem.

Polityka dostępu firewalld

Porty komponentów wewnętrznych są chronione centralną polityką observability_firewall_rules zdefiniowaną w lokalnym inventory. Role aplikacyjne nie otwierają samodzielnie szerokich reguł portowych.

Publicznie otwarte pozostają wyłącznie frontendy HAProxy:

  • 80/tcp dla przekierowania HTTP do HTTPS;
  • 443/tcp dla interfejsu Grafany.

Grafana, Prometheus, Alertmanager, Loki, Alloy, Node Exporter, Patroni, PostgreSQL oraz etcd są dostępne tylko dla adresów hostów z wymaganych grup inventory. Adresy źródłowe są pobierane najpierw z ansible_host, a przy jego braku z zebranego domyślnego adresu IPv4 lub IPv6. Wynik musi być stałym adresem IP; nazwy DNS nie są używane w rich rules. Endpoint PostgreSQL HAProxy na porcie 5000 słucha wyłącznie na 127.0.0.1, ponieważ korzysta z niego lokalna Grafana.

Centralna rola najpierw dodaje wymagane rich rules, a dopiero potem usuwa szerokie reguły portowe. Zarządzany stan jest zapisywany w:

/etc/observability/managed-firewall-rules.json

Pierwsze wdrożenie wykonuje również seryjną migrację lokalnego endpointu PostgreSQL HAProxy i konfiguracji Grafany. Najpierw należy sprawdzić plan:

ansible-playbook -i inventory/hosts.ini playbooks/network_hardening.yml \
  --check --diff --ask-vault-pass \
  --extra-vars @inventory/group_vars/vault.yml

Następnie można wykonać migrację:

ansible-playbook -i inventory/hosts.ini playbooks/network_hardening.yml \
  --ask-vault-pass --extra-vars @inventory/group_vars/vault.yml

Uzgadnianie reguł po zmianach inventory

Na każdym zarządzanym serwerze rola porównuje aktualnie wymagane reguły ze stanem zapisanym w /etc/observability/managed-firewall-rules.json. Najpierw dodaje nowe rich rules, następnie usuwa reguły, których nie wymaga już bieżące inventory, i zapisuje nowy stan. Zarówno dodawanie, jak i usuwanie dotyczy konfiguracji runtime oraz permanentnej firewalld. Rola nie usuwa reguł utworzonych ręcznie lub przez inne role.

Po usunięciu hosta z grupy źródłowej jego adres zostanie usunięty z rich rules na pozostałych serwerach. Jeśli host został usunięty z grupy komponentowej, ale nadal należy do observability_servers, playbook uzgodni również jego lokalny firewall. Host całkowicie usunięty z inventory nie jest już celem Ansible, dlatego jego własny firewall nie może zostać automatycznie wyczyszczony. Bezpieczna procedura wycofania hosta wygląda następująco:

  1. Usunąć host z grup komponentowych i grup źródłowych, pozostawiając jego definicję w inventory.
  2. Uruchomić playbooks/firewall.yml i sprawdzić usunięcie zbędnych reguł.
  3. Dopiero potem usunąć definicję hosta z inventory.

Po każdej zmianie grup samą politykę można uzgadniać niezależnie:

ansible-playbook -i inventory/hosts.ini playbooks/firewall.yml --check --diff
ansible-playbook -i inventory/hosts.ini playbooks/firewall.yml

Po wdrożeniu reguły aktywnej strefy można wyświetlić poleceniem:

firewall-cmd --get-active-zones
firewall-cmd --zone=internal --list-all

Porty rsyslog pozostają zarządzane oddzielnie przez playbooks/rsyslog_sources.yml, ponieważ ich źródłami są urządzenia spoza inventory serwerów observability. Poprzedni stan jest przechowywany na collectorach w /etc/observability/rsyslog-rich-rules.yml. Usunięcie urządzenia z grupy monitoring_network_syslog i ponowne wykonanie tego playbooka usuwa jego rich rules z każdego collectora. Pusta grupa usuwa wszystkie reguły źródłowe zarządzane przez tę rolę.

Klaster etcd

Trzywęzłowy klaster etcd działa jako rootful Podman Quadlet na hostach należących do grupy etcd. Nazwy członków oraz lista peerów są generowane dynamicznie na podstawie kolejności hostów w inventory.

Przed instalacją etcd należy wykonać bootstrap hostów:

ansible-playbook -i inventory/hosts.ini playbooks/bootstrap.yml

Następnie można sprawdzić plan instalacji:

ansible-playbook -i inventory/hosts.ini playbooks/etcd.yml --check --diff

Instalację klastra wykonuje polecenie:

ansible-playbook -i inventory/hosts.ini playbooks/etcd.yml --diff

Etcd domyślnie używa obrazu quay.io/coreos/etcd. Opcjonalny mirror ustawia się przez observability_container_registries. Wersję ustawia etcd_container_version, a niezmienny digest można przypiąć przez etcd_container_digest. Zmiana składu działającego klastra nie może być wykonywana wyłącznie przez edycję grupy inventory — wymaga procedury dodawania lub usuwania członka etcd.

TLS jest kontrolowany przez etcd_tls_enabled. Po jego włączeniu certyfikaty serwera, peera i klienta muszą zostać wcześniej dostarczone poza repozytorium Git, np. przez Ansible Vault lub zewnętrzny secrets manager.

Operacyjna obsługa etcd

Stan klastra można sprawdzić bez zmiany usług:

ansible-playbook -i inventory/hosts.ini playbooks/etcd_validate.yml

Status usługi oraz endpointów można sprawdzić playbookiem serwisowym:

ansible-playbook -i inventory/hosts.ini playbooks/etcd_service.yml

Kontrolowany restart jest wykonywany kolejno, po jednym członku klastra:

ansible-playbook -i inventory/hosts.ini playbooks/etcd_service.yml -e etcd_service_action=restart

Dostępne akcje to status, start i restart. Zatrzymywanie całego klastra nie jest udostępnione przez ten playbook.

HAProxy dla PostgreSQL

HAProxy działa na hostach grupy haproxy i udostępnia lokalnej Grafanie stały endpoint PostgreSQL pod 127.0.0.1:5000. Backend jest generowany dynamicznie z grupy patroni; zapytanie Patroni /primary sprawia, że ruch trafia wyłącznie do aktualnego lidera.

Instalacja i walidacja obu endpointów odbywa się kolejno:

ansible-playbook -i inventory/hosts.ini playbooks/haproxy.yml

HTTPS dla Grafany

HAProxy udostępnia obie instancje Grafany przez HTTPS na porcie 443 i przekierowuje ruch HTTP z portu 80. Pliki TLS znajdują się w /etc/haproxy/certs:

  • grafana.crt — certyfikat;
  • grafana.key — klucz prywatny;
  • grafana.pem — bundle używany przez HAProxy.

Jeżeli grafana.crt nie istnieje, rola generuje klucz RSA 3072 bit i certyfikat samopodpisany ważny przez 10 lat. Istniejący certyfikat nie jest nadpisywany i musi mieć odpowiadający mu plik grafana.key. Certyfikat wystawiony przez właściwe CA należy dostarczyć przed uruchomieniem roli.

PostgreSQL HA i Patroni

PostgreSQL działa na hostach grupy postgresql, a Patroni zarządza członkami z grupy patroni. Dane znajdują się na przygotowanym wcześniej XFS pod /var/lib/pgsql. Rola nie uruchamia postgresql-setup; inicjalizacja PGDATA należy wyłącznie do Patroni.

Nazwy pakietów można dostosować przez postgresql_packages oraz patroni_packages. Role najpierw instalują je z aktywnych repozytoriów, a następnie kolejno próbują identyfikatorów z postgresql_package_repositories i patroni_package_repositories. Puste listy oznaczają użycie wyłącznie aktywnych repozytoriów. Przed instalacją należy dostarczyć trzy sekrety przez Ansible Vault lub zewnętrzny secrets manager:

patroni_superuser_password: "..."
patroni_replication_password: "..."
patroni_rewind_password: "..."

Przykładowe uruchomienie z zaszyfrowanym plikiem Vault:

ansible-playbook -i inventory/hosts.ini playbooks/postgresql_ha.yml \
  --ask-vault-pass \
  --extra-vars @inventory/group_vars/vault.yml

Najpierw można sprawdzić plan zmian:

ansible-playbook -i inventory/hosts.ini playbooks/postgresql_ha.yml \
  --check --diff \
  --ask-vault-pass \
  --extra-vars @inventory/group_vars/vault.yml

Alertmanager

Dwie instancje Alertmanagera działają w klastrze na hostach grupy alertmanager. Interfejs WWW i API używają portu 9093, a komunikacja klastra portu 9096/tcp i 9096/udp, ponieważ port 9094 jest zajęty przez Grafana Alerting HA.

Domyślnym obrazem jest quay.io/prometheus/alertmanager:v0.33.1; opcjonalnie może pochodzić ze skonfigurowanego mirrora. Początkowa konfiguracja używa odbiornika noop: alerty są grupowane i widoczne w Alertmanagerze, ale nie są wysyłane na zewnętrzny kanał.

Instalacja klastra i podłączenie obu Prometheusów:

ansible-playbook -i inventory/hosts.ini playbooks/alertmanager.yml

Walidacja klastra:

ansible-playbook -i inventory/hosts.ini playbooks/alertmanager_validate.yml

Kontrolowany restart:

ansible-playbook -i inventory/hosts.ini playbooks/alertmanager_service.yml   -e alertmanager_service_action=restart

Przed uruchomieniem powiadomień produkcyjnych należy zastąpić odbiornik noop konfiguracją SMTP, webhooka lub wybranego systemu obsługi incydentów.

Prometheus

Dwie niezależne instancje Prometheusa działają na hostach grupy prometheus. Każda zapisuje własne TSDB na XFS pod /var/lib/prometheus, odpytuje te same cele i nie replikuje danych do drugiego węzła. Domyślna retencja wynosi 30 dni, a limit danych 155 GB. Interfejs HTTP i API nasłuchują na porcie 9095, ponieważ port 9090 jest zarezerwowany dla Cockpit.

Prometheus domyślnie używa obrazu quay.io/prometheus/prometheus. Wersję ustawia prometheus_container_version, a wybrany digest można przypiąć przez prometheus_container_digest.

Instalacja z lokalnego inventory:

ansible-playbook -i inventory/hosts.ini playbooks/prometheus.yml

Walidacja obu instancji, ich API i self-scrape:

ansible-playbook -i inventory/hosts.ini playbooks/prometheus_validate.yml

Kontrolowany restart po jednym węźle:

ansible-playbook -i inventory/hosts.ini playbooks/prometheus_service.yml   -e prometheus_service_action=restart

Dodatkowe zadania scrape można przekazać przez prometheus_additional_scrape_configs.

Loki

Loki działa w trybie monolithic na hostach grupy loki. Używa TSDB ze schematem v13, zapisuje chunki i dane Compactor w /var/lib/loki, a WAL oraz lokalny indeks i cache w /var/lib/loki-wal. Oba katalogi muszą być wcześniej przygotowanymi i zamontowanymi filesystemami XFS. Rola Loki nie inicjalizuje, nie formatuje ani nie montuje dysków.

Domyślna retencja wynosi 14 dni (336h) i jest egzekwowana przez Compactor. Backend filesystem jest ustawiony w przykładowym inventory. Rola zawiera również wariant s3; jego dane dostępowe należy przekazać przez Ansible Vault lub zewnętrzny secrets manager.

Domyślnym obrazem jest docker.io/grafana/loki:3.7.4; opcjonalnie może pochodzić ze skonfigurowanego mirrora. Tag ustawia loki_container_version, a digest można przypiąć przez loki_container_digest.

Przygotowanie storage jest oddzielone od instalacji i ograniczone przez hosts: logging_nodes, więc nie uruchamia preflight ani roli storage na monitoring nodes. Po ręcznej weryfikacji, że urządzenia są właściwe i puste:

ansible-playbook -i inventory/hosts.ini playbooks/loki_storage.yml \
  --check --diff \
  -e observability_storage_allow_initialization=true

ansible-playbook -i inventory/hosts.ini playbooks/loki_storage.yml \
  --diff \
  -e observability_storage_allow_initialization=true

Instalacja samego Loki również działa wyłącznie na grupie loki:

ansible-playbook -i inventory/hosts.ini playbooks/loki.yml --check --diff
ansible-playbook -i inventory/hosts.ini playbooks/loki.yml

Po pozytywnej walidacji osobny playbook podłącza metryki Loki do obu Prometheusów i tworzy datasource w Grafanie:

ansible-playbook -i inventory/hosts.ini playbooks/loki_integrate.yml --check --diff
ansible-playbook -i inventory/hosts.ini playbooks/loki_integrate.yml

Walidacja sprawdza readiness, wysyła unikalny wpis testowy przez API Loki i potwierdza jego odczyt:

ansible-playbook -i inventory/hosts.ini playbooks/loki_validate.yml

Status usługi i kontrolowany restart:

ansible-playbook -i inventory/hosts.ini playbooks/loki_service.yml
ansible-playbook -i inventory/hosts.ini playbooks/loki_service.yml \
  -e loki_service_action=restart

Po integracji datasource Loki jest dostępny w Grafana Explore. Prometheus odpytuje endpoint metryk Loki na porcie 3100.

Alloy gateway

Alloy gateway działa jako rootful Podman Quadlet na hostach grupy alloy_gateway. Odczytuje lokalny systemd journal, zachowuje pozycje i eksperymentalny WAL w trwałym katalogu /var/lib/alloy, a następnie wysyła logi do Loki. Port 12345 udostępnia interfejs, health checks i metryki Alloy. Port 12346 udostępnia zgodny z Loki Push API endpoint dla przyszłych agentów klienckich.

Domyślnym obrazem jest docker.io/grafana/alloy:v1.18.0; opcjonalnie może pochodzić ze skonfigurowanego mirrora. Wersję ustawia alloy_gateway_container_version, a użycie tagu latest wymaga jawnego alloy_gateway_container_allow_latest: true.

Kontener działa jako root, ponieważ musi odczytywać hostowy journald. Separacja etykiet SELinux jest wyłączona wyłącznie dla tego kontenera; nie są zmieniane konteksty katalogów /var/log/journal ani /run/log/journal, a SELinux hosta pozostaje w trybie enforcing.

Instalacja ograniczona do grupy alloy_gateway:

ansible-playbook -i inventory/hosts.ini playbooks/alloy_gateway.yml --check --diff
ansible-playbook -i inventory/hosts.ini playbooks/alloy_gateway.yml

Walidacja sprawdza readiness, zdrowie komponentów, endpoint gateway oraz pełną ścieżkę journald → Alloy → WAL → Loki:

ansible-playbook -i inventory/hosts.ini playbooks/alloy_gateway_validate.yml

Po walidacji można podłączyć metryki Alloy do Prometheusa:

ansible-playbook -i inventory/hosts.ini playbooks/alloy_gateway_integrate.yml --check --diff
ansible-playbook -i inventory/hosts.ini playbooks/alloy_gateway_integrate.yml

Status i kontrolowany restart:

ansible-playbook -i inventory/hosts.ini playbooks/alloy_gateway_service.yml
ansible-playbook -i inventory/hosts.ini playbooks/alloy_gateway_service.yml \
  -e alloy_gateway_service_action=restart

W Grafana Explore lokalne logi można wyszukać zapytaniem:

{collector="alloy-gateway"}

Agenty Alloy na hostach monitorujących

Rola alloy instaluje hostowego agenta na węzłach grupy alloy. W przykładowym inventory są to monitoring-01 i monitoring-02. Każdy agent odczytuje lokalny systemd journal, zapisuje pozycje i WAL w trwałym katalogu /var/lib/alloy, a następnie wysyła logi do Alloy Gateway na porcie 12346. Agent nie łączy się bezpośrednio z Loki. Okno odczytu journald wynosi siedem dni.

Metodę instalacji wybiera zmienna alloy_install_method:

  • container — rootful Podman Quadlet korzystający z obrazu grafana/alloy:v1.18.0 z wybranego registry;
  • package — pakiet RPM instalowany przez DNF z aktywnych lub opcjonalnych repozytoriów fallback.

Monitoring nodes używają domyślnie wariantu container. Dla hosta, na którym kontenery są niedostępne, można ustawić w host_vars:

alloy_install_method: package
alloy_package_name: alloy
alloy_package_version: "1.18.0"
alloy_package_repositories:
  - optional_alloy_repository_id

Jeżeli wymagane repozytorium jest już włączone na hoście, alloy_package_repositories może pozostać pustą listą. Po nieudanej próbie z aktywnych repozytoriów każdy identyfikator jest sprawdzany osobno jako enablerepo. Pierwsza udana instalacja kończy pętlę.

Wariant pakietowy używa /etc/alloy/config.alloy, /etc/sysconfig/alloy, natywnej usługi alloy.service i dedykowanego użytkownika alloy. Rola nadaje mu dostęp do grupy systemd-journal, ustawia bezpieczne prawa katalogów i dodaje hardening systemd. Obie metody używają usługi alloy.service, przechowują stan w /var/lib/alloy, udostępniają health checks i metryki na porcie 12345 oraz korzystają z tej samej walidacji end-to-end. SELinux hosta pozostaje w trybie enforcing.

Przed instalacją agentów musi działać Alloy Gateway. Instalacja jest ograniczona do grupy alloy i wykonuje hosty kolejno:

ansible-playbook -i inventory/hosts.ini playbooks/alloy.yml --check --diff
ansible-playbook -i inventory/hosts.ini playbooks/alloy.yml

Walidacja zapisuje unikalny komunikat do journald każdego hosta i sprawdza pełną ścieżkę agent → WAL → Alloy Gateway → Loki:

ansible-playbook -i inventory/hosts.ini playbooks/alloy_validate.yml

Po walidacji można dodać metryki agentów do obu Prometheusów:

ansible-playbook -i inventory/hosts.ini playbooks/alloy_integrate.yml --check --diff
ansible-playbook -i inventory/hosts.ini playbooks/alloy_integrate.yml

Status i kontrolowany restart agentów:

ansible-playbook -i inventory/hosts.ini playbooks/alloy_service.yml
ansible-playbook -i inventory/hosts.ini playbooks/alloy_service.yml \
  -e alloy_service_action=restart

Logi z agentów można wyszukać w Grafana Explore:

{collector="alloy"}

Rola pozostaje niezależna od nazw hostów. W przyszłości hosty klienckie można dodawać do grupy alloy lub do osobnych inventory korzystających z tego samego playbooka.

Node Exporter na hostach Linux

Hosty objęte monitoringiem metryk należą do grupy node_exporter, która jest jednocześnie dzieckiem czytelnej grupy monitoring_linux_metrics. Początkowo obejmuje ona wszystkie trzy serwery platformy. Kolejne hosty klienckie dodaje się do tej samej grupy w lokalnym inventory.

Domyślnie rola instaluje pakiet RPM node-exporter. Najpierw próbuje użyć repozytoriów już włączonych na hoście. Jeżeli pakiet nie jest w nich dostępny, kolejno sprawdza identyfikatory z node_exporter_package_repositories i kończy pętlę po pierwszej udanej instalacji. enablerepo obowiązuje wyłącznie podczas danej transakcji i nie zmienia trwale konfiguracji repozytorium.

Lista może zawierać repozytoria dla różnych wersji RHEL, ponieważ brak danego ID albo brak zgodnego pakietu powoduje przejście do następnego elementu:

node_exporter_package_repositories:
  - UMK_EPEL10_EPEL10
  - UMK_EPEL_9_Everything_x86_64

Błąd jest zgłaszany dopiero wtedy, gdy pakietu nie dostarczyły repozytoria domyślne ani żaden fallback. Na hostach dopuszczających kontenery można ustawić node_exporter_install_method: container; obraz prometheus/node-exporter jest wtedy domyślnie pobierany z publicznego registry dostawcy lub z ustawionego mirrora.

Instalacja agentów nie wykonuje wspólnego bootstrapu i nie instaluje Podmana w wariancie pakietowym. Port 9100/tcp jest udostępniany przez rich rules wyłącznie adresom hostów z grupy prometheus.

Instalacja i walidacja agentów:

ansible-playbook -i inventory/hosts.ini playbooks/node_exporter.yml --check --diff
ansible-playbook -i inventory/hosts.ini playbooks/node_exporter.yml
ansible-playbook -i inventory/hosts.ini playbooks/node_exporter_validate.yml

Po instalacji agentów osobny playbook dodaje wszystkie targety do obu Prometheusów i instaluje dashboardy Node Exportera na węzłach Grafany:

ansible-playbook -i inventory/hosts.ini playbooks/node_exporter_integrate.yml --check --diff
ansible-playbook -i inventory/hosts.ini playbooks/node_exporter_integrate.yml

Stan targetów można sprawdzić zapytaniem PromQL:

up{job="node"}

Provisioning dodaje dwa dashboardy do folderu Observability:

Oba dashboardy mają zmienną Prometheus, która pozwala wybrać Prometheus-01 albo Prometheus-02. Zapytania są dostosowane do joba node generowanego przez ten projekt i nie wymagają dodatkowej etykiety origin_prometheus ani zewnętrznych recording rules.

Kontrolowany status lub restart usług:

ansible-playbook -i inventory/hosts.ini playbooks/node_exporter_service.yml
ansible-playbook -i inventory/hosts.ini playbooks/node_exporter_service.yml \
  -e node_exporter_service_action=restart

Audyt istniejącej instalacji wykonuje playbooks/node_exporter_inspect.yml. Instalację i kontrolowaną migrację uruchamia playbooks/node_exporter_install.yml, a samą konfigurację już zarządzanej usługi — playbooks/node_exporter_configure.yml. Migracja obcej instalacji wymaga jawnej zgody; pojedyncza obsługiwana instalacja źródłowa jest wykrywana automatycznie, bez przepisywania jej danych do inventory. Szczegóły, ograniczenia i przykłady znajdują się w usage.md.

Rsyslog collectors dla urządzeń sieciowych

Collectory rsyslog działają niezależnie na hostach grupy rsyslog_collectors, czyli początkowo na monitoring-01 i monitoring-02. Pakiet RPM odbiera komunikaty urządzeń sieciowych, zapisuje je w katalogach per adres źródłowy pod /var/log/observability/network i używa kolejki dyskowej w /var/lib/rsyslog-observability. Rola nie inicjalizuje opcjonalnego dysku rsyslog; gdy nie jest on zamontowany, kolejka znajduje się na filesystemie systemowym.

Domyślnie aktywny jest 514/tcp. 514/udp i TLS na 6514/tcp są opcjonalne. TLS wymaga wcześniej dostarczonych plików CA, certyfikatu i klucza oraz listy dozwolonych tożsamości certyfikatów. SELinux pozostaje enforcing, a aktywne porty otrzymują typ syslogd_port_t.

Instalacja collectorów celowo nie otwiera portów w firewalld:

ansible-playbook -i inventory/hosts.ini playbooks/rsyslog_collectors.yml --check --diff
ansible-playbook -i inventory/hosts.ini playbooks/rsyslog_collectors.yml

Przypisanie rodzaju monitoringu

Inventory rozdziela grupy komponentowe od czytelnych grup określających rodzaj monitoringu:

  • monitoring_linux_metrics — hosty Linux, z których Alloy zbiera metryki;
  • monitoring_linux_logs — hosty Linux, z których Alloy zbiera logi;
  • monitoring_network_syslog — urządzenia sieciowe uprawnione do wysyłania syslog;
  • rsyslog_collectors — serwery odbierające logi, a nie lista monitorowanych urządzeń.

Dodanie urządzenia sieciowego nie uruchamia na nim Ansible. W lokalnym inventory należy dodać nazwę i stały adres źródłowy:

[monitoring_network_syslog]
switch-core-01 ansible_host=192.0.2.10
firewall-edge-01 rsyslog_source_address=192.0.2.20

Następnie oddzielny playbook uzgadnia rich rules na obu collectorach:

ansible-playbook -i inventory/hosts.ini playbooks/rsyslog_sources.yml --check --diff
ansible-playbook -i inventory/hosts.ini playbooks/rsyslog_sources.yml

Każda reguła dopuszcza wyłącznie adres /32 albo /128 danego urządzenia i tylko aktywne porty rsyslog. Rola zapisuje stan zarządzanych reguł. Usunięcie urządzenia z grupy i ponowne uruchomienie playbooka usuwa jego wcześniejsze rich rules. Pusta grupa zamyka wszystkie porty zarządzane przez tę rolę.

Po instalacji collectorów integracja rozszerza Alloy o odczyt plików i sprawdza pełną ścieżkę rsyslog → plik → Alloy → gateway → Loki:

ansible-playbook -i inventory/hosts.ini playbooks/rsyslog_integrate.yml --check --diff
ansible-playbook -i inventory/hosts.ini playbooks/rsyslog_integrate.yml

Dodatkowa walidacja i kontrolowany restart:

ansible-playbook -i inventory/hosts.ini playbooks/rsyslog_validate.yml
ansible-playbook -i inventory/hosts.ini playbooks/rsyslog_service.yml
ansible-playbook -i inventory/hosts.ini playbooks/rsyslog_service.yml \
  -e rsyslog_collector_service_action=restart

Logi urządzeń są dostępne w Grafana Explore między innymi przez:

{collector="rsyslog"}
{collector="rsyslog", device="192.0.2.10"}

Grafana HA

Grafana działa na obu hostach grupy grafana jako rootful Podman Quadlet i korzysta ze wspólnej bazy PostgreSQL przez lokalny endpoint HAProxy. Domyślnym obrazem jest docker.io/grafana/grafana; opcjonalnie może pochodzić ze skonfigurowanego mirrora. Tag jest ustawiany przez grafana_container_version, a produkcyjny digest przez grafana_container_digest.

Rola wymaga sekretów dostarczonych przez Ansible Vault lub zewnętrzny secrets manager:

grafana_database_password: "..."
grafana_admin_password: "..."
grafana_secret_key: "..."

grafana_secret_key musi mieć co najmniej 32 znaki i być identyczny na obu węzłach. Instalację można wykonać poleceniem:

ansible-playbook -i inventory/hosts.ini playbooks/grafana.yml   --ask-vault-pass   --extra-vars @inventory/group_vars/vault.yml

Sprawdzenie planu zmian:

ansible-playbook -i inventory/hosts.ini playbooks/grafana.yml --check --diff   --ask-vault-pass   --extra-vars @inventory/group_vars/vault.yml

Provisioning Prometheusa w Grafanie

Rola Grafany automatycznie tworzy datasource Prometheus-01 i Prometheus-02. Pierwszy jest domyślny, a dashboard Prometheus Status pozwala przełączać instancję przez zmienną Prometheus.

ansible-playbook -i inventory/hosts.ini playbooks/grafana.yml   --ask-vault-pass   --extra-vars @inventory/group_vars/vault.yml

Provisioning Grafany zarządza centralnymi datasource i dashboardami. Hosty klienckie będą dodawane osobnymi playbookami dla agentów i exporterów. Listy celów Prometheusa będą generowane niezależnie przez file_sd.

Walidacja stanu systemu

Stan stosu bazodanowego należy sprawdzać warstwami: najpierw etcd, następnie Patroni i PostgreSQL, a na końcu endpoint HAProxy używany przez Grafanę.

etcd

Walidację wszystkich członków i endpointów klastra wykonuje playbook:

ansible-playbook -i inventory/hosts.ini playbooks/etcd_validate.yml

Dodatkową diagnostykę można wykonać na dowolnym hoście z grupy etcd:

podman exec etcd /usr/local/bin/etcdctl \
  --endpoints=http://127.0.0.1:2379 endpoint health

podman exec etcd /usr/local/bin/etcdctl \
  --endpoints=http://127.0.0.1:2379 endpoint status --cluster --write-out=table

podman exec etcd /usr/local/bin/etcdctl \
  --endpoints=http://127.0.0.1:2379 member list --write-out=table

Każdy endpoint powinien być zdrowy, a lista członków powinna zawierać trzy uruchomione instancje.

Patroni

Topologię klastra PostgreSQL można wyświetlić na dowolnym monitoring node:

patronictl -c /etc/patroni/patroni.yml list

Lista powinna zawierać jednego lidera i replikę w stanie running. Należy również sprawdzić timeline oraz wartość Lag in MB.

Endpointy REST Patroni pozwalają sprawdzić konkretny węzeł:

curl -i http://<adres-monitoring-node>:8008/liveness
curl -i http://<adres-monitoring-node>:8008/readiness
curl -i http://<adres-monitoring-node>:8008/primary
curl -i http://<adres-monitoring-node>:8008/replica

Endpoint /primary zwraca HTTP 200 wyłącznie na aktualnym liderze, natomiast /replica na działającej replice. Logi Patroni są dostępne przez:

systemctl status patroni --no-pager -l
journalctl -u patroni -n 100 --no-pager

PostgreSQL i replikacja

Rolę lokalnej instancji można sprawdzić jako użytkownik postgres:

sudo -u postgres psql -c "SELECT pg_is_in_recovery();"

Wartość f oznacza lidera, a t replikę. Na liderze stan połączeń replikacyjnych pokazuje:

sudo -u postgres psql -x -c "
SELECT application_name,
       client_addr,
       state,
       sync_state,
       write_lag,
       flush_lag,
       replay_lag
FROM pg_stat_replication;"

Kolumna state powinna mieć wartość streaming. Stan odbioru i odtwarzania WAL na replice można sprawdzić poleceniem:

sudo -u postgres psql -x -c "
SELECT pg_is_in_recovery(),
       pg_last_wal_receive_lsn(),
       pg_last_wal_replay_lsn(),
       pg_last_xact_replay_timestamp();"

HAProxy

Konfigurację i usługę HAProxy można sprawdzić na każdym monitoring node:

haproxy -c -f /etc/haproxy/haproxy.cfg
systemctl status haproxy --no-pager -l
pg_isready -h <adres-monitoring-node> -p 5000

Test połączenia przez endpoint przeznaczony dla Grafany:

psql -h <adres-monitoring-node> -p 5000 \
  -U postgres -d postgres -W \
  -c "SELECT inet_server_addr(), pg_is_in_recovery();"

Połączenie powinno trafić do aktualnego lidera, dlatego pg_is_in_recovery() musi zwrócić f. W przypadku problemów należy sprawdzić logi:

journalctl -u haproxy -n 100 --no-pager

Miejsce na WAL Alloy

Role alloy i alloy_gateway przed instalacją pakietów i zmianą konfiguracji sprawdzają aktualne wolne miejsce na filesystemie katalogu danych (domyślnie /var/lib/alloy). Kontrola działa również z --check; dla nieistniejącego katalogu sprawdza najbliższy istniejący katalog nadrzędny. Docelowe mountpointy należy przygotować przed uruchomieniem roli.

Domyślnie wymagany jest 1 GiB wolnego miejsca. Zapas można zwiększyć:

alloy_storage_min_free_bytes: 1073741824
alloy_gateway_storage_min_free_bytes: 1073741824

Próg powinien pokrywać przewidywany dodatkowy przyrost WAL oraz rezerwę dla pozostałych danych na tym samym filesystemie. Przykładowo przy przyroście WAL 1 GiB/dobę i siedmiu dniach buforowania należy zapewnić około 7 GiB na WAL plus rezerwę. Pomiar przyrostu należy wykonać dla rzeczywistego ruchu; sam czas przechowywania nie wystarcza do wyliczenia pojemności.

alloy_wal_max_segment_age i alloy_gateway_wal_max_segment_age wynoszą domyślnie 168h. To ustawienia wieku segmentów, nie limit rozmiaru w bajtach. Kontrola przed wdrożeniem nie rezerwuje miejsca ani nie chroni przed późniejszym zapełnieniem dysku; potrzebne jest monitorowanie wolnego miejsca podczas pracy.

Na systemie testowym można usunąć zbędny WAL po zatrzymaniu usługi zapisującej katalog danych (alloy.service albo alloy-gateway.service). Usunięcie WAL powoduje utratę niewysłanych wpisów. Należy usuwać wyłącznie zawartość /var/lib/alloy/loki.write.local/wal/, zachowując stany pozostałych komponentów, a następnie uruchomić usługę. Nie należy usuwać plików WAL podczas pracy Alloy.

Minimalny rozmiar urządzeń w preflight

Pole minimum_size_gb we wpisach observability_storage_devices jest opcjonalne; bez niego preflight przyjmuje minimum 1 GB (dziesiętne GB). Jawnie podane progi pozostają obowiązujące. Sprawdzany jest rozmiar urządzenia, nie wolne miejsce w zamontowanym filesystemie.

Przy brakujących polach należy sprawdzić efektywne zmienne hosta, np.:

ansible -i inventories/production/hosts.ini srv-tech-monitoring-02 \
  -m ansible.builtin.debug -a 'var=observability_storage_devices'

Ścieżkę inventory należy dostosować do wdrożenia. Słownik z host_vars może zastąpić cały słownik z group_vars; domyślnie Ansible nie scala ich rekurencyjnie. Przy nadpisywaniu definicji urządzeń należy zachować wymagane progi rozmiaru.

Ochrona Alloy przed ponownym zbieraniem własnych błędów

Agent i gateway odrzucają wpisy journala z jednostek alloy.service, alloy-gateway.service oraz własnej skonfigurowanej jednostki systemd przed przekazaniem ich do WAL. Zapobiega to ponownemu zbieraniu własnych błędów zapisu lub wysyłki. Diagnostyka pozostaje dostępna lokalnie w journald, ale te wpisy nie trafiają do Loki przez źródło journal.

Wyrażenia alloy_journal_excluded_units_regex i alloy_gateway_journal_excluded_units_regex pozwalają rozszerzyć wykluczenia przy niestandardowych nazwach usług. Należy zachować wykluczenie samego collectora. Filtr nie usuwa wpisów już zapisanych w WAL i nie ogranicza rozmiaru WAL.

Uprawnienia mountpointów storage

Rola observability_storage tworzy brakujące katalogi mountpointów jako root:root z trybem 0750. Dla istniejących katalogów zachowuje właściciela, grupę i tryb dostępu. Uprawnienia zamontowanego filesystemu ustalają role komponentów, np. Loki nadaje swoim katalogom danych i WAL właściciela zgodnego z loki_container_uid (domyślnie 10001). Ponowne uruchomienie storage nie powinno odbierać działającej aplikacji dostępu do danych.

Po wdrożeniu poprawki istniejące błędne uprawnienia trzeba naprawić przez ponowne uruchomienie roli komponentu lub zmianę właściciela samego katalogu mountpointu. Rola storage zachowuje aktualne uprawnienia, nie ustala użytkownika aplikacji i nie zmienia rekurencyjnie zawartości filesystemu.

Zbiorcza kontrola stanu

Aby sprawdzić wyłącznie serwery platformy observability:

ANSIBLE_ROLES_PATH=roles ansible-playbook -i inventory/hosts.ini playbooks/status_servers.yml

Ten wariant wybiera tylko grupę observability_servers (w przykładowym inventory: monitoring-01, monitoring-02, logging-01). Sprawdza wszystkie przypisane im komponenty, w tym Node Exportera i Alloy, jeśli te hosty należą do ich grup. Pozostałe hosty z grup node_exporter i alloy nie są objęte kontrolą. Skład serwerów określa inventory, bez wpisywania nazw maszyn w playbooku.

Pełna kontrola, obejmująca również monitorowanych klientów:

ANSIBLE_ROLES_PATH=roles ansible-playbook -i inventory/hosts.ini playbooks/status.yml

Playbook sprawdza komponenty przypisane do hosta przez grupy inventory: Prometheus, Grafana, Alertmanager, Loki, Alloy gateway, Alloy, Node Exporter, etcd, Patroni, PostgreSQL, HAProxy i collectory rsyslog. Nie instaluje pakietów, nie restartuje usług ani nie wysyła testowych logów.

Kontrole obejmują stan usług systemd, endpointy gotowości/zdrowia HTTP, metryki Node Exportera, bazę Grafany, zdrowie klastra etcd i członkostwo oraz lidera Patroni. PostgreSQL jest sprawdzany przez pg_isready (jego procesem zarządza Patroni, więc osobna usługa postgresql.service nie musi działać). HAProxy sprawdza listener PostgreSQL i zdrowie Grafany przez HTTPS; rsyslog — usługę i włączone listenery. Kontrole lokalne wykonują się z hostów docelowych.

Każdy host wypisuje observability_status_results z wynikiem OK lub FAILED dla każdego przypisanego komponentu. Pierwszy błąd danego komponentu kończy jego kontrolę, ale pozostałe komponenty są nadal sprawdzane. Po raporcie playbook zwraca kod błędu, jeżeli którykolwiek komponent nie działa. Host niedostępny przez SSH jest raportowany przez Ansible jako UNREACHABLE; nie ma dla niego raportu komponentów.

Można ograniczyć kontrolę do hosta lub grupy:

ANSIBLE_ROLES_PATH=roles ansible-playbook -i inventory/hosts.ini playbooks/status.yml --limit monitoring-01

observability_status_timeout (domyślnie 10 sekund) ustawia timeout nowych kontroli HTTP, HAProxy TCP i pg_isready. Istniejące kontrole klastrów oraz rsyslog zachowują własne timeouty i ponowienia. Tryb --check również wykonuje kontrole diagnostyczne. W razie potrzeby dodaj standardowe opcje dostępu SSH, --ask-become-pass lub opcje Vault wymagane przez inventory.

Wynik OK dotyczy powyższych kontroli, nie potwierdza pełnego przepływu danych, wszystkich celów Prometheusa, backupów ani stanu dysków. Do testów przepływu logów służą istniejące playbooki *_validate.yml.

Dostępność Node Exportera z węzłów monitoringu

Po kontrolach lokalnych oba playbooki wykonują żądania HTTP z każdego hosta w grupie prometheus (w przykładowym inventory: monitoring-01 i monitoring-02). status.yml sprawdza wszystkie cele z prometheus_node_exporter_group (domyślnie node_exporter), a status_servers.yml tylko cele należące także do observability_servers.

Kontrola używa ansible_host celu (lub nazwy inventory), portu prometheus_node_exporter_port i ścieżki /metrics, zgodnie z szablonem konfiguracji Prometheusa. Wymaga HTTP 200 i metryk node_exporter_build_info oraz node_uname_info. Nie używa proxy HTTP. Timeout pojedynczego żądania ustawia observability_status_timeout (domyślnie 10 sekund).

Raport observability_node_exporter_connectivity_results na każdym węźle zawiera źródło, cel, URL i wynik OK/FAILED. Awaria jednego celu nie przerywa sprawdzania kolejnych; po raporcie zwracany jest kod błędu. Test potwierdza dostępność endpointu z hosta Prometheusa, ale nie stan jego rzeczywistego scrape.

Sam test sieciowy, bez SSH do klientów:

ANSIBLE_ROLES_PATH=roles ansible-playbook -i inventory/hosts.ini playbooks/node_exporter_connectivity.yml

Opcjonalnie dodaj -e observability_status_target_group=observability_servers, aby testować tylko exportery serwerów platformy. --limit ogranicza także węzły wykonujące test: --limit monitoring-01 uruchomi go tylko z tego węzła, a ograniczenie do samego klienta pominie test sieciowy. Lista celów pochodzi z inventory i nie jest zawężana przez --limit. Kontrole wykonują się również w trybie --check. Brak hostów w grupie prometheus oznacza pominięcie tego etapu.