Migrimi nga Nagios në Icinga2 në Australi

Përshëndetje të gjithëve.

UnĂ« jam administrator i sistemit Linux, kam bĂ«rĂ« trasferimin nga Rusia nĂ« Australi me njĂ« vizĂ« profesionale tĂ« pavarur nĂ« vitin 2015, por ky artikull nuk do tĂ« flasĂ« pĂ«r si tĂ« vendosĂ«sh njĂ« traktor pĂ«r njĂ« derr. Ka mjaft artikuj tĂ« tillĂ« (nĂ«se ka interes, mund tĂ« shkruaj edhe pĂ«r kĂ«tĂ«), kĂ«shtu qĂ« do tĂ« doja tĂ« flisja pĂ«r atĂ« se si nĂ« punĂ«n time nĂ« Australi si inxhinier linux-ops kam qenĂ« iniciatori i migrimit nga njĂ« sistem monitorimi nĂ« njĂ« tjetĂ«r. Konkretesht — Nagios => Icinga2.

Artikulli Ă«shtĂ« pjesĂ«risht teknik dhe pjesĂ«risht — pĂ«r komunikimin me njerĂ«zit dhe problemet qĂ« lidhen me ndryshimin e kulturĂ«s dhe metodave tĂ« punĂ«s.

Fatkeqësisht, etiketa «code» nuk ndriçon kodin e Puppet dhe yaml, kështu që duhej të përdorja «plaintext».

Asgjë nuk e parashikonte të keqen në mëngjesin e 21 dhjetorit 2016. Unë, si zakonisht, po lexoja Habr si një anonim i pa regjistruar gjatë dy orëve të para të ditës së punës, duke pirë kafe dhe u ndesha me ky artikull.

Duke qenë se në kompaninë time përdorej Nagios, pa menduar shumë, krijova një biletë në Redmine dhe dërgova lidhjen në bisedën e përgjithshme, duke e konsideruar këtë të rëndësishme. Iniciativa është e dënueshme edhe në Australi, kështu që inxhinieri kryesor e ngarkoi këtë problem mbi mua, pasi e kisha zbuluar.

Ekran nga RedmineMigrimi nga Nagios në Icinga2 në Australi

NĂ« departamentin tonĂ«, para se tĂ« paraqesĂ«sh mendimin tĂ«nd Ă«shtĂ« e zakonshme tĂ« ofrosh tĂ« paktĂ«n njĂ« alternativĂ«, edhe nĂ«se zgjedhja Ă«shtĂ« e qartĂ«, kĂ«shtu qĂ« fillova tĂ« kĂ«rkoja nĂ« Google se cilat sistemi monitorimi ishin aktualisht nĂ« treg, pasi nĂ« RusinĂ« nĂ« vendin tim tĂ« fundit tĂ« punĂ«s kisha njĂ« sistem tĂ« vetĂ«-shkruar, shumĂ« primitiv, por megjithatĂ« plotĂ«sisht funksional dhe duke pĂ«rmbushur tĂ« gjitha detyrat e caktuara. Python, Politekniku i ShĂ«n Petersburgut dhe metro janĂ« tĂ« shkĂ«lqyera. Jo, metro — Ă«shtĂ« e tmerrshme. Kjo Ă«shtĂ« personale (11 vjet punĂ«) dhe meriton njĂ« artikull tĂ« veçantĂ«, por jo tani.

