Migrasi dari Nagios ke Icinga2 di Australia

Halo.

Saya seorang administrator sistem Linux, saya pindah dari Rusia ke Australia dengan visa profesional independen pada tahun 2015, tetapi artikel ini tidak akan membahas tentang cara memulai traktor untuk babi. Sudah cukup banyak artikel seperti itu (namun, jika ada minat, saya akan menulis tentang ini juga), jadi saya ingin berbicara tentang bagaimana, dalam pekerjaan saya di Australia sebagai insinyur operasi linux, saya memulai migrasi dari satu sistem pemantauan ke yang lain. Khususnya - Nagios => Icinga2.

Artikel ini sebagian bersifat teknis dan sebagian lagi tentang komunikasi dengan orang-orang dan masalah-masalah yang terkait dengan perbedaan budaya dan metode kerja.

Sayangnya, tag “code” tidak menyorot kode Puppet dan yaml, jadi saya harus menggunakan “plaintext”.

Tidak ada tanda-tanda gangguan pada pagi hari tanggal 21 Desember 2016. Seperti biasa, saya membaca Habr oleh pengguna anonim yang tidak terdaftar pada setengah jam pertama hari kerja, sambil minum kopi, dan menemukan artikel ini.

Karena perusahaan saya menggunakan Nagios, tanpa berpikir dua kali, saya membuat tiket di Redmine dan mengirimkan link ke chat umum, karena saya anggap penting. Inisiatif ini dapat dihukum bahkan di Australia, jadi teknisi utama menyalahkan saya sejak saya menemukannya.

Tangkapan layar dari RedmineMigrasi dari Nagios ke Icinga2 di Australia

Di departemen kami, sebelum mengutarakan pendapat Anda, biasanya menawarkan setidaknya satu alternatif, meskipun pilihannya jelas, jadi saya mulai dengan mencari di Google jenis sistem pemantauan apa yang relevan saat ini, karena di Rusia di tempat kerja terakhir saya, saya memiliki sistem yang saya tulis sendiri, sangat primitif, namun cukup berfungsi dan melakukan semua tugas yang diberikan padanya. Python, Politeknik St. Petersburg dan pemerintahan metro. Tidak, kereta bawah tanahnya jelek. Ini bersifat pribadi (11 tahun bekerja) dan layak untuk artikel terpisah, tetapi tidak sekarang.

Sedikit tentang aturan dalam melakukan perubahan konfigurasi infrastruktur di tempat saya saat ini. Kami menggunakan prinsip Wayang, Gitlab, dan Infrastruktur sebagai Kode, jadi:

  • Tidak ada perubahan manual melalui SSH dengan mengubah file apa pun secara manual di mesin virtual. Selama tiga tahun bekerja, saya dipukul berkali-kali karena hal ini, terakhir kali adalah seminggu yang lalu dan saya rasa itu bukan yang terakhir kalinya. Ya, sungguh - perbaiki satu baris di konfigurasi, mulai ulang layanan dan lihat apakah masalahnya sudah teratasi - 10 detik. Buat cabang baru di Gitlab, lakukan perubahan, tunggu r10k berfungsi di Puppetmaster, jalankan Puppet -environment=mybranch dan tunggu beberapa menit lagi hingga semuanya berfungsi - minimal 5 menit.
  • Setiap perubahan dilakukan dengan membuat Permintaan Penggabungan di Gitlab dan harus disetujui oleh setidaknya satu anggota tim. Perubahan besar yang diputuskan oleh ketua tim memerlukan dua atau tiga persetujuan.
  • Semua perubahan adalah teks dalam satu atau lain cara (karena manifes Wayang, skrip, dan data Hiera adalah teks), biner sangat tidak disarankan dan perlu ada alasan kuat untuk menyetujui file tersebut.

