Migrimi nga Nagios në Icinga2 në Australi

Përshëndetje të gjithëve.

Unë jam një administrator linux, transferuar nga Rusia në Australi me një vizë profesionale të pavarur në vitin 2015, por ky artikull nuk do të jetë për mënyrën se si një derra mund të blejë një traktor. Ka mjaft artikuj të tillë (ndonjëherë, nëse ka interes, do të shkruaj edhe për këtë), kështu që do të doja të flisja për mënyrën se si, në punën time në Australi si inxhiner linux-ops, isha iniciatori i migrimit nga një sistem monitorimi në një tjetër. Konkretisht - Nagios => Icinga2.

Artikulli është pjesërisht teknik dhe pjesërisht - mbi ndërveprimin me njerëzit dhe problemet e lidhura me diferencat kulturore dhe metodat e punës.

Fatkeqësisht, tiku «code» nuk ndriçon kodin Puppet dhe yaml, kështu që duhet të përdor «plaintext».

Asgjë nuk parashikonte ndodhi mëngjesin e 21 dhjetorit 2016. Unë, ashtu si zakonisht, isha duke lexuar Habr si një anonim i pa regjistruar në dy orët e para të ditës së punës, duke e pirë kafen dhe u ndala te këtë artikull.

Duke qenë se në kompaninë time përdorej Nagios, nuk mendova gjatë dhe krijova një tiket në Redmine dhe shpërndaova lidhjen në bisedën e përbashkët, pasi e konsiderova të rëndësishme. Iniciativa është ndëshkuese edhe në Australi, kështu që inxhinieri kryesor e ngarkoi këtë problem mbi mua, duke qenë se unë e zbulova atë.

Skena nga RedmineMigrimi nga Nagios në Icinga2 në Australi

Në departamentin tonë, para se të shprehim mendimin tonë, është zakon t'u ofrojmë të paktën një alternativë, edhe nëse zgjedhja është e dukshme, prandaj fillova me googlimin e cilave sisteme monitorimi janë të aktualizuara aktualisht, pasi në vendin tim të fundit të punës në Rusi kisha sistemin tim të shkruar vetë, shumë primitiv, por megjithatë plotësisht funksional dhe duke përmbushur të gjitha detyrat që i ishin ngarkuar. Python, Politehnika e Shën Pjetërburgut dhe metroja janë të shkëlqyera. Jo, metroja është e keqe. Kjo është personale (11 vjet punë) dhe meriton një artikull të veçantë, por jo tani.

Pak rreth rregullave të ndryshimeve në konfigurimin e infrastrukturës në vendin tim të tanishëm të punës. Ne përdorim Puppet, Gitlab dhe parimin e Infrastrukturës si Kod, kështu që:

  • Asnjë ndryshim manual përmes SSH duke ndryshuar dorazi ndonjë skedar në makinën virtuale. Gjatë tre viteve të punës kam marrë ndëshkime për këtë shumë herë, e fundit - një javë më parë dhe nuk mendoj se ishte hera e fundit. Mirë, në të vërtetë - të rregullosh një rresht në konfigurim, të rinisësh shërbimin dhe të shohësh nëse u zgjidh problemi - 10 sekonda. Të krijosh një degë të re në Gitlab, të shtosh ndryshimet, të presësh që r10k të funksionojë në Puppetmaster, të nisim Puppet -environment=mybranch dhe disa minuta të tjera të presësh derisa gjithçka të funksionojë - të paktën 5 minuta.
  • Të gjitha ndryshimet bëhen përmes krijimit të një Merge Request në Gitlab dhe nevojitet miratimi i paktën nga një anëtar i ekipit. Ndryshime të mëdha sipas vendimit të liderit të ekipit kërkojnë dy ose tre miratime.
  • Të gjitha ndryshimet janë në formë teksti (pasi manifestat e Puppet, skriptet dhe të dhënat Hiera janë tekste), skedarët binarë janë shumë të papëlqyer dhe për miratimin e këtyre skedarëve kërkohen arsye të forta.