Pak për rregullat e ndryshimeve në konfigurimin e infrastrukturës në vendin tim aktual të punës. Ne përdorim Puppet, Gitlab dhe parimin Infrastructure as Code, kështu që:

  • Nuk ka ndryshime manuale pĂ«rmes SSH duke modifikuar ndonjĂ« skedĂ« nĂ« makinat virtuale. GjatĂ« tre viteve tĂ« punĂ«s kam marrĂ« shumĂ« herĂ« kritikĂ« pĂ«r kĂ«tĂ«, herĂ«n e fundit njĂ« javĂ« mĂ« parĂ« dhe nuk mendoj se do tĂ« jetĂ« hera e fundit. E vĂ«rteta Ă«shtĂ« — tĂ« korrigjosh njĂ« rresht nĂ« konfigurim, tĂ« rinisĂ«sh shĂ«rbimin dhe tĂ« shikosh nĂ«se problemi Ă«shtĂ« zgjidhur — 10 sekonda. TĂ« krijosh njĂ« degĂ« tĂ« re nĂ« Gitlab, tĂ« bĂ«sh push, tĂ« presĂ«sh derisa r10k tĂ« funksioni nĂ« Puppetmaster, tĂ« nisĂ«sh Puppet —environment=mybranch dhe tĂ« presĂ«sh disa minuta derisa tĂ« pĂ«rfundojĂ« — minimumi 5 minuta.
  • Çdo ndryshim bĂ«het duke krijuar njĂ« Merge Request nĂ« Gitlab dhe kĂ«rkohet miratimi nga tĂ« paktĂ«n njĂ« anĂ«tar tĂ« ekipit. Ndryshimet serioze sipas vendimeve tĂ« liderit tĂ« ekipit kĂ«rkojnĂ« dy ose tre miratime.
  • TĂ« gjitha ndryshimet nĂ« njĂ« mĂ«nyrĂ« ose tjetĂ«r janĂ« tekstuale (pasi manifestet e Puppet, skriptet dhe tĂ« dhĂ«nat Hiera janĂ« tekst), skedarĂ«t binary janĂ« tepĂ«r tĂ« papĂ«rshtatshĂ«m dhe pĂ«r miratimin e atyre skedarĂ«ve nevojiten arsye tĂ« forta.

Pra, opsionet që kam shqyrtuar:

  • Munin — nĂ«se infrastruktura ka mĂ« shumĂ« se 10 serverĂ«, administrimi kthehet nĂ« njĂ« ferr (nga ky artikull. Nuk kisha dĂ«shirĂ« tĂ« veçantĂ« ta kontrolloja kĂ«tĂ«, kĂ«shtu qĂ« besoja nĂ« fjalĂ«n e tjetrit).
  • Zabbix — e kam vĂ«zhguar prej kohĂ«sh, qĂ« nga koha nĂ« Rusi, por atĂ«herĂ« ishte tepĂ«r i tepĂ«rt pĂ«r detyrat e mia. KĂ«tu — u detyrova ta braktis pĂ«r shkak tĂ« pĂ«rdorimit tĂ« Puppet si menaxher konfigurimi dhe Gitlab si sistem kontrolli versioni. NĂ« atĂ« moment, aq sa kam kuptuar — Zabbix ruan tĂ« gjithĂ« konfigurimin nĂ« njĂ« bazĂ« tĂ« dhĂ«nash, dhe nga ajo erdhi pyetja se si tĂ« menaxhohej konfigurimi nĂ« kushtet aktuale dhe si tĂ« ndiqeshin ndryshimet.
  • Prometheus — Ă«shtĂ« ajo nĂ« tĂ« cilĂ«n do tĂ« arrijmĂ« pĂ«rfundimisht, sipas ndjenjave nĂ« departament, por nĂ« atĂ« moment nuk arrita ta realizoja dhe nuk arrita tĂ« demonstroja njĂ« mostĂ«r funksionuese nĂ« mĂ«nyrĂ« reale (Proof of Concept), kĂ«shtu qĂ« u detyrova tĂ« heq dorĂ«.
  • Ishte edhe disa opsione tĂ« tjera, tĂ« cilat kĂ«rkonin njĂ« riparim tĂ« plotĂ« tĂ« sistemit, ose ishin nĂ« fazat fillestare / braktisur dhe pĂ«r kĂ«tĂ« arsye u hodhĂ«n poshtĂ«.

Në fund, u ndala te Icinga2 për tre arsye:

1 — kompatibilitet me Nrpe (shĂ«rbimi klientor qĂ« ekzekuton kontrollet pĂ«rmes komandave nga Nagios). Kjo ishte shumĂ« e rĂ«ndĂ«sishme, sepse nĂ« atĂ« kohĂ« kishim 135 (tani nĂ« 2019 janĂ« 165) makina virtuale me shumĂ« shĂ«rbime/kontrolle tĂ« krijuara vetĂ« dhe ristrukturimi i gjithĂ« kĂ«saj do tĂ« ishte njĂ« stres i madh.
2 — tĂ« gjithĂ« skedarĂ«t e konfigurimit janĂ« tekstualĂ«, çka lejon qĂ« tĂ« redaktohet lehtĂ«, tĂ« krijohen kĂ«rkesa pĂ«r bashkimin e skedarĂ«ve me mundĂ«sinĂ« pĂ«r tĂ« parĂ«, çfarĂ« Ă«shtĂ« shtuar ose fshirĂ«.
3 — ky Ă«shtĂ« njĂ« projekt OpenSource i gjallĂ« dhe nĂ« zhvillim. Ne e duam shumĂ« OpenSource dhe kontribuojmĂ« sa mundemi nĂ« tĂ« pĂ«rmes krijimit tĂ« KĂ«rkesave pĂ«r tĂ« TĂ«rhequr dhe Problemesh pĂ«r tĂ« zgjidhur.

Pra, le të fillojmë me Icinga2.

E para me tĂ« cilĂ«n u pĂ«rballa — inertĂ«sia e kolegĂ«ve. TĂ« gjithĂ« ishin mĂ«suar me Nagios/Nadjius (edhe kĂ«tu nuk arritĂ«m tĂ« pajtohemi se si ta shqiptojmĂ«) dhe ndĂ«rfaqen e CheckMK. Tek Icinga, ndĂ«rfaqja duket ndryshe (kĂ«to ishte njĂ« disavantazh), por ka mundĂ«sinĂ« pĂ«r ta konfiguruar fleksibĂ«l atĂ« qĂ« dĂ«shirojmĂ« tĂ« shohim pĂ«rmes filtrave pĂ«r çdo parameter (kĂ«to ishte njĂ« avantazh, por pĂ«r tĂ« luftova shumĂ«).

FiltërMigrimi nga Nagios në Icinga2 në Australi

Vlerësoni marrëdhënien e madhësisë së shenjës së rrotullimit me madhësinë e fushës për rrotullim.

E dyta — tĂ« gjithĂ« ishin mĂ«suar tĂ« shihnin tĂ« gjithĂ« infrastrukturĂ«n nĂ« njĂ« monitor, sepse CheckMk lejon tĂ« punosh me disa hoste Nagios, por ndĂ«rfaqja e Icinga nuk e bĂ«ri kĂ«tĂ« (nĂ« tĂ« vĂ«rtetĂ« e bĂ«nte, por pĂ«r kĂ«tĂ« mĂ« poshtĂ«). Alternativa ishte njĂ« gjĂ« qĂ« quhej Thruk, por dizajni i saj shkaktonte ndjenja tĂ« neveritshme te tĂ« gjithĂ« anĂ«tarĂ«t e ekipit pĂ«rveç njĂ«rit — atij qĂ« e propozoi (nuk isha unĂ«).

NĂ« djall me Thruk — vendim unanim i ekipit.Migrimi nga Nagios nĂ« Icinga2 nĂ« Australi

Pas disa ditĂ«sh mendimesh, unĂ« propozoja idenĂ« e monitorimit me klaster, ku ka njĂ« master-host nĂ« zonĂ«n e prodhimit dhe dy nĂ«nshtrues - njĂ« nĂ« dev/test dhe njĂ« host i jashtĂ«m, i vendosur te njĂ« ofrues tjetĂ«r me qĂ«llim qĂ« tĂ« monitorojĂ« shĂ«rbimet tona nga pikĂ«pamja e klientit ose njĂ« vĂ«zhguesi tĂ« jashtĂ«m. Kjo konfigurim lejonte tĂ« shihnim tĂ« gjitha problemet nĂ« njĂ« ndĂ«rfaqe web dhe funksiononte mjaft mirĂ«, por Puppet
 Problemi me Puppet ishte se master-host tani duhej tĂ« dinte pĂ«r tĂ« gjitha hostet dhe shĂ«rbimet/kontrollimet nĂ« sistem dhe duhej tĂ« shpĂ«rndante ato midis zonave (dev-test, staging-prod, ext), por dĂ«rgimi i ndryshimeve pĂ«rmes Icinga API merrte disa sekonda, ndĂ«rsa kompilimi i katalogut Puppet pĂ«r tĂ« gjitha shĂ«rbimet pĂ«r tĂ« gjitha hostet merrte disa minuta. MĂ« kĂ«tĂ« ende akuzohen, megjithĂ«se kam shpjeguar disa herĂ« si funksionon gjithçka dhe pse gjithçka Ă«shtĂ« kaq e gjatĂ«.