Jadi, opsi yang saya pertimbangkan:

  • Munin - jika ada lebih dari 10 server di infrastruktur, administrasi berubah menjadi neraka (dari artikel ini. Saya tidak punya keinginan khusus untuk memeriksanya, jadi saya percaya pada kata-katanya).
  • Zabbix - Saya sudah lama melihatnya, di Rusia, tapi kemudian itu mubazir untuk tugas saya. Di sini - harus dibuang karena penggunaan Wayang sebagai manajer konfigurasi dan Gitlab sebagai sistem kontrol versi. Pada saat itu, sejauh yang saya pahami, Zabbix menyimpan seluruh konfigurasi dalam database, dan oleh karena itu tidak jelas bagaimana mengelola konfigurasi dalam kondisi saat ini dan bagaimana melacak perubahan.
  • Prometheus adalah apa yang akan kita bahas pada akhirnya, dilihat dari suasana di departemen, tetapi pada saat itu saya tidak menguasainya dan tidak dapat mendemonstrasikan sampel yang benar-benar berfungsi (Bukti Konsep), jadi saya harus menolak.
  • Ada juga beberapa opsi lain yang memerlukan pengerjaan ulang sistem secara menyeluruh, atau masih dalam tahap awal/ditinggalkan dan ditolak karena alasan yang sama.

Pada akhirnya, saya memilih Icinga2 karena tiga alasan:

1 - kompatibilitas dengan Nrpe (layanan klien yang menjalankan pemeriksaan perintah dari Nagios). Ini sangat penting, karena pada saat itu kami memiliki 135 (sekarang ada 2019 pada tahun 165) mesin virtual dengan banyak layanan/pemeriksaan yang ditulis khusus, dan mengulangi semuanya akan sangat merepotkan.
2 - semua file konfigurasi adalah teks, yang memudahkan untuk mengedit masalah ini, membuat permintaan penggabungan dengan kemampuan untuk melihat apa yang telah ditambahkan atau dihapus.
3 adalah proyek OpenSource yang hidup dan berkembang. Kami sangat menyukai OpenSource dan memberikan kontribusi maksimal dengan membuat Permintaan Tarik dan Masalah untuk memecahkan masalah.

Jadi, ayo berangkat, Icinga2.

Hal pertama yang harus saya hadapi adalah kelembaman rekan-rekan saya. Semua orang sudah terbiasa dengan Nagios/Naggios (walaupun di sini pun mereka tidak bisa berkompromi tentang cara mengucapkannya) dan antarmuka CheckMK. Antarmuka icinga terlihat sangat berbeda (ini adalah nilai minus), tetapi dimungkinkan untuk secara fleksibel menyesuaikan apa yang perlu Anda lihat menggunakan filter untuk parameter apa pun (ini adalah nilai tambah, tetapi saya berjuang keras untuk itu).

FilterMigrasi dari Nagios ke Icinga2 di Australia

Perkirakan rasio ukuran bilah gulir dengan ukuran bidang gulir.

Kedua, semua orang terbiasa melihat seluruh infrastruktur pada satu monitor, karena CheckMk memungkinkan Anda bekerja dengan beberapa host Nagios, tetapi antarmuka Icinga tidak dapat melakukan ini (sebenarnya bisa, tetapi lebih lanjut tentang itu di bawah). Alternatifnya adalah sesuatu yang disebut Thruk, namun desainnya membuat semua orang di tim terkejut kecuali satu orang yang menyarankannya (bukan saya).

Ke dalam tungku Thruk - keputusan bulat timMigrasi dari Nagios ke Icinga2 di Australia

