Olá pessoal.
Eu sou o administrador do sistema linux, mudei da Rússia para a Austrália com um visto profissional independente em 2015, mas o artigo não abordará como obter um leitão para um trator. Esses artigos já são suficientes (no entanto, se houver interesse, também escreverei sobre isso), gostaria de falar sobre como, no meu trabalho na Austrália como engenheiro de operações Linux, iniciei a migração de um sistema monitorando para outro. Especificamente - Nagios => Icinga2.
O artigo é parcialmente técnico e parcialmente sobre comunicação com pessoas e problemas associados à diferença de cultura e métodos de trabalho.
Infelizmente, a tag "code" não destaca o código Puppet e yaml, então tive que usar "plaintext".
Nada deu errado na manhã de 21 de dezembro de 2016. Como sempre, li Habr com um anônimo não registrado na primeira meia hora do dia útil, absorvendo café e me deparei com este artigo .
Como o Nagios foi usado na minha empresa, sem pensar duas vezes, criei um ticket no Redmine e joguei o link no chat geral, porque achei importante. A iniciativa é punível até na Austrália, então o engenheiro-chefe pendurou esse problema em mim, desde que eu o descobri.
Em nosso departamento, antes de expressar nossa opinião, é costume propor pelo menos uma alternativa, mesmo que a escolha seja óbvia, então comecei pesquisando quais sistemas de monitoramento em geral são atualmente relevantes, já que na Rússia, no último local em que trabalhei, eu tinha meu próprio sistema de gravação pessoal, muito primitivo, mas, no entanto, bastante funcional e cumprindo todas as tarefas atribuídas a ele. Python, Politécnica de São Petersburgo e a regra do metro. Não, o metrô é péssimo. Isso é pessoal (11 anos de trabalho) e merece um artigo separado, mas não agora.
Um pouco sobre as regras para fazer alterações na configuração da infraestrutura na minha localização atual. Utilizamos o Puppet, o Gitlab e o princípio de infraestrutura como código, para que:
- Nenhuma alteração manual via SSH modificando manualmente os arquivos nas máquinas virtuais. Por três anos de trabalho, recebi um chapéu por isso muitas vezes, o último há uma semana, e acho que não foi a última vez. Bem, na verdade - corrija uma linha na configuração, reinicie o serviço e veja se o problema foi resolvido - 10 segundos. Crie uma nova ramificação no Gitlab, faça as alterações, aguarde r10k funcionar no Puppetmaster, execute Puppet --environment = mybranch e aguarde mais alguns minutos até que tudo funcione - no mínimo 5 minutos.
- Quaisquer alterações são feitas através da criação de uma solicitação de mesclagem no Gitlab e você precisa obter a aprovação de pelo menos um membro da equipe. Grandes mudanças no líder da equipe exigem duas ou três aprovações.
- Todas as alterações são textuais de uma maneira ou de outra (como os manifestos do Puppet, os scripts e os dados Hiera são textos), os binários são altamente desencorajados e são necessárias boas razões para aprová-las.
Então, as opções que eu olhei são:
- Munin - se houver mais de 10 servidores na infraestrutura, a administração se transformará em um inferno ( deste artigo . Eu não tinha muito desejo de verificar isso, então aceitei minha palavra).
- Zabbix - há muito tempo está de olho na Rússia, mas era redundante para minhas tarefas. Aqui - teve que ser descartado devido ao uso do Puppet como gerenciador de configuração e do Gitlab como sistema de controle de versão. Nesse momento, pelo que entendi, o Zabbix armazena toda a configuração em um banco de dados e, portanto, não ficou claro como gerenciar a configuração nas condições atuais e como rastrear alterações.
- Prometheus é o que chegaremos no final, a julgar pelo humor do departamento, mas naquela época eu não conseguia dominá-lo e não conseguia demonstrar uma amostra realmente funcional (Prova de Conceito), então tive que recusar.
- Havia várias outras opções que exigiam uma reformulação completa do sistema ou estavam na infância / abandonadas e, pelo mesmo motivo, foram rejeitadas.
No final, decidi pelo Icinga2 por três razões:
1 - compatibilidade com o Nrpe (um serviço de cliente que executa verificações nos comandos do Nagios). Isso foi muito importante, porque naquela época tínhamos 135 (agora são 165 em 2019) máquinas virtuais com um monte de serviços / verificações auto-escritas e refazer tudo isso seria uma terrível hemorróida.
2 - todos os arquivos de configuração são texto, o que facilita a edição deste assunto, cria solicitações de mesclagem com a capacidade de ver o que foi adicionado ou excluído.
3 é um projeto OpenSource animado e em crescimento. Nós gostamos muito do OpenSource e oferecemos uma contribuição viável, criando solicitações e problemas de pull para resolver problemas.
Então vamos lá, Icinga2.
A primeira coisa que tive que enfrentar foi a inércia dos meus colegas. Todo mundo está acostumado a Nagios / Najios (embora mesmo aqui eles não pudessem se comprometer em como pronunciar isso) e a interface CheckMK. A interface do icinga parece completamente diferente (era um sinal de menos), mas é possível configurar de maneira flexível o que você precisa ver com filtros literalmente por qualquer parâmetro (foi um plus, mas lutei por isso notavelmente).
Estime a proporção do tamanho da barra de rolagem para o tamanho do campo de rolagem.
Segundo, todo mundo está acostumado a ver toda a infraestrutura em um monitor, porque o CheckMk permite que você trabalhe com vários hosts do Nagios, mas a Icinga não sabia como fazê-lo (na verdade, sabia, mas mais sobre isso abaixo). Uma alternativa era uma coisa chamada Thruk, mas seu design causava vômito para todos os membros da equipe, exceto um - aquele que sugeriu (não eu).
Thruk Firebox - Decisão unânime da equipe Após alguns dias de uma tempestade cerebral, propus a idéia de monitoramento de cluster, quando há um host principal na zona de produção e dois subordinados - um em dev / test e um host externo localizado em outro provedor, a fim de monitorar nossos serviços do ponto de vista de um cliente ou de um outsider observador. Essa configuração me permitiu ver todos os problemas em uma interface baseada na Web e funcionou para mim, mas o Puppet ... O problema com o Puppet era que o host principal agora precisava conhecer todos os hosts e serviços / verificações no sistema e distribuí-los entre as zonas. (dev-test, staging-prod, ext), mas o envio de alterações pela API Icinga leva alguns segundos, mas a compilação do diretório Puppet de todos os serviços para todos os hosts leva alguns minutos. Isso ainda me foi atribuído, embora eu já tenha explicado várias vezes como tudo funciona e por que leva tanto tempo.
Terceiro - um monte de SnowFlakes (flocos de neve) - coisas que são eliminadas do sistema geral, porque têm algo especial, portanto as regras gerais não se aplicam a elas. Foi decidido por um ataque frontal - se houver um alarme, mas na verdade tudo estiver em ordem, então aqui você precisa se aprofundar e entender por que isso me alerta, embora não deva. Ou vice-versa - por que Nagios está em pânico, mas Icinga não.
Quarto - Nagios trabalhou aqui para mim por três anos e, inicialmente, havia mais confiança nele do que no meu novo sistema hipster, então toda vez que Icinga criava pânico - ninguém fazia nada até Nagios se empolgar com o mesmo problema. Mas muito raramente Icinga emitia alarmes reais mais cedo que Nagios, e considero isso um batente sério, que discutirei na seção "Conclusões".
Como resultado, o comissionamento foi adiado por mais de 5 meses (planejado em 28 de junho de 2018, de fato - 3 de dezembro de 2018), principalmente por causa da “verificação de paridade” - que porcaria quando existem vários serviços em Nagios dos quais ninguém está falando Não ouvi nada nos últimos dois anos, mas agora eles emitiram críticas sem motivo e eu tive que explicar por que eles não estavam no meu painel e tive que adicioná-los ao Icinga para "a verificação de paridade está concluída" (todos os serviços / verificações) em Nagios correspondem a serviços / cheques em Icinga)
Implementação:
O primeiro é a guerra de códigos versus dados, como o Puppet Style. Todos os dados, bem aqui tudo em geral, devem estar em Hiera e nada mais. Todo o código está em arquivos .pp. Variáveis, abstrações, funções - tudo sai em pp.
Como resultado, temos várias máquinas virtuais (165 no momento da redação) e 68 aplicativos da web que precisam ser monitorados quanto à integridade e validade dos certificados SSL. Porém, devido a hemorróidas históricas, as informações para monitorar aplicativos são obtidas de um repositório separado do gitlab e o formato dos dados não mudou desde o Puppet 3, o que cria dificuldades adicionais de configuração.
Código de marionete para aplicações, tome cuidadodefine 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 } } } } } } } }
O código de configuração do host e do serviço também parece horrível:
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 <<| |>> # 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', } }
Ainda estou trabalhando nesse macarrão e melhorando-o sempre que possível. No entanto, foi esse código que possibilitou o uso de sintaxe simples e clara no Hiera:
Dados 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 as verificações são divididas em grupos, cada grupo tem configurações padrão, como onde e com que freqüência executar essas verificações, quais notificações enviar e para quem.
Em cada verificação, você pode substituir qualquer opção e tudo isso acaba adicionando as configurações padrão de todas as verificações como um todo. Portanto, esse macarrão é gravado em config.pp - há uma fusão de todas as configurações padrão com as configurações dos grupos e depois com cada verificação individual.
Além disso, uma mudança muito importante foi a capacidade de usar funções nas configurações, por exemplo, a função de alterar a porta, endereço e 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
Isso significa - se houver uma variável http_port na definição de host - use-a, caso contrário 443. Por exemplo, a interface da web do jabber trava no 9090 e Unifi no 7443.
http_vhost significa ignorar o DNS e usar este endereço.
Se uri for especificado no host, siga-o, caso contrário, use "/".
Uma história engraçada foi publicada com http_ssl - essa infecção não queria se desconectar sob demanda. Estupidamente, tropecei nessa linha por um longo tempo, até que me ocorreu que havia uma variável na definição de host:
http_ssl: false
Substitui a expressão
if(host.vars.http_ssl) { return false } else { return true }
como falso e acontece
if(false) { return false } else { return true }
isto é, a verificação ssl está sempre ativa. Foi decidido substituindo a sintaxe:
http_ssl: no
Conclusões :
Prós:
- Agora, temos um sistema de monitoramento, e não dois, como nos últimos 7-8 meses, ou um, desatualizado e vulnerável.
- A estrutura de dados dos hosts / serviços (verificações) é agora (na minha opinião) muito mais legível e compreensível. Para outros, isso não era tão óbvio, então eu tive que cortar algumas páginas no wiki local para explicar como funciona e onde editá-lo.
- É possível configurar verificações de forma flexível usando variáveis e funções, por exemplo, para verificar http_regexp, o padrão desejado, código de retorno, URL e porta podem ser definidos nas configurações do host.
- Existem vários painéis, para cada um dos quais você pode definir sua própria lista de alarmes exibidos e gerenciar tudo isso através de solicitações de Puppet e mesclagem.
Contras:
- Inércia dos membros da equipe - Nagios trabalhou, trabalhou e trabalhou, e este seu Isinga constantemente falha e diminui a velocidade. E como posso ver a história? E, caramba, ele não é atualizado ... (O verdadeiro problema é que o histórico de alarmes não é atualizado automaticamente, apenas por F5)
- A inércia do sistema - quando clico em "verificar agora" na interface da web - o resultado da execução depende do clima em Marte, especialmente em serviços complexos que levam dezenas de segundos para serem concluídos. Um resultado semelhante é uma coisa normal.

- Em geral, de acordo com as estatísticas semestrais dos dois sistemas trabalhando lado a lado, o Nagios sempre trabalhava mais rápido que o Icinga e isso realmente me irritava. Parece-me que há algo enganado com temporizadores e uma verificação de cinco minutos do fato acontece a cada 5:30 ou algo assim.
- Se você reiniciar o serviço a qualquer momento (systemctl restart icinga2) - todas as verificações em andamento naquele momento acionarão um alarme crítico <terminado pelo sinal 15> na tela e, pelo lado, parecerá que tudo caiu ( erro confirmado )
Mas, em geral - funciona.