E treta - një mori SnowFlakes (flake që përfaqësojnë gjëra që dalin nga sistemi i përgjithshëm, sepse përmbajnë diçka të veçantë, për këtë arsye rregullat e përgjithshme nuk janë të zbatueshme. Kjo u zgjidh përmes një sulmi të drejtpërdrejtë - nëse ka alarmet, por në fakt gjithçka është në rregull, atëherë këtu duhet të thellohemi dhe të kuptojmë pse po alarmon, megjithëse nuk duhet. Ose përkundrazi - pse Nagios panikohet, ndonëse Icinga jo.

E katĂ«rta - Nagios kishte punuar kĂ«tu pĂ«r tre vjet para meje dhe kishte fillimisht mĂ« shumĂ« besim se sistemi im modern hipster, kĂ«shtu qĂ« çdo herĂ« qĂ« Icinga shkaktonte panik - askush nuk bĂ«ntĂ« asgjĂ«, derisa Nagios tĂ« alarmonte pĂ«r tĂ« njĂ«jtin çështje. Por shumĂ« rrallĂ« Icinga jepte alarmet reale pĂ«rpara Nagios dhe unĂ« e mendoj kĂ«tĂ« si njĂ« gabim tĂ« rĂ«ndĂ«sishĂ«m, pĂ«r tĂ« cilin do tĂ« flas nĂ« seksionin “PĂ«rfundimet”.

Si rezultat, implementimi u vonua mĂ« shumĂ« se 5 muaj (ishte planifikuar pĂ«r 28 qershor 2018, realisht - 3 dhjetor 2018), kryesisht pĂ«r shkak tĂ« “kontrollit tĂ« paritetit” - atij dreqi, kur ka disa shĂ«rbime nĂ« Nagios, pĂ«r tĂ« cilat askush nuk kishte dĂ«gjuar pĂ«r disa vite, por PIKËRISHT TANI ata, e lĂ«nĂ«, dolĂ«n crit pa ndonjĂ« arsye dhe mĂ« duhej tĂ« shpjegoja pse ata nuk ishin nĂ« panelin tim dhe duhej t'i shtoja nĂ« Icinga, qĂ« “kontrolli i paritetit Ă«shtĂ« pĂ«rfunduar” (TĂ« gjitha shĂ«rbimet/kontrollimet nĂ« Nagios pĂ«rputhen me shĂ«rbimet/kontrollimet nĂ« Icinga)

Zbatimi:
E para e — lufta Code vs Data, nĂ« stilin Puppet. TĂ« dhĂ«nat, pra tĂ« gjitha, duhet tĂ« jenĂ« nĂ« Hiera dhe ashtu siç Ă«shtĂ«. TĂ« gjithĂ« kodin — nĂ« skedarĂ«t .pp. Variablat, abstraksionet, funksionet — gjithçka shkon nĂ« pp.
NĂ« fund — kemi njĂ« sĂ«rĂ« makinash virtuale (165 nĂ« momentin e shkruajtur tĂ« artikullit) dhe 68 aplikacione web, tĂ« cilat duhet tĂ« monitorohen pĂ«r funksionalitetin dhe vlefshmĂ«rinĂ« e certifikatat SSL. Por pĂ«r shkak tĂ« historisĂ« problematike, informacioni pĂ«r monitorimin e aplikacioneve merret nga njĂ« repo tĂ« veçantĂ« gitlab dhe formati i tĂ« dhĂ«nave nuk Ă«shtĂ« ndryshuar qĂ« nga Puppet 3, gjĂ« qĂ« krijon vĂ«shtirĂ«si tĂ« mĂ«tejshme nĂ« konfigurim.

Kodi Puppet për aplikacionet, ruani sytë

përcakto profile::shërbimet::monitorimi::docker_apps(
  Hash $lista_aplikacioneve,
  Hash $aplikacionet_e_qasshme_nga,
  Hash $lista_e_qasshme_e_aplikacioneve,
  Hash $defaultet_e_webhost,
  Hash $defaultet_e_webcheck,
  Hash $përjashtimet_e_shërbimeve,
  Hash $objektivat,
  Hash $kontrollet_e_aplikacioneve,
  )
{
#### APLIKACIONET ####
  $zona = $emri
  $lista_aplikacioneve.each | String $emri_aplikacioni, Hash $të_Dhënat_e_aplikacionit |
  {

    $grupi_njoftues = { 'grupi_njoftues' => ($defaultet_e_webcheck[$zona]['grupi_njoftues'] + pick($të_Dhënat_e_aplikacionit['grupi_njoftues'], {} )) } # shton njoftime për grupin e parazgjedhur (sistemet) + çdo grup i përcaktuar në int/pm_docker_apps.eyaml

    $të_Dhënat = merge($defaultet_e_webhost, $aplikacionet_e_qasshme_nga, $të_Dhënat_e_aplikacionit)

    $domenu_i_saj $të_Dhënat_e_aplikacionit['domenu_i_saj']

    $regexp = pick($të_Dhënat_e_aplikacionit['kontrollo_regex'], 'html')        # Zgjidh një regex për të kontrolluar

    $kontrollo_url = $të_Dhënat_e_aplikacionit['kontrollo_url'] ? {
      undef   => { 'http_uri' => '\/\' },
      default => { 'http_uri' => $të_Dhënat_e_aplikacionit['kontrollo_url'] }
    }

    $kontrollo_regex = $regexp ?{
      'absent' => {},
      default  => {'http_pritet_trupi_regex' => $regexp}
    }

    $domenu_i_saj.each | String $vhost, Hash $vdata | {        # Ndaj një aplikacion sipas domenesh nëse ka dy ose më shumë
      $emri_vhost = {'http_vhost' => $vhost}

      $variablat = $të_Dhënat['variablat'] + $emri_vhost + $kontrollo_regex + $kontrollo_url

      $adresa_ip_web = is_array($vdata['adresa_ip_web']) ? {  # Bëni adresën IP një array nëse nuk është, sepse askizzy ka 2 ips dhe është një array
        true  => $vdata['adresa_ip_web'],
        false => [$vdata['adresa_ip_web']],
      }

      $qasshmeria_nga_zonat = [$zona] + $lista_e_qasshme_e_aplikacioneve[$të_Dhënat['e_qasshme_nga']] # Kombinoni zonën e parazgjedhur (ku eshte e përcaktuar aplikacioni) dhe zonat shtesë nëse ekzistojnë
      $adresa_ip_web.each | String $adresa_ip | {            # Për çdo IP (nëse kemi shumë)
        $shtesa = length($adresa_ip_web) ? {                  # Nëse kemi më shumë se një - shtoni IP si një shtesë në këtë emër hosti për të shmangur dyfishimin e burimeve
          1       => '',
          default => "_${adresa_ip}"
        }
        $octetet = split($adresa_ip, '.')
        $etiketa_ip = "${octetet[2]}.${octetet[3]}" # Përdorimi i oktetëve të fundit shkakton një kolizion midis nginx-vip 203.15.70.94 dhe ip ekst. 49.255.194.94

        $qasshmeria_nga_zonat.each | $prefix_zonë |{
          $objektivi_zonës = $objektivat[$prefix_zonë]

          $emri_nginx_vip = "${prefix_zonë}_nginx-vip-${etiketa_ip}" # Nëse është një host për ext - prefix bëhet 'ext_' (ext_nginx-vip...)
          $nginx_host_vip = {
            $emri_nginx_vip => {
              siguro        => prezent,
              objektivi        => $objektivi_zonës,
              adresa       => $adresa_ip,
              kontrollo_komandë => 'hostalive',
              grupe        => ['nginx_vip',],
            }
          }

          $variablat_ssl = $kontrollimet_e_aplikacioneve['ssl']
          $variablat_regex = $kontrollimet_e_aplikacioneve['http'] + $variablat + $defaultet_e_webcheck[$zona] + $grupi_njoftues

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

          if !defined( Icinga2::Object::Service["${emri_nginx_vip}_ssl"] ) {
            icinga2::object::service {"${emri_nginx_vip}_ssl":
              siguro         => $të_Dhënat['siguro'],
              cakto         => ["host.name == $emri_nginx_vip",],
              grupe         => ['webchecks',],
              kontrollo_komandë  => 'ssl',
              intervali_i_kontrollimit => $përjashtimet_e_shërbimeve['ssl']['intervali_i_kontrollimit'],
              objektivi         => $objektivat['shërbimet'],
              apliko          => true,
              variablat           => $variablat_ssl
            }
          }
          if $regexp != 'absent'{
            if !defined(Icinga2::Object::Service["${vhost}${$shtesa} regex"]){
              icinga2::object::service {"${vhost}${$shtesa} regex":
                siguro          => $të_Dhënat['siguro'],
                cakto          => ["match(*_nginx-vip-${etiketa_ip}, host.name)",],
                grupe          => ['webchecks',],
                kontrollo_komandë   => 'http',
                intervali_i_kontrollimit  => $përjashtimet_e_shërbimeve['regex']['intervali_i_kontrollimit'],
                objektivi          => $objektivat['shërbimet'],
                mundeso_flapping => true,
                apliko           => true,
                variablat            => $variablat_regex
              }
            }
          }
        }
      }
    }
  }
}

Kodi i konfigurimit të hosteve dhe shërbimeve duket gjithashtu tmerrshëm:

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 <> # do të aktivizohet kur të kalojmë plotësisht në icinga
#### APLIKACIONE ####
  rast $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']},
      }
    }

    defaut: {
      mos dështosh('Ju lutem sigurohuni që nodi të ketë faktorin e $location të vendosur (int, pm, ext)')
    }
  }

  file { '/etc/icinga2/conf.d/':
    siguroh => 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}":
      siguroh => 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,
    }
  }

