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