Migrálás Nagios-ról Icinga2-re Ausztráliában

Helló mindenkinek.

Linux rendszergazda vagyok, 2015-ben független szakmai vízummal költöztem Oroszországból Ausztráliába, de a cikk nem arról fog szólni, hogyan indítson traktort egy disznó. Ilyen témájú cikkekből már bőven van, így arra szeretnék fókuszálni, hogyan voltam az iniciátora annak a migrációnak, hogy egy monitorozó rendszerről egy másikra térjünk át az ausztrál munkahelyemen linux-ops mérnökként. Konkrétan: Nagios => Icinga2.

A cikk részben technikai, részben pedig az emberekkel való kommunikációról és a kultúrák közötti eltérésekhez kapcsolódó problémákról szól.

Sajnos a „code” címke nem világítja meg a Puppet és yaml kódot, ezért kénytelen voltam a „plaintext”-t használni.

Nem történt semmi rendkívüli 2016. december 21-én reggel. Mint mindig, anonimként olvastam a Habr-t a munkaidő első fél órájában, kávét kortyolgatva, és rábukkantam erre a cikkre.

Mivel a cégemnél éppen Nagios-t használtunk, gondolkodás nélkül létrehoztam egy jegyet a Redmine-ban, és megosztottam a linket a közös cseten, mivel fontosnak tartottam. Az iniciatíva akár Ausztráliában is büntethető, így a vezető mérnök rám bízta ezt a problémát, mivel én fedeztem fel.

Kép a Redmine-bólMigrálás Nagios-ról Icinga2-re Ausztráliában

A részlegünkben, mielőtt kifejtenénk a véleményünket, szokás legalább egy alternatívát javasolni, még ha a választás nyilvánvaló is, így elkezdtem guglizni, hogy milyen monitorozó rendszerek relevánsak jelenleg, mivel Oroszországban az utolsó munkahelyemen volt egy saját írású, nagyon primitív rendszerem, de mégis teljesen működőképes, és ellátta az összes elvárt feladatot. A Python, a Pétervári Politechnikum és a metró a menők. Nem, a metró az pocsék. Ez személyes (11 év munka), és megérne egy külön cikket, de nem most.

Egy kicsit a változtatások szabályairól az infrastruktúra konfigurációjában a jelenlegi munkahelyemen. Puppet, Gitlab és Infrastructure as Code elvét használjuk, így:

  • Nincs manuális módosítás SSH-n keresztül a virtuális gépeken lévő fájlok kézi megváltoztatásával. Három év alatt sokszor megkaptam érte a magamét, legutóbb egy hete, és nem hiszem, hogy ez volt az utolsó alkalom. Valóban — módosítani egy sort a konfigurációban, újraindítani a szolgáltatást, és megnézni, hogy megoldódott-e a probléma — 10 másodperc. Új ágat létrehozni a Gitlabon, feltölteni a módosításokat, megvárni, amíg az r10k lefut a Puppetmasteren, elindítani a Puppet —environment=mybranch-t, és még pár percig várni, amíg ez mind végbemegy — minimum 5 perc.
  • Bármilyen módosítást Merge Request létrehozásával végzünk a Gitlabon, és legalább egy csapattag jóváhagyása szükséges. A komolyabb módosításokhoz, amelyeket a csapatvezető határoz meg, két vagy három jóváhagyás szükséges.
  • Minden módosítás valamilyen formában szöveges (mivel a Puppet manifesztációk, szkriptek és Hiera adatok szöveg), a bináris fájlok használatát pedig erősen nem ajánlják, és ilyen fájlok jóváhagyásához súlyos okok szükségesek.

Tehát az opciók, amelyeket megfontoltam:

  • Munin — ha az infrastruktúrában több mint 10 szerver van, az adminisztráció pokollá válik (a ezen cikket. Nem volt különösebb kedvem ellenőrizni ezt, ezért elhittem a szóbeszédet).
  • Zabbix — már régóta nézegettem, még Oroszországban, de akkoriban túlzás volt a feladataimhoz. Itt — el kellett vetnem a Puppet konfigurációs menedzserként és a Gitlab verziókezelő rendszerként való használata miatt. Abban az időben, amennyire értettem — a Zabbix az összes konfigurációt adatbázisban tárolja, ami miatt nem volt világos, hogyan lehet kezelni a konfigurációt a jelenlegi körülmények között és hogyan lehet nyomon követni a módosításokat.
  • Prometheus — az, amire végül eljutunk, a részleg hangulata alapján, de abban az időben nem tudtam megugrani, és nem tudtam bemutatni egy valós működő példányt (Proof of Concept), így le kellett mondanom róla.
  • Még néhány más opciót is figyelembe vettem, amelyek vagy teljességgel újra kellett volna dolgoznunk a rendszert, vagy kezdeti állapotban voltak / elhanyagolták őket, és ezért elutasításra kerültek.