####    HOSTET    ####

  # Profiles::Services::Monitoring::Host <> # Ky është për invazionin e anijes kur të jetë gati.
  $hosts_has_large_disks = query_nodes('mountpoints.*.size_bytes >= 1099511627776')

  $hosts.each | String $hostgroup, Hash $list_of_hosts_with_settings | {           # Ndarja e listave të site-ve sipas hostgroups - docker_host/gluster_host/etc
    $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 |{  # Ndarja e listave sipas hosteve
      # A është ky host në arrayn $hosts_has_large_disks? Nëse po, vendosni 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)) # Ndarja e variablave veçmas

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

      profiles::services::monitoring::host{$host_name:
        siguroh             => $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){                                                                # TĂ« gjitha hostet e menaxhuara nga API
    $hosts_api.each | String $zone, Hash $hosts_api_zone | {                            # Ndarja e hosteve të api sipas zonave
      $hosts_api_zone.each | String $hostgroup, Hash $list_of_hosts_with_settings | {   # Ndarja e listave të site-ve sipas hostgroups - docker_host/gluster_host/etc
        $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 |{        # Ndarja e listave sipas hosteve
          # A është ky host në arrayn $hosts_has_large_disks? Nëse po, vendosni 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:
            siguroh             => $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'],
          }
        }
      }
    }
  }

#### FUND I HOSTEVE ####

####   SHËRBIME   ####

  $services.each | String $service_group, Hash $s_list |{             # Grupi i shërbimeve dhe lista e shërbimeve në atë grup
    $service_list = $s_list['checks']                                 # Lista e kontrolleve aktuale, veçmas nga cilësimet e SG
    $service_list.each | String $service_name, Hash $data |{

      $merged_defaults = merge($service_defaults, $s_list['settings']) # defaultet globale të shërbimeve + defaultet e grupit të shërbimeve
      $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)

      # Nëse ne e kalojmë kohën e kontrollit të defaultit, por jo nrpe_timeout, bëj që nrpe_timeout të jetë e njëjtë me check_timeout
      if ( $merged_data['check_timeout'] and ! $this_service_vars['nrpe_timeout'] ) {
        # NB: Icinga do ta konvertojë 1m në 60 automatikisht!
        $nrpe = { 'nrpe_timeout' => $merged_data['check_timeout'] }
      } else {
        $nrpe = {}
      }

      # Në përgjithësi përdorim nrpe dhe të gjitha urdhërat ekzekutohen përmes nrpe. Pra vars.nrpe_command = $service_name është një vlerë e parazgjedhur
      # Nëse është urdhri i Icinga-s nga ana e serverit - nuk na nevojitet 'nrpe_command',
      # por nuk ka dëm që të kemi atë variabël dhe kodi është më i shkurtër

      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 = {}
      }

      # Duke mbledhur $vars nga cilësimet globale të shërbimeve, cilësimet e grupit të shërbimeve, këtë cilësim të veçantë të kontrollit dhe mos ta harrojmë cilësimin nrpe.
      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'], []) # pick është e nevojshme kudo, përndryshe bëhet "Vlera '' nuk mund të konvertohet në Numeric"

      $service_notify_group = $service_notify ? {
        []      => $service_defaults['vars']['notify_group'],
        default => $service_notify
      } # Cakto grupin e parazgjedhur (sistemet) nëse nuk janë përcaktuar grupe të tjera

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

      # Kjo duhet të bashkohet veçmas, sepse bashkimi i saj si pjesë e MERGED_DATA do të mbivendosë listat në vend të bashkimit, kështu që humbasim disa "cakto" dhe "injoro" vlera

      $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:
        siguroh             => $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'],
      }
    }
  }
