Migrar de Nagios a Icinga2 en Australia

Hola a todos


Soy el administrador de sistemas de Linux, me mud茅 de Rusia a Australia con una visa profesional independiente en 2015, pero el art铆culo no tratar谩 sobre c贸mo conseguir un lech贸n y un tractor. Dichos art铆culos ya son suficientes (sin embargo, si hay inter茅s, tambi茅n escribir茅 sobre ello), por lo que me gustar铆a hablar sobre c贸mo, en mi trabajo en Australia como ingeniero de linux-ops, fui el iniciador de la migraci贸n desde un sistema seguimiento a otro. Espec铆ficamente - Nagios => Icinga2.


El art铆culo es en parte t茅cnico y en parte sobre comunicaci贸n con personas y problemas asociados con la diferencia en cultura y m茅todos de trabajo.


Desafortunadamente, la etiqueta "c贸digo" no resalta el c贸digo de Puppet y yaml, as铆 que tuve que usar "texto sin formato".


Nada anunciaba mal la ma帽ana del 21 de diciembre de 2016. Como de costumbre, le铆 a Habr con un an贸nimo no registrado en la primera media hora de la jornada laboral, absorbiendo caf茅 y me encontr茅 con este art铆culo .


Como Nagios fue utilizado en mi empresa, sin pensarlo dos veces, cre茅 un ticket en Redmine y lanc茅 el enlace al chat general, porque pens茅 que era importante. La iniciativa es punible incluso en Australia, por lo que el ingeniero principal me colg贸 este problema desde que lo descubr铆.


Pantalla de Redmine

En nuestro departamento, antes de exponer nuestra opini贸n, es costumbre ofrecer al menos una alternativa, incluso si la elecci贸n es obvia, as铆 que comenc茅 buscando en Google qu茅 sistemas de monitoreo en general son relevantes actualmente, ya que en Rusia en el 煤ltimo lugar donde trabaj茅, ten铆a mi propio sistema de grabaci贸n personal, muy primitivo, pero sin embargo bastante funcional y cumpliendo todas las tareas que se le asignaron. Python, el Polit茅cnico de San Petersburgo y la regla del metro. No, el metro apesta. Esto es personal (11 a帽os de trabajo) y merece un art铆culo separado, pero no ahora.


Un poco sobre las reglas para realizar cambios en la configuraci贸n de la infraestructura en mi ubicaci贸n actual. Utilizamos Puppet, Gitlab y el principio de Infraestructura como C贸digo, para que:


  • No hay cambios manuales a trav茅s de SSH modificando manualmente ning煤n archivo en m谩quinas virtuales. Durante tres a帽os de trabajo, recib铆 un sombrero por esto muchas veces, el 煤ltimo hace una semana y no creo que fuera la 煤ltima vez. Bueno, de hecho, arregle una l铆nea en la configuraci贸n, reinicie el servicio y vea si el problema se ha resuelto: 10 segundos. Cree una nueva sucursal en Gitlab, empuje los cambios, espere a que r10k funcione en Puppetmaster, ejecute Puppet --environment = mybranch y espere un par de minutos m谩s hasta que todo esto funcione: 5 minutos como m铆nimo.
  • Cualquier cambio se realiza creando una Solicitud de fusi贸n en Gitlab y debe obtener la aprobaci贸n de al menos un miembro del equipo. Los cambios importantes en el liderazgo del equipo requieren dos o tres aprobaciones.
  • Todos los cambios son textuales de una forma u otra (dado que los manifiestos de Puppet, los scripts y los datos de Hiera son texto), los archivos binarios est谩n altamente desaconsejados y se necesitan buenas razones para aprobar dichos archivos.

Entonces, las opciones que mir茅 son:


  • Munin: si hay m谩s de 10 servidores en la infraestructura, la administraci贸n se convierte en un infierno (a partir de este art铆culo . No ten铆a muchas ganas de comprobar esto, as铆 que cre铆 en mi palabra).
  • Zabbix: ha estado observando durante mucho tiempo, de regreso en Rusia, pero luego fue redundante para mis tareas. Aqu铆, tuvo que descartarse debido al uso de Puppet como administrador de configuraci贸n y Gitlab como sistema de control de versiones. En ese momento, seg煤n tengo entendido, Zabbix almacena la configuraci贸n completa en una base de datos y, por lo tanto, no estaba claro c贸mo administrar la configuraci贸n en las condiciones actuales y c贸mo rastrear los cambios.
  • Prometheus es a lo que llegaremos al final, a juzgar por el estado de 谩nimo en el departamento, pero en ese momento no pude dominarlo y no pude demostrar una muestra realmente funcional (Prueba de concepto), as铆 que tuve que rechazarlo.
  • Hab铆a varias otras opciones que requer铆an un redise帽o completo del sistema, o estaban en su infancia / abandonadas y por la misma raz贸n fueron rechazadas.