Pra, opsionet që shqyrtova ishin:

  • Munin - nëse infrastruktura ka më shumë se 10 servera, administrimi shndërrohet në një çmenduri (nga këtë artikull. Nuk kisha dëshirë të vepronte këtë, prandaj e pranuam si fjalë).
  • Zabbix - kam pasur për një kohë në vëmendje, edhe në Rusi, por atëherë ishte i tepruar për nevojat e mia. Këtu - duhej ta përjashtoja për shkak të përdorimit të Puppet si menaxher konfigurimi dhe Gitlab si sistem kontrolli versioni. Në atë kohë, sa kuptova - Zabbix ruan të gjitha konfigurimet në një bazë të dhënash, për të cilën nuk ishte e qartë si të menaxhohej konfigurimi në kushtet aktuale dhe si të përndiqeshin ndryshimet.
  • Prometheus - ajo në të cilën ne do të arrijmë në fund, sipas humorit në departament, por në atë kohë nuk isha në gjendje ta tregoja një mostër funksionale (Prova e Konceptit), kështu që duhej të heqja dorë.
  • Ishte edhe disa opsione të tjera, që kërkonin një rivlerësim të plotë të sistemit, ose ishin në faza fillestare / të braktisura dhe për këtë arsye u përjashtuan.

Përfundimisht, u ndala në Icinga2 për tri arsye:

1 - kompatibilitet me Nrpe (shërbimi klient që ekzekuton kontrollin me komandat nga Nagios). Kjo ishte shumë e rëndësishme, sepse në atë kohë kishim 135 (tani në 2019, janë 165) makina virtuale me një shumëllojshmëri shërbimesh/kontrollesh të shkruara vetë dhe riparimi i të gjitha këtyre do të ishte një dhimbje e madhe.
2 - të gjitha skedarët e konfigurimit janë tekst, gjë që lejon editimin e lehtë të kësaj, krijimin e kërkesave për bashkimin me mundësinë e shikimit çfarë është shtuar ose hequr.
3 - është një projekt OpenSource aktiv dhe në zhvillim. Ne e duam shumë OpenSource dhe kontribuojmë në të përmes krijimit të Kërkesave të Bashkimit dhe Problemesh për zgjidhjen e çështjeve.

Pra, le të fillojmë, Icinga2.

E para, që çfarë kam hasur — inertësia e kolegëve. Të gjithë ishin mësuar me Nagios/Nagios (ndonëse këtu nuk arritëm të gjenim një kompromis mbi si ta shqiptojmë) dhe ndërfaqen e CheckMK. Me icinga ndërfaqja duket krejt ndryshe (kjo ishte një disavantazh), por ka mundësinë për të përshtatur me fleksibilitet atë që duhet të shikohet përmes filtrave në çdo parametrim (kjo ishte një avantazh, por për të luftuar për të, kam pasur shumë punë).

FiltratMigrimi nga Nagios në Icinga2 në Australi

Vlerësoni raportin e madhësisë së shiritit të skrollit me madhësinë e fushës për skrollim.

E dyta — të gjithë ishin mësuar të shihnin gjithë infrastrukturën në një monitor, sepse CheckMk lejon të punosh me disa hoste Nagios, por ndërfaqja Icinga nuk e bënte këtë (në fakt e bënte, por për këtë do flasim më poshtë). Një alternativë ishte diçka e quajtur Thruk, por dizajni i saj shkaktonte që të gjithë anëtarët e ekipit të përjetonin të vjella, përveç njërit — atij që e propozoi (nuk isha unë).

Fatkeqësisht Thruk — ishte një vendim unanim i ekipit.Migrimi nga Nagios në Icinga2 në Australi

Pas disa ditësh brainstorming-u, kam propozuar idenë e monitorimit të grupeve, ku ka një host master në zonën e prodhimit dhe dy nënshërbime — një në dev/test dhe një host të jashtëm, i vendosur tek një ofrues tjetër, me qëllim që të monitorojmë shërbimet tona nga këndvështrimi i klientit ose një vëzhgues 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 hosti master tani duhej të dinte për të gjithë hostet dhe shërbimet/kontrollimet në sistem dhe duhej t'i shpërndante ato mes zonave (dev-test, staging-prod, ext), por dërgimi i ndryshimeve përmes Icinga API merr disa sekonda, ndërsa kompilimi i katalogut Puppet për të gjitha shërbimet për të gjitha hostet merr disa minuta. Kjo ende më është vënë në faj, ndonëse kam shpjeguar disa herë si funksionon dhe pse është kaq e gjatë.