Végül az Icinga2 mellett döntöttem három okból:

1 — A Nrpe-vel (a Nagios által parancsok alapján végrehajtott ellenőrzéseket végző kliensszolgáltatás) való kompatibilitás. Ez nagyon fontos volt, mert akkor 135 (2019-re 165-re nőtt) virtuális gépünk volt, amelyek teli voltak saját fejlesztésű szolgáltatásokkal/ellenőrzésekkel, és mindezt átírni hatalmas kínszenvedés lett volna.
2 — Minden konfigurációs fájl szöveges, ami megkönnyíti a módosítást, lehetővé téve a merge kérések létrehozását, ahol látható, mi lett hozzáadva vagy eltávolítva.
3 — Ez egy élő és fejlődő OpenSource projekt. Nagyon szeretjük az OpenSource-t, és aktívan hozzájárulunk a problémák megoldásához Pull Requestek és Issues létrehozásával.

Tehát, kezdjük el az Icinga2-t.

Az első dolog, amivel szembesültem — a kollégák passzivitása. Mindenki hozzászokott a Nagioshoz/Nagioshoz (még itt sem tudtunk kompromisszumra jutni a kiejtésével) és a CheckMK felületéhez. Az Icinga interfésze azonban teljesen másképp néz ki (ez hátrány volt), de van lehetőség rugalmasan beállítani, hogy mit szeretnénk látni szűrők segítségével gyakorlatilag bármilyen paraméter szerint (ez előny volt, de nagy harcot vívtam érte).

SzűrőkMigrálás Nagios-ról Icinga2-re Ausztráliában

Értékelje a görgetősáv mérete és a görgetési terület mérete közötti arányt.

Másodszor — mindenki hozzászokott, hogy az egész infrastruktúrát egy monitoron látja, mert a CheckMk lehetővé teszi, hogy több Nagios hoszttal dolgozzon, de az Icinga interfésze nem volt képes erre (valójában volt, de erről később). Az alternatíva egy Thruk nevű dolog volt, de ennek a dizájnja hányingert okozott a csapat minden tagjának, kivéve egyet — aki ezt javasolta (nem én).

A Thruk a kukába — a csapat egyhangú döntése.Migrálás Nagios-ról Icinga2-re Ausztráliában

Pár nap brainstorming után javasoltam a klaszter-monitoring ötletét, ahol van egy fő hoszt a production zónában és két alárendelt — egy a dev/test, és egy külső hoszt, amely egy másik szolgáltatónál található, célja, hogy figyelemmel kísérje szolgáltatásainkat a felhasználók vagy külső megfigyelők szempontjából. Ez a konfiguráció lehetővé tette az összes probléma egy webes felületen való megtekintését és teljesen működött, de a Puppet… A Puppet problémája az volt, hogy a fő hosztnak most tudnia kellett minden hoszt és szolgáltatás/ellenőrzés adatait a rendszerben, és ezeket zónák között (dev-test, staging-prod, ext) kellett megosztania, de a változások elküldése az Icinga API-n keresztül pár másodpercet vesz igénybe, míg a Puppet összes szolgáltatásának a hosztokhoz való összeállítása pár percet. Ezt még mindig a szememre hányják, bár már többször elmagyaráztam, hogyan működik minden és miért tart ilyen sokáig.

Harmadik — sok SnowFlakes (hópehely) — olyan dolgok, amelyek kilógnak az összes többi közül, mert van bennük valami különleges, így a közös szabályok nem vonatkoznak rájuk. Ezt egy közvetlen támadással oldottam meg — ha van riasztás, de a valóságban minden rendben van, akkor ott mélyebben kell ásni, hogy kiderüljön, miért ad ki figyelmeztetést, amikor nem kéne. Vagy éppen ellenkezőleg — miért pánikol a Nagios, amikor az Icinga nem.

Negyedik — a Nagios itt előttem három éve működött, és vele kezdetben nagyobb bizalom övezett, mint az én új divatos hipster rendszerem iránt, így amikor az Icinga pánikot keltett — senki sem cselekedett, amíg a Nagios nem váltott hasonló ügyben. De nagyon ritkán az Icinga valós riasztásokat adott ki, mielőtt a Nagios, és ezt komoly hibának tartom, amelyről a „Következtetések” részben fogok beszélni.