Setelah beberapa hari bertukar pikiran, saya mengusulkan ide pemantauan cluster, ketika ada satu host master di zona produksi dan dua budak - satu di dev/test dan satu host eksternal yang terletak di penyedia lain untuk memantau kami layanan dari sudut pandang klien atau pengamat luar. Konfigurasi ini memungkinkan untuk melihat semua masalah dalam satu antarmuka web dan bekerja dengan cukup baik, tetapi Wayang... Masalah dengan Wayang adalah bahwa host utama sekarang harus mengetahui semua host dan layanan/pemeriksaan dalam sistem dan telah untuk mendistribusikannya antar zona (dev-test, staging-prod, ext), tetapi mengirimkan perubahan melalui Icinga API membutuhkan beberapa detik, tetapi mengkompilasi direktori Wayang semua layanan untuk semua host membutuhkan beberapa menit. Saya masih menyalahkan hal ini, meskipun saya sudah menjelaskan beberapa kali bagaimana semuanya bekerja dan mengapa semuanya memakan waktu lama.

Ketiga, ada sekumpulan Kepingan Salju - hal-hal yang menonjol dari sistem umum karena memiliki sesuatu yang istimewa, sehingga aturan umum tidak berlaku untuknya. Itu diselesaikan dengan serangan frontal - jika ada alarm, tetapi sebenarnya semuanya beres, maka saya perlu menggali lebih dalam dan mencari tahu mengapa itu mengingatkan saya, meskipun seharusnya tidak. Atau sebaliknya - kenapa Nagios panik, tapi Icinga tidak.

Keempat, Nagios bekerja di sini sebelum saya selama tiga tahun dan awalnya ada lebih banyak kepercayaan padanya daripada sistem hipster bermodel baru saya, jadi setiap kali Icinga menimbulkan kepanikan, tidak ada yang melakukan apa pun sampai Nagios menjadi bersemangat tentang masalah yang sama. Tapi sangat jarang Icinga menimbulkan alarm nyata sebelum Nagios dan saya menganggap ini sebagai masalah serius, yang akan saya bicarakan di bagian “Kesimpulan”.

Akibatnya, commissioning tertunda selama lebih dari 5 bulan (direncanakan pada 28 Juni 2018, sebenarnya - 3 Desember 2018), terutama karena "pemeriksaan paritas" - omong kosong ketika ada beberapa layanan di Nagios yang tidak diketahui siapa pun tentang belum mendengar apa pun selama beberapa tahun terakhir, tapi SEKARANG mereka memberikan kritik tanpa alasan dan saya harus menjelaskan mengapa mereka tidak ada di panel saya dan harus menambahkannya ke Icinga sehingga "pemeriksaan paritas adalah selesai" (Semua layanan/pemeriksaan di Nagios sesuai dengan layanan/pemeriksaan di Icinga)

Pelaksanaan:
Yang pertama adalah perang Kode vs Data, seperti Gaya Wayang. Semua data, semuanya, harus ada di Hiera dan tidak ada yang lain. Semua kode ada dalam file .pp. Variabel, abstraksi, fungsi - semuanya ada di halaman.
Hasilnya, kami memiliki banyak mesin virtual (165 pada saat penulisan) dan 68 aplikasi web yang perlu dipantau kinerja dan validitas sertifikat SSL. Namun karena riwayat wasir, informasi untuk aplikasi pemantauan diambil dari repositori gitlab terpisah dan format data tidak berubah sejak Wayang 3, yang menciptakan kerumitan tambahan dalam konfigurasi.

Kode boneka untuk aplikasi, lindungi mata Anda

define profiles::services::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'], {} )) } # adds notifications for default group (systems) + any group defined in 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')        # Pick a regex to check

    $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 | {        # Split an app by domains if there are two or more
      $vhost_name = {'http_vhost' => $vhost}

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

      $web_ipaddress = is_array($vdata['web_ipaddress']) ? {  # Make IP-address an array if it's not, because askizzy has 2 ips and it's an array
        true  => $vdata['web_ipaddress'],
        false => [$vdata['web_ipaddress']],
      }

      $access_from_zones = [$zone] + $apps_access_list[$data['accessible_from']] # Merge default zone (where the app is defined) and extra zones if they exist
      $web_ipaddress.each | String $ip_address | {            # For each IP (if we have multiple)
        $suffix = length($web_ipaddress) ? {                  # If we have more than one - add IP as a suffix to this hostname to avoid duplicating resources
          1       => '',
          default => "_${ip_address}"
        }
        $octets = split($ip_address, '.')
        $ip_tag = "${octets[2]}.${octets[3]}" # Using last octet only causes a collision between nginx-vip 203.15.70.94 and 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}" # If it's a host for ext - prefix becomes '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
              }
            }
          }
        }
      }
    }
  }
}