#### FUND I SHËRBIMEVE ####

#### GJERË OTHER BORING ####

  $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'],
    }
  }

  # Bashkimi i cilësimeve të njoftimeve për përdoruesit me cilësime të tjera
  $users_oncall = deep_merge($users, $oncall)
  # Magji. Mos e preki.
  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':
    siguroh            => present,
    sudoersd_template => 'profiles/os/redhat/centos7/sudoers/icinga.erb',
  }

}

Unë vazhdoj të punoj mbi këtë kod dhe ta përmirësoj sa më shumë të jetë e mundur. Megjithatë, ky kod mundësoi përdorimin e një sintakse të thjeshtë dhe të qartë në Hiera:

Të dhënat

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'

Të gjitha kontrollimet janë të ndara në grupe, ku secili grup ka cilësime të paracaktuara si dhe ku dhe sa shpesh të kryhen këto kontrollime, cilat njoftime të dërgohen dhe kujt.

NĂ« çdo kontrollim mund tĂ« anashkalosh çdo opsion dhe gjithçka kĂ«shtu ka pĂ«rfunduar duke u kombinuar me cilĂ«simet e paracaktuara tĂ« tĂ« gjitha kontrollimeve nĂ« pĂ«rgjithĂ«si. Prandaj, nĂ« config.pp Ă«shtĂ« shkruar njĂ« kod i tillĂ« — atje ndodh kombinimi i tĂ« gjitha cilĂ«simeve tĂ« paracaktuara me cilĂ«simet e grupeve dhe mĂ« pas me çdo kontrollim individual.