E treta — shumë SnowFlakes (flokë bore) — gjëra që duken jashtë sistemit të zakonshëm, sepse kanë diçka të veçantë, prandaj rregullat e zakonshme nuk zbatohen për to. Kjo u zgjidh përmes një sulmi frontal — nëse ka alarm, por në fakt gjithçka është në rregull, atëherë këtu duhet të shqyrtojmë thellë dhe të kuptojmë pse më alarmon, ndonëse nuk duhet. Ose e kundërta — pse Nagios panikohet, ndërsa Icinga jo.

E katërt — Nagios ka punuar këtu për tre vjet para meje dhe kishte më shumë besim fillimisht sesa sistemi im modern hipster, prandaj çdo herë që Icinga ngjiste panik — askush nuk bënte asgjë, derisa Nagios nuk ngrihej për të njëjtin çështje. Por shumë rrallë Icinga jepte alarmet reale më parë se Nagios dhe unë e konsideroj këtë një gabim të rëndësishëm, për të cilin do të flas në seksionin "Përfundimet".

Në fund, futja në funksionim u zgjat më shumë se 5 muaj (planifikuar për 28 qershor 2018, në fakt — 3 dhjetor 2018), kryesisht për shkak të "parity check" — ajo gjë, ku ka disa shërbime në Nagios, për të cilat askush nuk kishte dëgjuar për dy vitet e fundit, por PIKËRISHT TANI ata, dreqi, dolën crit pa asnjë arsye dhe unë duhej të shpjegoja pse nuk ishin në panelin tim dhe duhej t'i shtoja ata në Icinga, që "parity check është përfunduar" (Të gjitha shërbimet/kontrollimet në Nagios përputhen me shërbimet/kontrollimet në Icinga).

Zbatimi:
E para — lufta Code vs Data, si në stilin Puppet. Të gjitha të dhënat, pikërisht të gjitha, duhet të jenë në Hiera dhe ndryshe asnjëherë. I gjithë kodi — në skedarë .pp. Variablat, abstraksionet, funksionet — gjithçka në pp.
Në fund — kemi një shumëllojshmëri makinash virtuale (165 në momentin e shkruarjes së këtij artikulli) dhe 68 aplikacione web, që duhet të monitorohen për funksionalitetin dhe për vërtetësinë e certifikateve SSL. Por për shkak të një histori të vështirë, informacioni për monitorimin e aplikacioneve merret nga një repozitor gitlab të veçantë dhe formati i të dhënave nuk është ndryshuar që nga Puppet 3, gjë që krijon vështirësi shtesë në konfigurim.

Kodi Puppet për aplikacionet, ruani sytë tuaj.

defino profile::shërbimeve::monitorimi::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,
  )
{
#### APLIKACIONET ####
  $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'], {} )) } # shton njoftime për grupin e paracaktuar (sistemet) + çdo grup të përcaktuar në int/pm_docker_apps.eyaml

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

    $site_domain = $app_data['site_domain']

    $regexp = pick($app_data['check_regex'], 'html')        # Zgjidhni një regex për të kontrolluar

    $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 | {        # Ndarja e një aplikacioni sipas domenesh nëse ka dy ose më shumë
      $vhost_name = {'http_vhost' => $vhost}

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

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

      $access_from_zones = [$zone] + $apps_access_list[$data['accessible_from']] # Bashkoni zonën standarde (ku është përcaktuar aplikacioni) dhe zonat shtesë nëse ekzistojnë
      $web_ipaddress.each | String $ip_address | {            # Për çdo IP (nëse kemi shumë)
        $suffix = length($web_ipaddress) ? {                  # Nëse kemi më shumë se një - shtoni IP-në si një prapashtesë në këtë emër host-i për të shmangur shumëzimin e burimeve
          1       => '',
          default => "_${ip_address}"
        }
        $octets = split($ip_address, '.')
        $ip_tag = "${octets[2]}.${octets[3]}" # Përdorimi i oktetit të fundit krijon një kolizion mes nginx-vip 203.15.70.94 dhe ext. ip 49.255.194.94

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

          $nginx_vip_name = "${zone_prefix}_nginx-vip-${ip_tag}" # Nëse është një host për ext - prapashtesa bëhet 'ext_' (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
              }
            }
          }
        }
      }
    }
  }
}

