الهجرة من Nagios إلى Icinga2 في أستراليا

مرحبا بالجميع.


أنا مسؤول النظام linux ، انتقلت من روسيا إلى أستراليا بتأشيرة مهنية مستقلة في عام 2015 ، لكن المقال لن يدور حول كيفية الحصول على جرار خنزير صغير. هذه المقالات كافية بالفعل (ومع ذلك ، إذا كانت هناك مصلحة ، فسأكتب عنها أيضًا) ، لذلك أود أن أتحدث عن كيف كنت في عملي في أستراليا كمهندس نظام تشغيل لينكس ، كنت البادئ بالهجرة من نظام واحد. مراقبة لآخر. على وجه التحديد - Nagios => Icinga2.


المقال تقني جزئيًا وجزئيًا عن التواصل مع الأشخاص والمشاكل المرتبطة بالفرق في الثقافة وأساليب العمل.


لسوء الحظ ، لا تُبرز علامة "الرمز" رمز العُلوة واليميل ، لذلك اضطررت إلى استخدام "نص عادي".


لا شيء ينذر بالمرض في صباح يوم 21 ديسمبر 2016. كالمعتاد ، قرأت هبر مع مجهول الهوية غير مسجل في النصف ساعة الأولى من يوم العمل ، حيث تمتص القهوة وصادفت هذا المقال .


منذ أن تم استخدام Nagios في شركتي ، دون التفكير مرتين ، قمت بإنشاء تذكرة في Redmine وألقيت الارتباط في الدردشة العامة ، لأنني اعتقدت أن ذلك مهم. المبادرة يعاقب عليها حتى في أستراليا ، لذلك علق المهندس الرئيسي هذه المشكلة عليّ منذ أن اكتشفتها.


شاشة من Redmine

في قسمنا ، قبل وضع رأينا ، من المعتاد اقتراح بديل واحد على الأقل ، حتى لو كان الخيار واضحًا ، لذلك بدأت من خلال googling أنظمة المراقبة بشكل عام ذات الصلة حاليًا ، حيث أنني في روسيا في آخر مكان عملت فيه ، كان لدي نظام تسجيل شخصي خاص بي ، بدائية للغاية ، ولكن مع ذلك تعمل بشكل جيد وتؤدي جميع المهام الموكلة إليها. بيثون وسانت بطرسبرغ للفنون التطبيقية وحكم المترو. لا ، تمتص المترو. هذه شخصية (11 عامًا من العمل) وتستحق مقالة منفصلة ، ولكن ليس الآن.


قليلاً عن قواعد إجراء تغييرات على تكوين البنية التحتية في موقعي الحالي. نستخدم الدمى و Gitlab ومبدأ البنية التحتية كقانون ، بحيث:


  • لا توجد تغييرات يدوية عبر SSH عن طريق تعديل أي ملفات على الأجهزة الافتراضية يدويًا. لمدة ثلاث سنوات من العمل ، تلقيت قبعة لهذا مرات عديدة ، آخرها قبل أسبوع ولا أعتقد أنها كانت المرة الأخيرة. حسنًا ، في الواقع - إصلاح سطر واحد في التكوين ، أعد تشغيل الخدمة ومعرفة ما إذا كان قد تم حل المشكلة - 10 ثوانٍ. أنشئ فرعًا جديدًا في Gitlab ، وادفع التغييرات ، وانتظر r10k للعمل على Puppetmaster ، وقم بتشغيل Puppet --environment = mybranch وانتظر بضع دقائق حتى يعمل كل هذا - بحد أدنى 5 دقائق.
  • يتم إجراء أي تغييرات عن طريق إنشاء طلب دمج في Gitlab وتحتاج إلى الحصول على موافقة من عضو واحد على الأقل من أعضاء الفريق. التغييرات الرئيسية في قيادة الفريق تتطلب موافقتين أو ثلاث موافقات.
  • جميع التغييرات نصية بشكل أو بآخر (بما أن إعلانات العرائس ومخطوطات هيرا والبيانات نصية) ، فإن الثنائيات محبطة للغاية ، وهناك حاجة إلى أسباب وجيهة للموافقة عليها.