Ennek eredményeként a bevezetés több mint 5 hónapig elhúzódott (eredetileg 2018. június 28-án terveztük, ténylegesen pedig 2018. december 3-án valósult meg), főként a „parity check” miatt — arról a fránya dologról, amikor a Nagiosban több olyan szolgáltatás van, amelyről senki sem tudott az utolsó pár évben, de ÉPP MOST kiadták a kritikus riasztást bármi ok nélkül, és magyarázkodnom kellett, hogy miért nincsenek ott a panelemen, és hogy hozzá kellett adnom őket az Icingához, hogy „a parity check teljes” legyen (minden szolgáltatás/ellenőrzés a Nagiosban megfelel a szolgáltatások/ellenőrzéseknek az Icingában)

Bevezetés:
Első — a Code vs Data háború, Puppet Style. Minden adat, tényleg minden, a Hiera-ban kell, hogy legyen, és másként nem. Az összes kód a .pp fájlokban van. A változók, absztrakciók, funkciók — mind a pp-ben találhatók.
Ennek eredményeként — van egy csomó virtuális gépünk (165 a cikk írásakor) és 68 webalkalmazásunk, amelyeket figyelemmel kell kísérni a működés szempontjából és az SSL-tanúsítványok érvényessége szempontjából. De a történelmi nehézségek miatt az alkalmazások monitorozásához szükséges információ egy külön gitlab-tárhelyről származik, és az adatformátum a Puppet 3 óta nem változott, ami további nehézségeket okoz a konfigurációban.

A Puppet-kód az alkalmazások számára, vigyázzon a szemeire