Kodi i konfigurimit të hosteve dhe shërbimeve gjithashtu duket jashtëzakonisht i papërshtatshë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
#### 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('Ju lutemi sigurohuni që nodi ka faktorin $location të vendosur (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 <> # Kjo është për invazionin e anijeve hapësinore kur të jetë gati.
  $hosts_has_large_disks = query_nodes('mountpoints.*.size_bytes >= 1099511627776')

  $hosts.each | String $hostgroup, Hash $list_of_hosts_with_settings | {           # Duke ndarë listat e vendeve sipas grupeve të hostëve - docker_host\/gluster_host\/etj.
    $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 |{  # Duke ndarë listat e grupeve sipas hostëve
      # A është ky host në array $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)) # Bashkimi i vars-ve veçmas

      $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){                                                                # Të gjitha hostet e menaxhuara nga API
    $hosts_api.each | String $zone, Hash $hosts_api_zone | {                            # Ndaj hostet api sipas zonave
      $hosts_api_zone.each | String $hostgroup, Hash $list_of_hosts_with_settings | {   # Duke ndarë listat e vendeve sipas grupeve të hostëve - docker_host\/gluster_host\/etj.
        $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 |{        # Duke ndarë listat e grupeve sipas hostëve
          # A është ky host në array $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:
            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'],
          }
        }
      }
    }
  }

#### FUND I HOSTEVE ####

####   SHERBIME   ####

  $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 kontrollimeve reale, të ndara nga cilësitë e SG
    $service_list.each | String $service_name, Hash $data |{

      $merged_defaults = merge($service_defaults, $s_list['settings']) # cilësitë globale të shërbimeve + cilësitë 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 anullojmë kohën e kontrollit të paracaktuar, por jo nrpe_timeout, bëni nrpe_timeout të njëjtë si check_timeout
      if ( $merged_data['check_timeout'] and ! $this_service_vars['nrpe_timeout'] ) {
        # NB: Icinga do të konvertojë 1m në 60 automatikisht!
        $nrpe = { 'nrpe_timeout' => $merged_data['check_timeout'] }
      } else {
        $nrpe = {}
      }

      # Në mënyrë të paracaktuar ne përdorim nrpe dhe të gjitha komandat ekzekutohen përmes nrpe. Pra vars.nrpe_command = $service_name është një vlerë parazgjedhje
      # Nëse është komandë e Icingës në anën e serverit - ne nuk kemi nevojë për 'nrpe_command'
      # por nuk ka dëm që të kemi atë var 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ësitë globale të shërbimeve, cilësitë e grupit të shërbimeve, cilësitë e këtij kontrolli të veçantë dhe mos harrojmë cilësitë 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 kërkohet kudo, ndryshe bëhet "Vlera '' nuk mund të konvertohet në Numerik"

      $service_notify_group = $service_notify ? {
        []      => $service_defaults['vars']['notify_group'],
        default => $service_notify
      } # Caktoni grupin parazgjedhës (sistemet) nëse nuk janë definuar grupe të tjera

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

      # Kjo duhet të bashkohet veçmas, sepse duke e bashkuar atë si pjesë e MERGED_DATA anashkalon array-t në vend që t'i bashkojë, kështu që humbasim disa vlera "cakto" dhe "injoro"

      $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'],
      }
    }
  }
#### FUND I SHERBIMEVE ####

#### GJËRA TË TJERA NËNUK KANË VLERË ####

  $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ësive të njoftimeve për përdoruesit me cilësi të tjera
  $users_oncall = deep_merge($users, $oncall)
  # Magji. Mos prek.
  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',
  }

}

Unë vazhdoj të punoj mbi këtë kod dhe e përmirësoj sa më shumë që të jetë e mundur. Megjithatë, ky kod lejon 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, dhe çdo grup ka cilësimet e tij të paracaktuara për vendin dhe frekuencën e ekzekutimit të këtyre kontrollimeve, si dhe për cilat njoftime të dërgohen dhe kujt.