لذلك ، فإن الخيارات التي نظرت إليها هي:


  • Munin - إذا كان هناك أكثر من 10 خوادم في البنية التحتية ، تتحول الإدارة إلى جهنم (من هذه المقالة . لم أكن أرغب في التحقق من ذلك ، لذا أخذت كلامي لذلك).
  • Zabbix - منذ فترة طويلة تتطلع ، مرة أخرى في روسيا ، ولكن بعد ذلك كان لا لزوم لها لمهامي. هنا - كان لا بد من إسقاطه بسبب استخدام Puppet كمدير للتكوين و Gitlab كنظام للتحكم في الإصدار. في تلك اللحظة ، كما أفهمها ، يخزن Zabbix التكوين بالكامل في قاعدة بيانات ، وبالتالي لم يكن من الواضح كيفية إدارة التكوين في الظروف الحالية وكيفية تتبع التغييرات.
  • بروميثيوس هو ما سنأتي إليه في النهاية ، إذا حكمنا من خلال الحالة المزاجية في القسم ، لكن في ذلك الوقت لم أتمكن من إتقانه ولم أستطع تقديم نموذج عملي (إثبات الفكرة) ، لذلك اضطررت إلى الرفض.
  • كانت هناك عدة خيارات أخرى تتطلب إما إعادة تصميم كاملة للنظام ، أو كانت في مهدها / تم التخلي عنها وتم رفض السبب نفسه.

في النهاية ، استقرت على Icinga2 لثلاثة أسباب:


1 - التوافق مع Nrpe (خدمة العملاء التي تدير عمليات التحقق من الأوامر من Nagios). كان هذا مهمًا للغاية ، لأنه في ذلك الوقت كان لدينا 135 جهازًا (يوجد الآن 165 جهازًا في عام 2019) مع مجموعة من الخدمات / الشيكات المكتوبة ذاتيا وإعادة كل هذا سيكون البواسير الرهيبة.
2 - جميع ملفات التكوين هي نص ، مما يجعل من السهل تحرير هذه المسألة ، وإنشاء طلبات دمج مع القدرة على رؤية ما تمت إضافته أو حذفه.
3 هو مشروع مفتوح المصدر حيوي ومتنامٍ. نحن مغرمون للغاية من OpenSource ونقدم مساهمة مجدية له من خلال إنشاء طلبات السحب والقضايا لحل المشاكل.


لذلك دعونا نذهب ، Icinga2.


أول شيء كان علي مواجهته هو القصور الذاتي لزملائي. لقد اعتاد الجميع على Nagios / Najios (رغم أنه حتى هنا لم يتمكنوا من حل وسط حول كيفية نطق هذا) وواجهة CheckMK. في icinga ، تبدو الواجهة مختلفة تمامًا (كانت ناقصًا) ، لكن من الممكن تكوين ما تحتاجه بمرونة لتتمكن من رؤيته باستخدام المرشحات حرفيًا بواسطة أي معلمة (كانت علامة زائد ، لكني ناضلت من أجلها بشكل خاص).


مرشحات

قم بتقدير نسبة حجم شريط التمرير إلى حجم حقل التمرير.


ثانياً ، اعتاد الجميع على رؤية البنية التحتية بأكملها على شاشة واحدة ، لأن CheckMk يسمح لك بالعمل مع العديد من مضيفي Nagios ، لكن إيسينجا لم تكن تعرف كيف (في الواقع ، ولكن أكثر حول ذلك أدناه). كان هناك بديل يسمى Thruk ، لكن تصميمه تسبب في التقيؤ لجميع أعضاء الفريق ، باستثناء واحد - الشخص الذي اقترحه (وليس أنا).


Thruk Firebox - قرار فريق بالإجماع

بعد يومين من العاصفة الدماغية ، اقترحت فكرة مراقبة الكتلة ، عندما يكون هناك مضيف رئيسي واحد في منطقة الإنتاج واثنين من المرؤوسين - واحد في dev / test ومضيف خارجي واحد موجود في مزود آخر من أجل مراقبة خدماتنا من وجهة نظر العميل أو من الخارج مراقب. سمح لي هذا التكوين برؤية كل المشاكل في واجهة واحدة على شبكة الإنترنت وعملت بشكل جيد ، لكن Puppet ... كانت المشكلة مع Puppet هي أن المضيف الرئيسي كان عليه الآن معرفة جميع المضيفين والخدمات / الاختبارات في النظام واضطر إلى توزيعها بين المناطق (dev-test ، staging-prod ، ext) ، ولكن إرسال التغييرات من خلال Icinga API يستغرق بضع ثوانٍ ، لكن تجميع دليل Puppet لجميع الخدمات لجميع المضيفين يستغرق بضع دقائق. هذا لا يزال يلومني ، رغم أنني شرحت بالفعل عدة مرات كيف يعمل كل شيء ولماذا يستغرق كل هذا الوقت الطويل.