Al final, me decid铆 por Icinga2 por tres razones:


1 - compatibilidad con Nrpe (un servicio de cliente que ejecuta verificaciones de comandos desde Nagios). Esto era muy importante, porque en ese momento ten铆amos 135 m谩quinas virtuales (ahora hay 165 de ellas en 2019) con un mont贸n de servicios / cheques escritos por s铆 mismos y rehacer todo esto ser铆a una hemorroide terrible.
2: todos los archivos de configuraci贸n son texto, lo que facilita editar este asunto, crear solicitudes de fusi贸n con la capacidad de ver lo que se ha agregado o eliminado.
3 es un proyecto OpenSource animado y en crecimiento. Somos muy aficionados a OpenSource y hacemos una contribuci贸n viable al crear solicitudes de extracci贸n y problemas para resolver problemas.


Entonces vamos, Icinga2.


Lo primero que tuve que enfrentar fue la inercia de mis colegas. Todos est谩n acostumbrados a Nagios / Najios (aunque incluso aqu铆 no pudieron comprometerse sobre c贸mo pronunciar esto) y la interfaz CheckMK. La interfaz de icinga se ve completamente diferente (era un punto negativo), pero es posible configurar de manera flexible lo que necesita ver con filtros literalmente por cualquier par谩metro (fue una ventaja, pero luch茅 por ello notablemente).


Filtros

Estime la proporci贸n del tama帽o de la barra de desplazamiento con respecto al tama帽o del campo de desplazamiento.


El segundo: todos est谩n acostumbrados a ver toda la infraestructura en un monitor, porque CheckMk le permite trabajar con varios hosts Nagios, pero Icinga no sab铆a c贸mo hacerlo (de hecho, lo hizo, pero m谩s sobre eso a continuaci贸n). Una alternativa era una cosa llamada Thruk, pero su dise帽o caus贸 v贸mitos para todos los miembros del equipo, excepto uno, el que lo propuso (no yo).


Thruk Firebox - Decisi贸n un谩nime del equipo

Despu茅s de un par de d铆as de tormenta de ideas, propuse la idea del monitoreo de cl煤ster, cuando hay un host maestro en la zona de producci贸n y dos subordinados, uno en desarrollo / prueba y un host externo ubicado en otro proveedor para monitorear nuestros servicios desde el punto de vista de un cliente o un extra帽o. observador Esta configuraci贸n me permiti贸 ver todos los problemas en una interfaz basada en la web y funcion贸 para m铆, pero Puppet ... El problema con Puppet era que el host maestro ahora ten铆a que saber sobre todos los hosts y servicios / controles en el sistema y ten铆a que distribuirlos entre zonas. (dev-test, staging-prod, ext), pero enviar los cambios a trav茅s de la API de Icinga lleva un par de segundos, pero compilar el directorio Puppet de todos los servicios para todos los hosts lleva un par de minutos. Todav铆a me culpan, aunque ya he explicado varias veces c贸mo funciona todo y por qu茅 todo lleva tanto tiempo.


Tercero, un mont贸n de copos de nieve (copos de nieve), cosas que quedan fuera del sistema general, porque tienen algo especial, por lo que las reglas generales no se aplican a ellos. Fue decidido por un ataque frontal: si hay una alarma, pero de hecho todo est谩 en orden, entonces aqu铆 debe profundizar y comprender por qu茅 me alerta, aunque no deber铆a. O viceversa: por qu茅 Nagios est谩 en p谩nico, pero Icinga no.


Cuarto: Nagios trabaj贸 aqu铆 para m铆 durante tres a帽os e inicialmente hab铆a m谩s confianza en 茅l que en mi novedoso sistema inconformista, por lo que cada vez que Icinga generaba p谩nico, nadie hac铆a nada hasta que Nagios se entusiasmaba con el mismo tema. Pero muy raramente, Icinga emiti贸 alarmas reales antes que Nagios, y considero que esto es una jamba seria, que analizar茅 en la secci贸n "Conclusiones".


Como resultado, la puesta en marcha se retras贸 m谩s de 5 meses (planeado el 28 de junio de 2018, de hecho, el 3 de diciembre de 2018), principalmente debido a la "verificaci贸n de paridad", esa basura cuando hay varios servicios en Nagios de los que nadie est谩 hablando No he escuchado nada en los 煤ltimos a帽os, pero AHORA emitieron cr铆ticas sin raz贸n y tuve que explicar por qu茅 no estaban en mi panel y tuve que agregarlos a Icinga para que "la verificaci贸n de paridad est茅 completa" (Todos los servicios / verificaciones en Nagios corresponden a servicios / controles en Icinga)