definiáld a profilokat::szolgáltatások::monitoring::docker_apps(
  Hash $app_list,
  Hash $apps_accessible_from,
  Hash $apps_access_list,
  Hash $webhost_defaults,
  Hash $webcheck_defaults,
  Hash $service_overrides,
  Hash $targets,
  Hash $app_checks,
  )
{
#### APPS ####
  $zone = $name
  $app_list.each | String $app_name, Hash $app_data |
  {

    $notify_group = { 'notify_group' => ($webcheck_defaults[$zone]['notify_group'] + pick($app_data['notify_group'], {} )) } # értesítések hozzáadása az alapértelmezett csoporthoz (rendszerek) + bármely csoport, amely az int/pm_docker_apps.eyaml fájlban van definiálva

    $data = merge($webhost_defaults, $apps_accessible_from, $app_data)

    $site_domain = $app_data['site_domain']

    $regexp = pick($app_data['check_regex'], 'html')        # Válassza ki a regexet az ellenőrzéshez

    $check_url = $app_data['check_url'] ? {
      undef   => { 'http_uri' => '\/'' },
      default => { 'http_uri' => $app_data['check_url'] }
    }

    $check_regex = $regexp ?{
      'absent' => {},
      default  => {'http_expect_body_regex' => $regexp}
    }

    $site_domain.each | String $vhost, Hash $vdata | {        # Osztja meg az alkalmazást domain-ek szerint, ha két vagy több van
      $vhost_name = {'http_vhost' => $vhost}

      $vars = $data['vars'] + $vhost_name + $check_regex + $check_url

      $web_ipaddress = is_array($vdata['web_ipaddress']) ? {  # IP-cím átalakítása tömbbé, ha nem az, mert az askizzy-nek 2 ips-e van és ez egy tömb
        true  => $vdata['web_ipaddress'],
        false => [$vdata['web_ipaddress']],
      }

      $access_from_zones = [$zone] + $apps_access_list[$data['accessible_from']] # Alapértelmezett zóna (ahol az alkalmazást definiálták) és extra zónák egyesítése, ha léteznek
      $web_ipaddress.each | String $ip_address | {            # Minden IP-címhez (ha több van)
        $suffix = length($web_ipaddress) ? {                  # Ha több mint egy van - add hozzá az IP-t, mint utótag ehhez a gazdagéphez, hogy elkerüljük az erőforrások duplikálását
          1       => '',
          default => "_${ip_address}"
        }
        $octets = split($ip_address, '.')
        $ip_tag = "${octets[2]}.${octets[3]}" # Csak az utolsó oktét használata ütközéseket okoz a nginx-vip 203.15.70.94 és az ext. ip 49.255.194.94 között

        $access_from_zones.each | $zone_prefix |{
          $zone_target = $targets[$zone_prefix]

          $nginx_vip_name = "${zone_prefix}_nginx-vip-${ip_tag}" # Ha ez egy host az ext - a prefix 'ext_' lesz (ext_nginx-vip...)
          $nginx_host_vip = {
            $nginx_vip_name => {
              ensure        => present,
              target        => $zone_target,
              address       => $ip_address,
              check_command => 'hostalive',
              groups        => ['nginx_vip',],
            }
          }

          $ssl_vars = $app_checks['ssl']
          $regex_vars = $app_checks['http'] + $vars + $webcheck_defaults[$zone] + $notify_group

          if !defined( Profiles::Services::Monitoring::Host[$nginx_vip_name] ) {
          ensure_resources('profiles::services::monitoring::host', $nginx_host_vip)
          }

          if !defined( Icinga2::Object::Service["${nginx_vip_name}_ssl"] ) {
            icinga2::object::service {"${nginx_vip_name}_ssl":
              ensure         => $data['ensure'],
              assign         => ["host.name == $nginx_vip_name",],
              groups         => ['webchecks',],
              check_command  => 'ssl',
              check_interval => $service_overrides['ssl']['check_interval'],
              target         => $targets['services'],
              apply          => true,
              vars           => $ssl_vars
            }
          }
          if $regexp != 'absent'{
            if !defined(Icinga2::Object::Service["${vhost}${$suffix} regex"]){
              icinga2::object::service {"${vhost}${$suffix} regex":
                ensure          => $data['ensure'],
                assign          => ["match(*_nginx-vip-${ip_tag}, host.name)",],
                groups          => ['webchecks',],
                check_command   => 'http',
                check_interval  => $service_overrides['regex']['check_interval'],
                target          => $targets['services'],
                enable_flapping => true,
                apply           => true,
                vars            => $regex_vars
              }
            }
          }
        }
      }
    }
  }
}

A hosztok és szolgáltatások konfigurációs kódja is borzalmasan néz ki:

monitoring/config.pp


class profiles::services::monitoring::config(
  Array $default_config,
  Array $hostgroups,
  Hash $hosts = {},
  Hash $host_defaults,
  Hash $services,
  Hash $service_defaults,
  Hash $service_overrides,
  Hash $webcheck_defaults,
  Hash $servicegroups,
  String $servicegroup_target,
  Hash $user_defaults,
  Hash $users,
  Hash $oncall,
  Hash $usergroup_defaults,
  Hash $usergroups,
  Hash $notifications,
  Hash $notification_defaults,
  Hash $notification_commands,
  Hash $timeperiods,
  Hash $webhost_defaults,
  Hash $apps_access_list,
  Hash $check_commands,
  Hash $hosts_api = {},
  Hash $targets = {},
  Hash $host_api_defaults = {},
)
{

  # Profiles::Services::Monitoring::Hostgroup <<| |>> # akkor lesz engedélyezve, amikor teljesen áttérünk az icingá-ra
#### APPS ####
  case $location {
    'int', 'ext': {
      $apps_by_zone = {}
    }
    'pm': {
      $int_apps         = hiera('int_docker_apps')
      $int_app_defaults = hiera('int_docker_app_common')

      $st_apps          = hiera('staging_docker_apps')
      $srs_apps         = hiera('pm_docker_apps_srs')
      $pm_apps          = hiera('pm_docker_apps') + $st_apps + $srs_apps
      $pm_app_defaults  = hiera('pm_docker_app_common')

      $apps_by_zone = {
        'int' => $int_apps,
        'pm'  => $pm_apps,
      }

      $app_access_by_zone = {
        'int' => {'accessible_from' => $int_app_defaults['accessible_from']},
        'pm'  => {'accessible_from' => $pm_app_defaults['accessible_from']},
      }
    }

    default: {
      fail('Kérjük, győződjön meg róla, hogy a noden rendelkezik $location ténnyel (int, pm, ext)')
    }
  }

  file { '\/etc\/icinga2\/conf.d\/':
    ensure  => directory,
    recurse => true,
    purge   => true,
    owner   => 'icinga',
    group   => 'icinga',
    mode    => '0750',
    notify  => Service['icinga2'],
  }

  $default_config.each | String $file_name |{
    file {"\/etc\/icinga2\/conf.d\/${file_name}":
      ensure => present,
      source => "puppet:\/\/modules\/profiles\/services\/monitoring\/default_config\/${file_name}",
      owner  => 'icinga',
      group  => 'icinga',
      mode    => '0640',
    }
  }

  $app_checks = {
    'ssl' => $services['webchecks']['checks']['ssl']['vars'],
    'http' => $services['webchecks']['checks']['http_regexp']['vars']
  }

  $apps_by_zone.each | String $zone, Hash $app_list | {
    profiles::services::monitoring::docker_apps{$zone:
      app_list             => $app_list,
      apps_accessible_from => $app_access_by_zone[$zone],
      apps_access_list     => $apps_access_list,
      webhost_defaults     => $webhost_defaults,
      webcheck_defaults    => $webcheck_defaults,
      service_overrides    => $service_overrides,
      targets              => $targets,
      app_checks           => $app_checks,
    }
  }

####    HOSTS    ####

  # Profiles::Services::Monitoring::Host <<| |>> # Ez az űrhajó inváziójára készült, amikor az készen áll.
  $hosts_has_large_disks = query_nodes('mountpoints.*.size_bytes >= 1099511627776')

  $hosts.each | String $hostgroup, Hash $list_of_hosts_with_settings | {           # A site listák elválasztása hostgroupokra - docker_host\/gluster_host\/stb
    $list_of_hosts_in_group = $list_of_hosts_with_settings['hosts']
    $hostgroup_settings     = $list_of_hosts_with_settings['settings']
    $merged_hostgroup_settings = deep_merge($host_defaults, $list_of_hosts_with_settings['settings'])
    $list_of_hosts_in_group.each | String $host_name, Hash $host_settings |{  # A grouplistok elválasztása hosztokra
      # Van-e ez a host a $hosts_has_large_disks tömbben? Ha igen, állítson be host.vars.has_large_disks
      if ( $hosts_has_large_disks.reduce(false) | $found, $value| { ( $value =~ "^${host_name}" ) or $found } ) {
        $vars_has_large_disks = { 'has_large_disks' => true }
      } else {
        $vars_has_large_disks = {}
      }
      $host_data = deep_merge($merged_hostgroup_settings, $host_settings)
      $hostgroup_settings_vars = pick($hostgroup_settings['vars'], {})
      $host_settings_vars = pick($host_settings['vars'], {})
      $host_notify_group = delete_undef_values($host_defaults['vars']['notify_group'] + $hostgroup_settings_vars['notify_group'] + $host_settings_vars['notify_group'])
      $host_data_vars = delete_undef_values(deep_merge($host_data['vars'] , {'notify_group' => $host_notify_group}, $vars_has_large_disks)) # Vars elkülönítése

      $hostgroups = delete_undef_values([$hostgroup] + $host_data['groups'])

      profiles::services::monitoring::host{$host_name:
        ensure             => $host_data['ensure'],
        display_name       => $host_data['display_name'],
        address            => $host_data['address'],
        groups             => $hostgroups,
        target             => $host_data['target'],
        check_command      => $host_data['check_command'],
        check_interval     => $host_data['check_interval'],
        max_check_attempts => $host_data['max_check_attempts'],
        vars               => $host_data_vars,
        template           => $host_data['template'],
      }
    }
  }
  if !empty($hosts_api){                                                                # Minden host, amit az API kezel
    $hosts_api.each | String $zone, Hash $hosts_api_zone | {                            # API hostok elválasztása zónák szerint
      $hosts_api_zone.each | String $hostgroup, Hash $list_of_hosts_with_settings | {   # A site listák elválasztása hostgroupokra - docker_host\/gluster_host\/stb
        $list_of_hosts_in_group = $list_of_hosts_with_settings['hosts']
        $hostgroup_settings     = $list_of_hosts_with_settings['settings']
        $merged_hostgroup_settings = deep_merge($host_api_defaults, $list_of_hosts_with_settings['settings'])
        $list_of_hosts_in_group.each | String $host_name, Hash $host_settings |{        # A grouplistok elválasztása hosztokra
          # Van-e ez a host a $hosts_has_large_disks tömbben? Ha igen, állítson be host.vars.has_large_disks
          if ( $hosts_has_large_disks.reduce(false) | $found, $value| { ( $value =~ "^${host_name}" ) or $found } ) {
            $vars_has_large_disks = { 'has_large_disks' => true }
          } else {
            $vars_has_large_disks = {}
          }
          $host_data = deep_merge($merged_hostgroup_settings, $host_settings)
          $hostgroup_settings_vars = pick($hostgroup_settings['vars'], {})

          $host_settings_vars = pick($host_settings['vars'], {})
          $host_api_notify_group = delete_undef_values($host_defaults['vars']['notify_group'] + $hostgroup_settings_vars['notify_group'] + $host_settings_vars['notify_group'])
          $host_data_vars = delete_undef_values(deep_merge($host_data['vars'] , {'notify_group' => $host_api_notify_group}, $vars_has_large_disks))
          $hostgroups = delete_undef_values([$hostgroup] + $host_data['groups'])

          if defined(Profiles::Services::Monitoring::Host[$host_name]){
            $hostname = "${host_name}_from_${zone}"
          }
          else
          {
            $hostname = $host_name
          }
          profiles::services::monitoring::host{$hostname:
            ensure             => $host_data['ensure'],
            display_name       => $host_data['display_name'],
            address            => $host_data['address'],
            groups             => $hostgroups,
            target             => "${host_data['target_base']}\/${zone}\/hosts.conf",
            check_command      => $host_data['check_command'],
            check_interval     => $host_data['check_interval'],
            max_check_attempts => $host_data['max_check_attempts'],
            vars               => $host_data_vars,
            template           => $host_data['template'],
          }
        }
      }
    }
  }

#### A HOSTOK VÉGE ####

####   SZOLGÁLTATÁSOK   ####

  $services.each | String $service_group, Hash $s_list |{             # Szolgáltatás-csoport és a csoportban lévő szolgáltatások listája
    $service_list = $s_list['checks']                                 # A tényleges ellenőrzések listája, amely elkülönítve van a SG beállításaitól
    $service_list.each | String $service_name, Hash $data |{

      $merged_defaults = merge($service_defaults, $s_list['settings']) # globális szolgáltatás alapbeállítások + szolgáltatás-csoport alapbeállításai
      $merged_data = merge($merged_defaults, $data)

      $settings_vars = pick($s_list['settings']['vars'], {})
      $this_service_vars = pick($data['vars'], {})
      $all_service_vars = delete_undef_values($service_defaults['vars'] + $settings_vars + $this_service_vars)

      # Ha felülírjuk az alapértelmezett check_timeout-ot, de nem a nrpe_timeout-ot, akkor állítsuk a nrpe_timeout-ot azonosra, mint a check_timeout
      if ( $merged_data['check_timeout'] and ! $this_service_vars['nrpe_timeout'] ) {
        # NB: Az Icinga automatikusan 1m-t 60-ra konvertál!
        $nrpe = { 'nrpe_timeout' => $merged_data['check_timeout'] }
      } else {
        $nrpe = {}
      }

      # Alapértelmezetten nrpe-t használunk, és az összes parancs nrpe-n keresztül fut. Tehát vars.nrpe_command = $service_name az alapértelmezett érték
      # Ha ez a szerveroldali Icinga parancs - nem kell 'nrpe_command'
      # De nem árt, ha van ez a var, és a kód is rövidebb

      if $merged_data['check_command'] == 'nrpe'{
        $check_command = $merged_data['vars']['nrpe_command'] ? {
          undef   => { 'nrpe_command' => $service_name },
          default => { 'nrpe_command' => $merged_data['vars']['nrpe_command'] }
        }
      }else{
        $check_command = {}
      }

      # Az $vars összeállítása a Globális Alapértelmezett szolgáltatásbeállítások, a szolgáltatáscsoport beállításai, ennek a konkrét ellenőrzés beállításai, és ne feledjük a nrpe beállításokat.
      if $all_service_vars['graphite_template'] {
        $graphite_template = {'check_command' => $all_service_vars['graphite_template']}
      }else{
        $graphite_template = {'check_command' => $service_name}
      }
      $service_notify = [] + pick($settings_vars['notify_group'], []) + pick($this_service_vars['notify_group'], []) # a pick mindenhol szükséges, különben "The value '' cannot be converted to Numeric"

      $service_notify_group = $service_notify ? {
        []      => $service_defaults['vars']['notify_group'],
        default => $service_notify
      } # Alapértelmezett csoport (rendszerek) megadása, ha nincs más csoport megadva

      $vars = $all_service_vars + $nrpe + $check_command + $graphite_template + {'notify_group' => $service_notify_group}

      # Ez külön össze kell vonni, mivel ha a MERGED_DATA részeként vonjuk össze, az felülírja a tömböket, így elveszítjük a "assign" és "ignore" értékeket

      $assign = delete_undef_values($service_defaults['assign'] + $s_list['settings']['assign'] + $data['assign'])
      $ignore = delete_undef_values($service_defaults['ignore'] + $s_list['settings']['ignore'] + $data['ignore'])

      icinga2::object::service {$service_name:
        ensure             => $merged_data['ensure'],
        apply              => $merged_data['apply'],
        enable_flapping    => $merged_data['enable_flapping'],
        assign             => $assign,
        ignore             => $ignore,
        groups             => [$service_group],
        check_command      => $merged_data['check_command'],
        check_interval     => $merged_data['check_interval'],
        check_timeout      => $merged_data['check_timeout'],
        check_period       => $merged_data['check_period'],
        display_name       => $merged_data['display_name'],
        event_command      => $merged_data['event_command'],
        retry_interval     => $merged_data['retry_interval'],
        max_check_attempts => $merged_data['max_check_attempts'],
        target             => $merged_data['target'],
        vars               => $vars,
        template           => $merged_data['template'],
      }
    }
  }
#### A SZOLGÁLTATÁSOK VÉGE ####

#### EGYÉB UNALMAS DOLGOK ####

  $servicegroups.each | $servicegroup, $description |{
    icinga2::object::servicegroup{ $servicegroup:
      target       => $servicegroup_target,
      display_name => $description
    }
  }

  $hostgroups.each| String $hostgroup |{
    profiles::services::monitoring::hostgroup { $hostgroup:}
  }

  $notifications.each | String $name, Hash $settings |{

    $assign = pick($notification_defaults['assign'], []) + $settings['assign']
    $ignore = pick($notification_defaults['ignore'], []) + $settings['ignore']

    $merged_settings = $settings + $notification_defaults

    icinga2::object::notification{$name:
      target       => $merged_settings['target'],
      apply        => $merged_settings['apply'],
      apply_target => $merged_settings['apply_target'],
      command      => $merged_settings['command'],
      interval     => $merged_settings['interval'],
      states       => $merged_settings['states'],
      types        => $merged_settings['types'],
      assign       => delete_undef_values($assign),
      ignore       => delete_undef_values($ignore),
      user_groups  => $merged_settings['user_groups'],
      period       => $merged_settings['period'],
      vars         => $merged_settings['vars'],
    }
  }

  # Értesítési beállítások egyes felhasználókkal való összevonása más beállításokkal
  $users_oncall = deep_merge($users, $oncall)
  # Varázslat. Ne nyúlj hozzá.
  create_resources('icinga2::object::user', $users_oncall, $user_defaults)
  create_resources('icinga2::object::usergroup', $usergroups, $usergroup_defaults)
  create_resources('icinga2::object::timeperiod',$timeperiods)
  create_resources('icinga2::object::checkcommand', $check_commands)
  create_resources('icinga2::object::notificationcommand', $notification_commands)

  profiles::services::sudoers { 'icinga_runs_ping_l2':
    ensure            => present,
    sudoersd_template => 'profiles\/os\/redhat\/centos7\/sudoers\/icinga.erb',
  }

}

Még mindig dolgozom ezen a kódon, és igyekszem folyamatosan javítani. De éppen ez a kód tette lehetővé, hogy egyszerű és érthető szintaxist használjunk a Hierában:

Adatok

profiles::services::monitoring::config::services:
  perf_checks:
    settings:
      check_interval: '2m'
      assign:
        - 'host.vars.type == linux'
    checks:
      procs: {}
      load: {}
      memory: {}
      disk:
        check_interval: '5m'
        vars:
          notification_period: '24x7'
      disk_iops:
        vars:
          notifications:
            - 'silent'
      cpu:
        vars:
          notifications:
            - 'silent'
      dns_fqdn:
        check_interval: '15m'
        ignore:
          - 'xenserver in host.groups'
        vars:
          notifications:
            - 'silent'
      iftraffic_nrpe:
        vars:
          notifications:
            - 'silent'
  logging:
    settings:
      assign:
        - 'logserver in host.groups'
    checks:
       rsyslog: {}
      nginx_limit_req_other: {}
      nginx_limit_req_s2s: {}
      nginx_limit_req_s2x: {}
      nginx_limit_req_srs: {}
     logstash: {}
      logstash_api:
        vars:
          notifications:
            - 'silent'

Minden ellenőrzés csoportokra van bontva, és minden csoportnak vannak alapértelmezett beállításai azzal kapcsolatban, hogy hol és milyen gyakran futtassák ezeket az ellenőrzéseket, milyen értesítéseket küldjenek és kinek.

Minden egyes ellenőrzésnél felülírható bármelyik opció, és mindez végül még összeadódik az összes ellenőrzés alapértelmezett beállításaival. Ezért van ez a kód a config.pp-ben — itt történik az összes alapértelmezett beállítás csoportbeállításokkal és egyéni ellenőrzésekkel való összevonása.

Egy nagyon fontos változás volt, hogy lehetővé vált funkciók használata a beállításokban, például a port, cím és URL cserélésére a http_regex ellenőrzéshez.

http_regexp:
  assign:
    - 'host.vars.http_regex'
    - 'static_sites in host.groups'
  check_command: 'http'
  check_interval: '1m'
  retry_interval: '20s'
  max_check_attempts: 6
  http_port: '{{ if(host.vars.http_port) { return host.vars.http_port } else { return 443 } }}'
  vars:
    notification_period: 'host.vars.notification_period'
    http_vhost: '{{ if(host.vars.http_vhost) { return host.vars.http_vhost } else { return host.name } }}'
    http_ssl: '{{ if(host.vars.http_ssl) { return false } else { return true } }}'
    http_expect_body_regex: 'host.vars.http_regex'
    http_uri: '{{ if(host.vars.http_uri) { return host.vars.http_uri } else { return "\/" } }}'
    http_onredirect: 'follow'
    http_warn_time: 8
    http_critical_time: 15
    http_timeout: 30
    http_sni: true

Ez azt jelenti, hogy ha a gazda definíciójában van egy változó http_port — használja azt, különben 443-at. Például, a jabber webes felülete 9090-en fut, míg a Unifi 7443-on.
http_vhost azt jelenti, hogy figyelmen kívül hagyjuk a DNS-t és ezt az címet használjuk.
Ha a gazdában meg van határozva uri — akkor ott kell haladni, különben a "\/"-ot vesszük.

A http_ssl-leal kapcsolatban vicces történet történt — ez a dög nem akarta kikapcsolni a követelésnek megfelelően. Sokáig néztem ezt a sort, míg rá nem jöttem, hogy a változó a gazda definíciójában:

http_ssl: false

Beillesztés a kifejezésbe

if(host.vars.http_ssl) { return false } else { return true }

hogyan hamis és végül ez jön ki

if(false) { return false } else { return true }

tehát SSL ellenőrzés mindig aktív marad. A szintaxis cseréjével megoldva:

http_ssl: no

Következtetések:

Előnyök:

  • Most már csak egy megfigyelő rendszerünk van, nem kettő, mint az elmúlt 7-8 hónapban, vagy egy elavult és sebezhető.
  • A hosztok/adatok struktúrája most (véleményem szerint) sokkal olvashatóbb és érthetőbb. Másoknak ez nem volt olyan nyilvánvaló, ezért pár oldalt kellett írnom a helyi wikin, hogy tisztázzam, hogyan működik az egész és mit hol kell módosítani.
  • Rugalmas ellenőrzési beállítások érhetők el változók és funkciók segítségével, például http_regexp esetén a keresett mintát, visszatérési kódot, URL-t és portot a hoszt beállításaiban meg lehet adni.
  • Több panel (dashboard) is elérhető, amelyekhez saját riasztási listát lehet meghatározni, és az egészet Puppet-en és merge requesteken keresztül lehet kezelni.

Hátrányok:

  • A csapat tagjainak tehetetlensége — Nagios folyamatosan működött, míg a te Icingád állandóan lefagyott és akadozott. De itt hogy nézhetem meg a történetet? Ja, a büdös életbe, hiszen nem is frissül… (Valós probléma — a riasztások története nem frissül automatikusan, csak F5 után)
  • A rendszer tehetetlensége — amikor a webes felületen a "frissítés" (check now) gombra kattintok, a végrehajtás eredménye a Mars időjárásától függ, különösen bonyolult szolgáltatások esetén, amelyek végrehajtásához tíz másodpercek kellenek. Az ilyen eredmény normális. Migrálás Nagios-ról Icinga2-re Ausztráliában
  • Összességében a két rendszer féléves statisztikája alapján a Nagios mindig gyorsabban működött, mint az Icinga, és ez nagyon idegesít. Úgy tűnik, ott valamit elrontottak az időzítőkkel, és az ötpercenkénti ellenőrzés valójában öt percen és harminc másodpercen történik, vagy valami hasonló.
  • Ha bármikor újraindítom a szolgáltatást (systemctl restart icinga2) — az összes ellenőrzés, ami éppen folyamatban volt, critical riasztást ad a képernyőn, és így néz ki, mintha minden összeomlott volna (megerősített hiba).

De összességében — működik.

Forrás: habr.com

Megbízható hosting vásárlása weboldalak számára, DDoS védelemmel, VPS VDS szerverek. 🔥 Megbízható webtárhely vásárlása DDoS védelemmel, VPS VDS szerverek | ProHoster