ثالثًا - مجموعة من SnowFlakes (رقاقات الثلج) - الأشياء التي تم إخراجها من النظام العام ، نظرًا لوجود شيء خاص بها ، وبالتالي فإن القواعد العامة لا تنطبق عليها. لقد تقرر ذلك من خلال هجوم أمامي - إذا كان هناك إنذار ، ولكن في الحقيقة كل شيء على ما يرام ، فأنت هنا بحاجة إلى حفر أعمق وفهم لماذا ينبهني ، على الرغم من أنه لا ينبغي. أو العكس - لماذا يشعر Nagios بالذعر ، لكن Icinga ليس كذلك.


رابعًا - عمل ناجيوس هنا لمدة ثلاث سنوات ، وفي البداية كان هناك ثقة أكبر منه في نظام محب جديد ، لذلك في كل مرة أثار إيسينغا حالة من الذعر - لم يفعل أحد أي شيء حتى أصبح ناغيوس متحمسًا لنفس المشكلة. ولكن نادرًا ما أصدرت Icinga إنذارات حقيقية في وقت سابق من Nagios ، وأعتقد أن هذا دعامة خطيرة ، والتي سأناقشها في قسم "الاستنتاجات".


ونتيجة لذلك ، تأخر التشغيل لأكثر من 5 أشهر (تم التخطيط له في 28 يونيو 2018 ، في الواقع - 3 ديسمبر 2018) ، ويعزى ذلك بشكل رئيسي إلى "التحقق من التكافؤ" - هذا هراء عندما توجد عدة خدمات في Nagios لا أحد يتحدث عنها لم أسمع أي شيء على مدار العامين الماضيين ، ولكن الآن أصدروا لعنة نقدية بدون سبب واضطررت إلى توضيح سبب عدم وجودهم في لوحة بلدي واضطررت لإضافتها إلى Icinga إلى "تكافؤ التحقق" (جميع الخدمات / الشيكات كاملة) في Nagios تتوافق مع الخدمات / الشيكات في Icinga)


التنفيذ:
الأول هو الحرب على الكود مقابل البيانات ، مثل Puppet Style. جميع البيانات ، هنا كل شيء بشكل عام ، يجب أن تكون في هييرا ولا شيء غير ذلك. كل رمز في ملفات .pp. المتغيرات ، التجريد ، الدوال - كل شيء يسير بشكل pp.
نتيجة لذلك ، لدينا مجموعة من الأجهزة الافتراضية (165 وقت كتابة هذا التقرير) و 68 تطبيقًا على الويب يحتاجون إلى مراقبتها من أجل صحة وصلاحية شهادات طبقة المقابس الآمنة. ولكن بسبب البواسير التاريخية ، يتم الحصول على معلومات تطبيقات المراقبة من مستودع gitlab منفصل ولم يتغير تنسيق البيانات منذ Puppet 3 ، مما يخلق صعوبات تكوين إضافية.


كود العرائس للتطبيقات ، احذر
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 } } } } } } } } 

يبدو أيضًا رمز تهيئة المضيف والخدمة:


مراقبة / 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', } } 

أنا لا أزال أعمل على هذه المعكرونة وتحسينها كلما أمكن ذلك. ومع ذلك ، كان هذا الكود هو الذي جعل من الممكن استخدام بناء جملة بسيط وواضح في هييرا:


البيانات
 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' 

تنقسم جميع عمليات التحقق إلى مجموعات ، ولكل مجموعة إعدادات افتراضية مثل مكان وعدد مرات تشغيل هذه الشيكات ، والإشعارات المرسلة وإرسالها إلى من.