Kode konfigurasi untuk host dan layanan juga terlihat buruk:

pemantauan/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 <<| |>> # will be enabled when we move to icinga completely
#### 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('Please ensure the node has $location fact set (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 <<| |>> # This is for spaceship invasion when it's ready.
  $hosts_has_large_disks = query_nodes('mountpoints.*.size_bytes >= 1099511627776')

  $hosts.each | String $hostgroup, Hash $list_of_hosts_with_settings | {           # Splitting site lists by 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 |{  # Splitting grouplists by hosts
      # Is this host in the array $hosts_has_large_disks ? If so set 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)) # Merging vars separately

      $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){                                                                # All hosts managed by API
    $hosts_api.each | String $zone, Hash $hosts_api_zone | {                            # Split api hosts by zones
      $hosts_api_zone.each | String $hostgroup, Hash $list_of_hosts_with_settings | {   # Splitting site lists by 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 |{        # Splitting grouplists by hosts
          # Is this host in the array $hosts_has_large_disks ? If so set 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'],
          }
        }
      }
    }
  }

#### END OF HOSTS ####

####   SERVICES   ####

  $services.each | String $service_group, Hash $s_list |{             # Service_group and list of services in that group
    $service_list = $s_list['checks']                                 # List of actual checks, separately from SG settings
    $service_list.each | String $service_name, Hash $data |{

      $merged_defaults = merge($service_defaults, $s_list['settings']) # global service defaults + service group defaults
      $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)

      # If we override default check_timeout, but not nrpe_timeout, make nrpe_timeout the same as check_timeout
      if ( $merged_data['check_timeout'] and ! $this_service_vars['nrpe_timeout'] ) {
        # NB: Icinga will convert 1m to 60 automatically!
        $nrpe = { 'nrpe_timeout' => $merged_data['check_timeout'] }
      } else {
        $nrpe = {}
      }

      # By default we use nrpe and all commands are run via nrpe. So vars.nrpe_command = $service_name is a default value
      # If it's server-side Icinga command - we don't need 'nrpe_command'
      # but there is no harm to have that var and the code is shorter

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

      # Assembling $vars from Global Default service settings, servicegroup settings, this particular check settings and let's not forget nrpe settings.
      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 is required everywhere, otherwise becomes "The value '' cannot be converted to Numeric"

      $service_notify_group = $service_notify ? {
        []      => $service_defaults['vars']['notify_group'],
        default => $service_notify
      } # Assing default group (systems) if no other groups are defined

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

      # This needs to be merged separately, because merging it as part of MERGED_DATA overwrites arrays instead of merging them, so we lose some "assign" and "ignore" values

      $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'],
      }
    }
  }
#### END OF SERVICES ####

#### OTHER BORING STUFF ####

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

  # Merging notification settings for users with other settings
  $users_oncall = deep_merge($users, $oncall)
  # Magic. Do not touch.
  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',
  }

}

Saya masih mengerjakan mie ini dan memperbaikinya sebaik mungkin. Namun, kode inilah yang memungkinkan kami menggunakan sintaksis yang sederhana dan mudah dipahami di Hiera:

Data

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'

Semua pemeriksaan dibagi menjadi beberapa grup, setiap grup memiliki pengaturan default seperti di mana dan seberapa sering menjalankan pemeriksaan tersebut, notifikasi apa yang harus dikirim dan kepada siapa.

Di setiap pemeriksaan, Anda dapat mengganti opsi apa pun, dan semua ini pada akhirnya menambah pengaturan default semua pemeriksaan secara keseluruhan. Itu sebabnya omong kosong seperti itu ditulis di config.pp - ini menggabungkan semua pengaturan default dengan pengaturan grup dan kemudian dengan setiap pemeriksaan individual.