Implementaci贸n
El primero es la guerra de C贸digo vs Datos, como el estilo Puppet. Todos los datos, aqu铆 todo en general, deben estar en Hiera y nada m谩s. Todo el c贸digo est谩 en archivos .pp. Variables, abstracciones, funciones: todo va en pp.
Como resultado, tenemos un mont贸n de m谩quinas virtuales (165 en el momento de la escritura) y 68 aplicaciones web que necesitan ser monitoreadas para verificar el estado y la validez de los certificados SSL. Pero debido a las hemorroides hist贸ricas, la informaci贸n para monitorear aplicaciones se toma de un repositorio de gitlab separado y el formato de datos no ha cambiado desde Puppet 3, lo que crea dificultades de configuraci贸n adicionales.


C贸digo de marionetas para aplicaciones, tenga cuidado
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 } } } } } } } } 

El c贸digo de configuraci贸n de host y servicio tambi茅n se ve horrible:


monitoreo / 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', } } 

Todav铆a estoy trabajando en este fideo y mejor谩ndolo siempre que sea posible. Sin embargo, fue este c贸digo el que hizo posible usar una sintaxis simple y clara en Hiera:


Datos
 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' 

Todas las verificaciones se dividen en grupos, cada grupo tiene configuraciones predeterminadas como d贸nde y con qu茅 frecuencia ejecutar estas verificaciones, qu茅 notificaciones enviar y a qui茅n.


En cada verificaci贸n, puede anular cualquier opci贸n, y todo esto finalmente se suma a la configuraci贸n predeterminada de todas las verificaciones en su conjunto. Por lo tanto, estos fideos se escriben en config.pp: hay una fusi贸n de todas las configuraciones predeterminadas con las configuraciones de los grupos y luego con cada verificaci贸n individual.


Adem谩s, un cambio muy importante fue la capacidad de usar funciones en la configuraci贸n, por ejemplo, la funci贸n de cambiar el puerto, la direcci贸n y la URL para verificar 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 

Esto significa que, si hay una variable http_port en la definici贸n de host, 煤sela , de lo contrario 443. Por ejemplo, la interfaz web jabber se bloquea en 9090 y Unifi en 7443.
http_vhost significa ignorar DNS y tomar esta direcci贸n.
Si se especifica uri en el host, contin煤e, de lo contrario tome "/".


Una historia divertida sali贸 con http_ssl: esta infecci贸n no quer铆a desconectarse a pedido. Est煤pidamente me top茅 con esta l铆nea durante mucho tiempo, hasta que me di cuenta de que hab铆a una variable en la definici贸n del host:


 http_ssl: false 

Sustituye en expresi贸n


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

como falso y al final resulta


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

es decir, la verificaci贸n SSL siempre est谩 activa. Se decidi贸 reemplazando la sintaxis:


 http_ssl: no 

Conclusiones :


Pros:


  • Ahora tenemos un sistema de monitoreo, y no dos, como fue en los 煤ltimos 7-8 meses, o uno, obsoleto y vulnerable.
  • La estructura de datos de los hosts / servicios (verificaciones) ahora es (en mi opini贸n) mucho m谩s legible y comprensible. Para otros, esto no era tan obvio, as铆 que tuve que cortar un par de p谩ginas en el wiki local para explicar c贸mo funciona y d贸nde editarlo.
  • Es posible configurar comprobaciones de manera flexible utilizando variables y funciones, por ejemplo, para verificar http_regexp, el patr贸n deseado, el c贸digo de retorno, la url y el puerto se pueden establecer en la configuraci贸n del host.
  • Hay varios paneles, para cada uno de los cuales puede definir su propia lista de alarmas mostradas y administrar todo esto a trav茅s de Puppet y solicitudes de fusi贸n.

Contras:


  • Inercia de los miembros del equipo: Nagios trabaj贸, trabaj贸 y trabaj贸, y este Isinga constantemente molesta y ralentiza. 驴Y c贸mo puedo ver la historia? Y, maldici贸n, no se actualiza ... (El verdadero problema es que el historial de alarmas no se actualiza autom谩ticamente, solo por F5)
  • La inercia del sistema, cuando hago clic en "verificar ahora" en la interfaz web, el resultado de la ejecuci贸n depende del clima en Marte, especialmente en servicios complejos que tardan decenas de segundos en completarse. Un resultado similar es algo normal.
  • En general, seg煤n las estad铆sticas semestrales de los dos sistemas trabajando uno al lado del otro, Nagios siempre trabaj贸 m谩s r谩pido que Icinga y realmente me molest贸. Me parece que hay algo enga帽ado con temporizadores y un control de cinco minutos sobre el hecho cada 5:30 o algo as铆.
  • Si reinicia el servicio en cualquier momento (systemctl restart icinga2): todas las comprobaciones que estaban en curso en ese momento activar谩n una alarma cr铆tica <terminada por la se帽al 15> en la pantalla y desde el lado parecer谩 que todo ha ca铆do ( error confirmado )

Pero en general, funciona.

Source: https://habr.com/ru/post/444060/


All Articles