في كل عملية تدقيق ، يمكنك تجاوز أي خيار ، ويضيف كل هذا في النهاية إلى الإعدادات الافتراضية لجميع عمليات التحقق ككل. لذلك ، تتم كتابة مثل هذه المعكرونة في config.pp - هناك دمج لجميع الإعدادات الافتراضية مع إعدادات المجموعات ثم مع كل تحقق فردي.


كذلك ، كان التغيير المهم للغاية هو القدرة على استخدام الوظائف في الإعدادات ، على سبيل المثال ، وظيفة تغيير المنفذ والعنوان وعنوان url للتحقق من 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 

هذا يعني - إذا كان هناك متغير http_port في تعريف المضيف - استخدامه ، وإلا 443. على سبيل المثال ، يتم تعليق واجهة الويب jabber على 9090 ، و Unifi على 7443.
http_vhost يعني تجاهل DNS واتخاذ هذا العنوان.
إذا تم تحديد uri في المضيف ، فاستمر في ذلك ، وإلا خذ "/".


ظهرت قصة مضحكة مع http_ssl - هذه الإصابة لم ترغب في قطع الاتصال عند الطلب. لقد تعثرت بغباء على هذا الخط لفترة طويلة ، حتى اتضح لي أنه كان هناك متغير في تعريف المضيف:


 http_ssl: false 

بدائل في التعبير


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

كما خطأ وفي النهاية اتضح


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

وهذا يعني أن فحص SSL نشط ​​دائمًا. وقد تقرر عن طريق استبدال بناء الجملة:


 http_ssl: no 

الاستنتاجات :


الايجابيات:


  • لدينا الآن نظام مراقبة واحد ، وليس نظامان ، كما كان الحال في آخر 7-8 أشهر ، أو نظام واحد عفا عليه الزمن وضعيف.
  • أصبحت بنية بيانات المضيفين / الخدمات (الشيكات) الآن (في رأيي) أكثر قابلية للقراءة وفهمًا. بالنسبة للآخرين ، لم يكن هذا واضحًا ، لذا اضطررت إلى قص صفحتين على الويكي المحلي لشرح كيفية عمله ومكان تحريره.
  • من الممكن تكوين الشيكات بمرونة باستخدام المتغيرات والوظائف ، على سبيل المثال ، للتحقق من http_regexp ، يمكن تعيين النمط المرغوب ، رمز الإرجاع ، عنوان url والمنفذ في إعدادات المضيف.
  • هناك العديد من لوحات المعلومات ، لكل منها يمكنك تحديد القائمة الخاصة بك من أجهزة الإنذار المعروضة وإدارة كل هذا من خلال Puppet ودمج الطلبات.

سلبيات:


  • القصور الذاتي لأعضاء الفريق - عملت Nagios وعملت وعملت ، وهذا Isinga الخاص بك الخلل باستمرار ويبطئ. وكيف يمكنني رؤية القصة؟ ولعنه ، لم يتم تحديثه ... (المشكلة الحقيقية هي أن سجل الإنذار لا يتم تحديثه تلقائيًا ، فقط بواسطة F5)
  • خمول النظام - عندما أقوم بالنقر فوق "تحقق الآن" في واجهة الويب - تعتمد نتيجة التنفيذ على حالة الطقس على المريخ ، لا سيما على الخدمات المعقدة التي تستغرق عشرات الثواني. نتيجة مماثلة هي شيء طبيعي.
  • بشكل عام ، وفقًا للإحصائيات نصف السنوية لنظامين يعملان جنبًا إلى جنب ، كان Nagios يعمل دائمًا بشكل أسرع من Icinga وقد أزعجني حقًا. يبدو لي أن هناك شيئًا مخدوعًا بأجهزة ضبط الوقت وأن الفحص لمدة خمس دقائق للحقيقة يذهب كل 5:30 أو شيء من هذا القبيل.
  • إذا قمت بإعادة تشغيل الخدمة في أي وقت (systemctl restart icinga2) - فإن جميع عمليات الفحص التي كانت قيد التنفيذ في ذلك الوقت ستطلق إنذارًا هامًا <إنهاء بالإشارة 15> على الشاشة ومن الجانب ستبدو كما لو أن كل شيء قد انخفض ( خطأ أكيد )

ولكن بشكل عام - كان يعمل.

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


All Articles