Një tjetër ndryshim i rëndësishëm është mundësia për të përdorur funksione në cilësime, për shembull, funksioni për zëvendësimin e portit, adresës dhe url për kontrollimin http_regex.

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

Kjo do tĂ« thotĂ« — nĂ«se nĂ« pĂ«rkufizimin e hostit ka njĂ« variabĂ«l http_port — pĂ«rdoreni atĂ«, pĂ«rndryshe 443. PĂ«r shembull, ndĂ«rfaqja web e jabber Ă«shtĂ« nĂ« 9090, dhe Unifi — nĂ« 7443.
http_vhost do të thotë të injorosh DNS-në dhe të marrësh këtë adresë.
NĂ«se nĂ« host Ă«shtĂ« pĂ«rcaktuar uri — atĂ«herĂ« shko pĂ«rmes tij, pĂ«rndryshe merr "\/".

Me http_ssl ka ndodhur njĂ« histori qesharake — ky ndryshim nuk donte tĂ« ndizte sipas kĂ«rkesĂ«s. E kosa shumĂ« deri sa arrita tĂ« kuptoj se variabla ishte nĂ« pĂ«rkufizimin e hostit:

http_ssl: false

Përdoret në shprehje

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

si false dhe në fund rezulton

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

këshilla është se kontrolli i ssl është gjithmonë aktiv. U zgjidh duke ndryshuar sintaksën:

http_ssl: no

Përfundimet:

Avantazhet:

  • Tani kemi njĂ« sistem monitorimi, jo dy siç ishte pĂ«r 7-8 muajt e fundit, ose njĂ« tĂ« vjetĂ«r dhe tĂ« cenueshme.
  • Struktura e tĂ« dhĂ«nave tĂ« hosteve / shĂ«rbimeve (kontrollit) tani Ă«shtĂ« (nĂ« mendimin tim) shumĂ« mĂ« e lexueshme dhe e kuptueshme. PĂ«r tĂ« tjerĂ«t, kjo u duk se nuk ishte aq e qartĂ«, kĂ«shtu qĂ« pata nevojĂ« tĂ« krijoj disa faqe nĂ« wiki-n lokale pĂ«r tĂ« shpjeguar si funksionon gjithçka dhe çfarĂ« duhet tĂ« rregullohet.
  • Ka mundĂ«si pĂ«r konfigurimin fleksibĂ«l tĂ« kontrolleve me ndihmĂ«n e variablave dhe funksioneve, pĂ«r shembull pĂ«r kontrollin http_regexp modelin e kĂ«rkuar, kodin e kthimit, url dhe portin mund tĂ« pĂ«rcaktohen nĂ« cilĂ«simet e hostit.
  • Ka disa panele (dashboards), pĂ«r secilĂ«n prej tĂ« cilave mund tĂ« pĂ«rcaktoni listĂ«n e alarmave qĂ« do tĂ« shfaqen dhe tĂ« menaxhoni gjithçka pĂ«rmes Puppet dhe merge requests.

Disavantazhet:

  • Inercia e anĂ«tarĂ«ve tĂ« ekipit — Nagios punonte, punonte dhe punonte, ndĂ«rsa kjo Isinga jote gjithmonĂ« bllokohet dhe ngadalĂ«sohet. Po si tĂ« shoh histori? Oh, e qartĂ«, ajo nuk pĂ«rditĂ«sohet... (Problemi real — historia e alarmave nuk pĂ«rditĂ«sohet automatikisht, vetĂ«m me F5)
  • Inercia e sistemit — kur klikoj nĂ« ndĂ«rfaqen web nĂ« 'pĂ«rditĂ«so' (check now) — rezultati i ekzekutimit varet nga moti nĂ« Mars, sidomos pĂ«r shĂ«rbimet e komplikuara qĂ« kĂ«rkojnĂ« dhjetĂ«ra sekonda pĂ«r tĂ« pĂ«rfunduar. NjĂ« rezultat i tillĂ« Ă«shtĂ« njĂ« gjĂ« normale. Migrimi nga Nagios nĂ« Icinga2 nĂ« Australi
  • NĂ« pĂ«rgjithĂ«si, sipas statistikave gjashtĂ«-mujore tĂ« punĂ«s sĂ« dy sistemeve ngjitur, Nagios gjithmonĂ« funksiononte mĂ« shpejt se Icinga dhe kjo mĂ« irritonte shumĂ«. Siç mĂ« duket, atje kanĂ« bĂ«rĂ« ndonjĂ« truk me timerat dhe kontrolli çdo pesĂ« minuta nĂ« fakt ndodh çdo 5:30 ose diçka e tillĂ«.
  • NĂ«se rinis shĂ«rbimin nĂ« çdo moment (systemctl restart icinga2) — tĂ« gjitha kontrollet qĂ« nĂ« atĂ« moment ishin duke u ekzekutuar do tĂ« japin alarmin critical nĂ« ekran dhe nga anash duket se gjithçka ka rĂ«nĂ« (bug i konfirmuar).

Por nĂ« tĂ«rĂ«si — funksionon.

Burimi: habr.com

Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS đŸ”„ Blini hosting tĂ« besueshĂ«m pĂ«r faqe interneti me mbrojtje nga DDoS, serverĂ« VPS VDS | ProHoster