Perubahan lain yang sangat penting adalah kemampuan untuk menggunakan fungsi-fungsi dalam pengaturan, misalnya fungsi penggantian port, alamat dan url untuk memeriksa 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

Artinya - jika ada variabel dalam definisi host http_port — gunakan, jika tidak 443. Misalnya, antarmuka web jabber hang di 9090, dan Unifi hang di 7443.
http_vhost berarti abaikan DNS dan ambil alamat ini.
Jika uri ditentukan di host, ikuti saja, jika tidak ambil "/".

Sebuah cerita lucu keluar dengan http_ssl - infeksi ini tidak ingin terputus sesuai permintaan. Saya bingung tentang baris ini untuk waktu yang lama sampai saya sadar bahwa variabel dalam definisi host adalah:

http_ssl: false

Diganti menjadi ekspresi

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

sebagai palsu dan pada akhirnya ternyata

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

maksudnya cek ssl selalu aktif. Saya menyelesaikannya dengan mengganti sintaks:

http_ssl: no

Temuan:

Pro:

  • Saat ini kita hanya mempunyai satu sistem pemantauan, dan bukan dua, seperti yang kita miliki selama 7-8 bulan terakhir, atau sistem yang sudah ketinggalan jaman dan rentan.
  • Struktur data host/layanan(pemeriksaan) sekarang (menurut saya) jauh lebih mudah dibaca dan dimengerti. Bagi yang lain, hal ini ternyata tidak begitu jelas, jadi saya harus memposting beberapa halaman di wiki lokal untuk menjelaskan cara kerjanya dan di mana harus diedit.
  • Dimungkinkan untuk mengkonfigurasi pemeriksaan secara fleksibel menggunakan variabel dan fungsi, misalnya, untuk memeriksa http_regexp, pola yang diinginkan, kode pengembalian, url dan port dapat diatur dalam pengaturan host.
  • Ada beberapa dasbor, yang masing-masingnya Anda dapat menentukan daftar alarm yang ditampilkan dan mengelola semua ini melalui permintaan Wayang dan penggabungan.

Cons:

  • Inersia anggota tim - Nagios bekerja, bekerja dan bekerja, dan Isinga Anda ini selalu bermasalah dan lambat. Bagaimana Anda bisa melihat sejarah di sini? Oh sial, tidak diperbarui... (Masalah sebenarnya adalah riwayat alarm tidak diperbarui secara otomatis, hanya dengan F5)
  • Kelambanan sistem - ketika saya mengklik "perbarui" (periksa sekarang) di antarmuka web - hasil eksekusi bergantung pada cuaca di Mars, terutama pada layanan kompleks yang memerlukan waktu puluhan detik untuk dijalankan. Hasil seperti itu adalah hal yang wajar. Migrasi dari Nagios ke Icinga2 di Australia
  • Secara umum, menurut statistik enam bulan pengoperasian kedua sistem secara berdampingan, Nagios selalu bekerja lebih cepat daripada Icinga dan ini sangat mengganggu saya. Tampak bagi saya bahwa mereka mengacaukan pengatur waktu dan pemeriksaan dilakukan setiap lima menit, sebenarnya itu terjadi setiap jam 5:30 atau sekitar itu.
  • Jika Anda memulai ulang layanan kapan saja (systemctl restart icinga2) - semua pemeriksaan yang sedang berlangsung pada saat itu akan menghasilkan alarm kritis di layar dan dari luar tampak seolah-olah semuanya telah jatuh (bug yang dikonfirmasi).

Tapi secara keseluruhan, ini berhasil.

Sumber: www.habr.com

Beli hosting yang andal untuk situs dengan perlindungan DDoS, server VPS VDS 🔥 Beli hosting website andal dengan perlindungan DDoS, server VPS VDS | ProHoster