Në çdo kontrollim është e mundur të ripërcaktohet çfarëdo opsioni dhe gjithçka përfundon duke u kombinuar me cilësimet e paracaktuara të të gjithë kontrollimeve në tërësi. Prandaj, në config.pp është shkruar një formë e tillë — aty bëhet bashkimi i të gjitha cilësimeve të paracaktuara me cilësimet e grupeve dhe pastaj me çdo kontrollim individual.

Një ndryshim shumë i rëndësishëm ishte 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-së për kontrollimin e 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ë definicionin e hostit ka një variabël http_port — ta përdorësh atë, përndryshe 443. Për shembull, ndërfaqja web e jabber është mbi 9090, ndërsa Unifi është mbi 7443.
http_vhost do të thotë të injorosh DNS dhe të marrësh këtë adresë.
Nëse në host është e specifikuar uri — atëherë të ndiqesh atë, përndryshe të marrësh «/».

Me http_ssl pasi që ngjarjat janë disi qesharake — kjo ishte një problem që nuk donte të çaktivizohej sipas kërkesës. Kaluar një kohë të gjatë duke u ndalur për këtë rresht, kisha kuptuar se ndryshimi në definicionin e hostit:

http_ssl: false

Zëvendësohej në shprehjen

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

si false dhe në fund del

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

pra kontrollimi ssl është gjithmonë aktiv. E zgjidhëm duke ndryshuar sintaksën:

http_ssl: no

Përfundimet:

Përparësitë:

  • Tani kemi një sistem të vetëm monitorimi, dhe jo dy, si ishte për 7-8 muajt e fundit, apo një të vjetruar dhe të brishtë.
  • Struktura e të dhënave të hosteve / shërbimeve (kontrollimeve) tani (në mendimin tim) është shumë më e lexueshme dhe e kuptueshme. Për të tjerët, kjo nuk ishte aq e qartë, kështu që isha i detyruar të krijoj disa faqe në wikin lokal për të sqaruar si funksionon gjithçka dhe çfarë duhet edituar.
  • Ka mundësi për konfigurimin fleksibël të kontrollimeve duke përdorur variabla dhe funksione, për shembull për kontrollimin http_regexp, modeli i kërkuar, kodi i rikthimit, URL dhe porti mund të definohen në cilësimet e hostit.
  • Ka disa panele (dashboards), për secilën prej të cilëve mund të përcaktohet lista e alarmave të shfaqura dhe të menaxhohet gjithçka përmes Puppet dhe merge requests.

Disavantazhet:

  • Inercia e anëtarëve të ekipit — NagiOS punonte, punonte dhe punonte, ndërsa ajo e Icinga vazhdimisht dështonte dhe ngadalësohej. Si mund ta shoh histori? Ah, të drejtat, ajo nuk përditësohet… (Problemi real — historia e alarmave nuk përditësohet automatikisht, vetëm përmes F5)
  • Inercia e sistemit — kur klikoja në ndërfaqen web mbi «refresh» (kontrollo tani) — rezultati i ekzekutimit varet nga moti në Mars, sidomos për shërbimet e ndërlikuara që kërkojnë disa sekonda për ekzekutimin. Një rezultat i tillë është diçka normale. Migrimi nga Nagios në Icinga2 në Australi
  • Duke parë statistikat për gjashtë muaj të dy sistemeve paralelisht, NagiOS gjithmonë e realizoi më shpejt sesa Icinga dhe kjo më shqetësonte shumë. Sikur të ishte një problem me timerat dhe kontrolli çdo pesë minuta është në fakt çdo 5:30 ose diçka e tillë.
  • Nëse e rinis shërbimin në çdo kohë (systemctl restart icinga2) — të gjitha kontrollimet që ishin në proces në atë moment do të raportojnë alarmin kritike <terminuar nga sinjali 15> në ekran dhe nga jashtë duket si të kishte rënë gjithçka (bug i konfirmuar).

Por në përgjithësi — po funksionon.

Burimi: habr.com

Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS 🔥 Bleni hostim të besueshëm për faqe me mbrojtje nga DDoS, serverë VPS VDS | ProHoster