Përshëndetje të gjithëve.
Unë jam një administrator linux, transferuar nga Rusia në Australi me një vizë profesionale të pavarur në vitin 2015, por ky artikull nuk do të jetë për mënyrën se si një derra mund të blejë një traktor. Ka mjaft artikuj të tillë (ndonjëherë, nëse ka interes, do të shkruaj edhe për këtë), kështu që do të doja të flisja për mënyrën se si, në punën time në Australi si inxhiner linux-ops, isha iniciatori i migrimit nga një sistem monitorimi në një tjetër. Konkretisht - Nagios => Icinga2.
Artikulli është pjesërisht teknik dhe pjesërisht - mbi ndërveprimin me njerëzit dhe problemet e lidhura me diferencat kulturore dhe metodat e punës.
Fatkeqësisht, tiku «code» nuk ndriçon kodin Puppet dhe yaml, kështu që duhet të përdor «plaintext».
Asgjë nuk parashikonte ndodhi mëngjesin e 21 dhjetorit 2016. Unë, ashtu si zakonisht, isha duke lexuar Habr si një anonim i pa regjistruar në dy orët e para të ditës së punës, duke e pirë kafen dhe u ndala te .
Duke qenë se në kompaninë time përdorej Nagios, nuk mendova gjatë dhe krijova një tiket në Redmine dhe shpërndaova lidhjen në bisedën e përbashkët, pasi e konsiderova të rëndësishme. Iniciativa është ndëshkuese edhe në Australi, kështu që inxhinieri kryesor e ngarkoi këtë problem mbi mua, duke qenë se unë e zbulova atë.
Skena nga Redmine
Në departamentin tonë, para se të shprehim mendimin tonë, është zakon t'u ofrojmë të paktën një alternativë, edhe nëse zgjedhja është e dukshme, prandaj fillova me googlimin e cilave sisteme monitorimi janë të aktualizuara aktualisht, pasi në vendin tim të fundit të punës në Rusi kisha sistemin tim të shkruar vetë, shumë primitiv, por megjithatë plotësisht funksional dhe duke përmbushur të gjitha detyrat që i ishin ngarkuar. Python, Politehnika e Shën Pjetërburgut dhe metroja janë të shkëlqyera. Jo, metroja është e keqe. Kjo është personale (11 vjet punë) dhe meriton një artikull të veçantë, por jo tani.
Pak rreth rregullave të ndryshimeve në konfigurimin e infrastrukturës në vendin tim të tanishëm të punës. Ne përdorim Puppet, Gitlab dhe parimin e Infrastrukturës si Kod, kështu që:
- Asnjë ndryshim manual përmes SSH duke ndryshuar dorazi ndonjë skedar në makinën virtuale. Gjatë tre viteve të punës kam marrë ndëshkime për këtë shumë herë, e fundit - një javë më parë dhe nuk mendoj se ishte hera e fundit. Mirë, në të vërtetë - të rregullosh një rresht në konfigurim, të rinisësh shërbimin dhe të shohësh nëse u zgjidh problemi - 10 sekonda. Të krijosh një degë të re në Gitlab, të shtosh ndryshimet, të presësh që r10k të funksionojë në Puppetmaster, të nisim Puppet -environment=mybranch dhe disa minuta të tjera të presësh derisa gjithçka të funksionojë - të paktën 5 minuta.
- Të gjitha ndryshimet bëhen përmes krijimit të një Merge Request në Gitlab dhe nevojitet miratimi i paktën nga një anëtar i ekipit. Ndryshime të mëdha sipas vendimit të liderit të ekipit kërkojnë dy ose tre miratime.
- Të gjitha ndryshimet janë në formë teksti (pasi manifestat e Puppet, skriptet dhe të dhënat Hiera janë tekste), skedarët binarë janë shumë të papëlqyer dhe për miratimin e këtyre skedarëve kërkohen arsye të forta.
Pra, opsionet që shqyrtova ishin:
- Munin - nëse infrastruktura ka më shumë se 10 servera, administrimi shndërrohet në një çmenduri (nga . Nuk kisha dëshirë të vepronte këtë, prandaj e pranuam si fjalë).
- Zabbix - kam pasur për një kohë në vëmendje, edhe në Rusi, por atëherë ishte i tepruar për nevojat e mia. Këtu - duhej ta përjashtoja për shkak të përdorimit të Puppet si menaxher konfigurimi dhe Gitlab si sistem kontrolli versioni. Në atë kohë, sa kuptova - Zabbix ruan të gjitha konfigurimet në një bazë të dhënash, për të cilën nuk ishte e qartë si të menaxhohej konfigurimi në kushtet aktuale dhe si të përndiqeshin ndryshimet.
- Prometheus - ajo në të cilën ne do të arrijmë në fund, sipas humorit në departament, por në atë kohë nuk isha në gjendje ta tregoja një mostër funksionale (Prova e Konceptit), kështu që duhej të heqja dorë.
- Ishte edhe disa opsione të tjera, që kërkonin një rivlerësim të plotë të sistemit, ose ishin në faza fillestare / të braktisura dhe për këtë arsye u përjashtuan.
Përfundimisht, u ndala në Icinga2 për tri arsye:
1 - kompatibilitet me Nrpe (shërbimi klient që ekzekuton kontrollin me komandat nga Nagios). Kjo ishte shumë e rëndësishme, sepse në atë kohë kishim 135 (tani në 2019, janë 165) makina virtuale me një shumëllojshmëri shërbimesh/kontrollesh të shkruara vetë dhe riparimi i të gjitha këtyre do të ishte një dhimbje e madhe.
2 - të gjitha skedarët e konfigurimit janë tekst, gjë që lejon editimin e lehtë të kësaj, krijimin e kërkesave për bashkimin me mundësinë e shikimit çfarë është shtuar ose hequr.
3 - është një projekt OpenSource aktiv dhe në zhvillim. Ne e duam shumë OpenSource dhe kontribuojmë në të përmes krijimit të Kërkesave të Bashkimit dhe Problemesh për zgjidhjen e çështjeve.
Pra, le të fillojmë, Icinga2.
E para, qĂ« çfarĂ« kam hasur â inertĂ«sia e kolegĂ«ve. TĂ« gjithĂ« ishin mĂ«suar me Nagios/Nagios (ndonĂ«se kĂ«tu nuk arritĂ«m tĂ« gjenim njĂ« kompromis mbi si ta shqiptojmĂ«) dhe ndĂ«rfaqen e CheckMK. Me icinga ndĂ«rfaqja duket krejt ndryshe (kjo ishte njĂ« disavantazh), por ka mundĂ«sinĂ« pĂ«r tĂ« pĂ«rshtatur me fleksibilitet atĂ« qĂ« duhet tĂ« shikohet pĂ«rmes filtrave nĂ« çdo parametrim (kjo ishte njĂ« avantazh, por pĂ«r tĂ« luftuar pĂ«r tĂ«, kam pasur shumĂ« punĂ«).
Filtrat
Vlerësoni raportin e madhësisë së shiritit të skrollit me madhësinë e fushës për skrollim.
E dyta â tĂ« gjithĂ« ishin mĂ«suar tĂ« shihnin gjithĂ« infrastrukturĂ«n nĂ« njĂ« monitor, sepse CheckMk lejon tĂ« punosh me disa hoste Nagios, por ndĂ«rfaqja Icinga nuk e bĂ«nte kĂ«tĂ« (nĂ« fakt e bĂ«nte, por pĂ«r kĂ«tĂ« do flasim mĂ« poshtĂ«). NjĂ« alternativĂ« ishte diçka e quajtur Thruk, por dizajni i saj shkaktonte qĂ« tĂ« gjithĂ« anĂ«tarĂ«t e ekipit tĂ« pĂ«rjetonin tĂ« vjella, pĂ«rveç njĂ«rit â atij qĂ« e propozoi (nuk isha unĂ«).
FatkeqĂ«sisht Thruk â ishte njĂ« vendim unanim i ekipit.
Pas disa ditĂ«sh brainstorming-u, kam propozuar idenĂ« e monitorimit tĂ« grupeve, ku ka njĂ« host master nĂ« zonĂ«n e prodhimit dhe dy nĂ«nshĂ«rbime â njĂ« nĂ« dev/test dhe njĂ« host tĂ« jashtĂ«m, i vendosur tek njĂ« ofrues tjetĂ«r, me qĂ«llim qĂ« tĂ« monitorojmĂ« shĂ«rbimet tona nga kĂ«ndvĂ«shtrimi i klientit ose njĂ« vĂ«zhgues tĂ« jashtĂ«m. Kjo konfigurim lejonte tĂ« shihnim tĂ« gjitha problemet nĂ« njĂ« ndĂ«rfaqe web dhe funksiononte mjaft mirĂ«, por Puppet⊠Problemi me Puppet ishte se hosti master tani duhej tĂ« dinte pĂ«r tĂ« gjithĂ« hostet dhe shĂ«rbimet/kontrollimet nĂ« sistem dhe duhej t'i shpĂ«rndante ato mes zonave (dev-test, staging-prod, ext), por dĂ«rgimi i ndryshimeve pĂ«rmes Icinga API merr disa sekonda, ndĂ«rsa kompilimi i katalogut Puppet pĂ«r tĂ« gjitha shĂ«rbimet pĂ«r tĂ« gjitha hostet merr disa minuta. Kjo ende mĂ« Ă«shtĂ« vĂ«nĂ« nĂ« faj, ndonĂ«se kam shpjeguar disa herĂ« si funksionon dhe pse Ă«shtĂ« kaq e gjatĂ«.
E treta â shumĂ« SnowFlakes (flokĂ« bore) â gjĂ«ra qĂ« duken jashtĂ« sistemit tĂ« zakonshĂ«m, sepse kanĂ« diçka tĂ« veçantĂ«, prandaj rregullat e zakonshme nuk zbatohen pĂ«r to. Kjo u zgjidh pĂ«rmes njĂ« sulmi frontal â nĂ«se ka alarm, por nĂ« fakt gjithçka Ă«shtĂ« nĂ« rregull, atĂ«herĂ« kĂ«tu duhet tĂ« shqyrtojmĂ« thellĂ« dhe tĂ« kuptojmĂ« pse mĂ« alarmon, ndonĂ«se nuk duhet. Ose e kundĂ«rta â pse Nagios panikohet, ndĂ«rsa Icinga jo.
E katĂ«rt â Nagios ka punuar kĂ«tu pĂ«r tre vjet para meje dhe kishte mĂ« shumĂ« besim fillimisht sesa sistemi im modern hipster, prandaj çdo herĂ« qĂ« Icinga ngjiste panik â askush nuk bĂ«nte asgjĂ«, derisa Nagios nuk ngrihej pĂ«r tĂ« njĂ«jtin çështje. Por shumĂ« rrallĂ« Icinga jepte alarmet reale mĂ« parĂ« se Nagios dhe unĂ« e konsideroj kĂ«tĂ« njĂ« gabim tĂ« rĂ«ndĂ«sishĂ«m, pĂ«r tĂ« cilin do tĂ« flas nĂ« seksionin "PĂ«rfundimet".
NĂ« fund, futja nĂ« funksionim u zgjat mĂ« shumĂ« se 5 muaj (planifikuar pĂ«r 28 qershor 2018, nĂ« fakt â 3 dhjetor 2018), kryesisht pĂ«r shkak tĂ« "parity check" â ajo gjĂ«, ku ka disa shĂ«rbime nĂ« Nagios, pĂ«r tĂ« cilat askush nuk kishte dĂ«gjuar pĂ«r dy vitet e fundit, por PIKĂRISHT TANI ata, dreqi, dolĂ«n crit pa asnjĂ« arsye dhe unĂ« duhej tĂ« shpjegoja pse nuk ishin nĂ« panelin tim dhe duhej t'i shtoja ata nĂ« Icinga, qĂ« "parity check Ă«shtĂ« pĂ«rfunduar" (TĂ« gjitha shĂ«rbimet/kontrollimet nĂ« Nagios pĂ«rputhen me shĂ«rbimet/kontrollimet nĂ« Icinga).
Zbatimi:
E para â lufta Code vs Data, si nĂ« stilin Puppet. TĂ« gjitha tĂ« dhĂ«nat, pikĂ«risht tĂ« gjitha, duhet tĂ« jenĂ« nĂ« Hiera dhe ndryshe asnjĂ«herĂ«. I gjithĂ« kodi â nĂ« skedarĂ« .pp. Variablat, abstraksionet, funksionet â gjithçka nĂ« pp.
NĂ« fund â kemi njĂ« shumĂ«llojshmĂ«ri makinash virtuale (165 nĂ« momentin e shkruarjes sĂ« kĂ«tij artikulli) dhe 68 aplikacione web, qĂ« duhet tĂ« monitorohen pĂ«r funksionalitetin dhe pĂ«r vĂ«rtetĂ«sinĂ« e certifikateve SSL. Por pĂ«r shkak tĂ« njĂ« histori tĂ« vĂ«shtirĂ«, informacioni pĂ«r monitorimin e aplikacioneve merret nga njĂ« repozitor gitlab tĂ« veçantĂ« dhe formati i tĂ« dhĂ«nave nuk Ă«shtĂ« ndryshuar qĂ« nga Puppet 3, gjĂ« qĂ« krijon vĂ«shtirĂ«si shtesĂ« nĂ« konfigurim.
Kodi Puppet për aplikacionet, ruani sytë tuaj.
defino profile::shërbimeve::monitorimi::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,
)
{
#### APLIKACIONET ####
$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'], {} )) } # shton njoftime për grupin e paracaktuar (sistemet) + çdo grup të përcaktuar në 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') # Zgjidhni një regex për të kontrolluar
$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 | { # Ndarja e një aplikacioni sipas domenesh nëse ka dy ose më shumë
$vhost_name = {'http_vhost' => $vhost}
$vars = $data['vars'] + $vhost_name + $check_regex + $check_url
$web_ipaddress = is_array($vdata['web_ipaddress']) ? { # Bëni IP-adresën një array nëse nuk është, sepse askizzy ka 2 ip dhe është një array
true => $vdata['web_ipaddress'],
false => [$vdata['web_ipaddress']],
}
$access_from_zones = [$zone] + $apps_access_list[$data['accessible_from']] # Bashkoni zonën standarde (ku është përcaktuar aplikacioni) dhe zonat shtesë nëse ekzistojnë
$web_ipaddress.each | String $ip_address | { # Për çdo IP (nëse kemi shumë)
$suffix = length($web_ipaddress) ? { # Nëse kemi më shumë se një - shtoni IP-në si një prapashtesë në këtë emër host-i për të shmangur shumëzimin e burimeve
1 => '',
default => "_${ip_address}"
}
$octets = split($ip_address, '.')
$ip_tag = "${octets[2]}.${octets[3]}" # Përdorimi i oktetit të fundit krijon një kolizion mes nginx-vip 203.15.70.94 dhe 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}" # Nëse është një host për ext - prapashtesa bëhet '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
}
}
}
}
}
}
}
}Kodi i konfigurimit të hosteve dhe shërbimeve gjithashtu duket jashtëzakonisht i papërshtatshëm:
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',
}
}Unë vazhdoj të punoj mbi këtë kod dhe e përmirësoj sa më shumë që të jetë e mundur. Megjithatë, ky kod lejon përdorimin e një sintakse të thjeshtë dhe të qartë në Hiera:
Të dhënat
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'Të gjitha kontrollimet janë të ndara në grupe, dhe çdo grup ka cilësimet e tij të paracaktuara për vendin dhe frekuencën e ekzekutimit të këtyre kontrollimeve, si dhe për cilat njoftime të dërgohen dhe kujt.
NĂ« çdo kontrollim Ă«shtĂ« e mundur tĂ« ripĂ«rcaktohet çfarĂ«do opsioni dhe gjithçka pĂ«rfundon duke u kombinuar me cilĂ«simet e paracaktuara tĂ« tĂ« gjithĂ« kontrollimeve nĂ« tĂ«rĂ«si. Prandaj, nĂ« config.pp Ă«shtĂ« shkruar njĂ« formĂ« e tillĂ« â aty bĂ«het bashkimi i tĂ« gjitha cilĂ«simeve tĂ« paracaktuara me cilĂ«simet e grupeve dhe pastaj me çdo kontrollim individual.
Një ndryshim shumë i rëndësishëm ishte mundësia për të përdorur funksione në cilësime, për shembull, funksioni për zëvendësimin e portit, adresës dhe URL-së për kontrollimin e 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: trueKjo do tĂ« thotĂ« â nĂ«se nĂ« definicionin e hostit ka njĂ« variabĂ«l http_port â ta pĂ«rdorĂ«sh atĂ«, pĂ«rndryshe 443. PĂ«r shembull, ndĂ«rfaqja web e jabber Ă«shtĂ« mbi 9090, ndĂ«rsa Unifi Ă«shtĂ« mbi 7443.
http_vhost do të thotë të injorosh DNS dhe të marrësh këtë adresë.
NĂ«se nĂ« host Ă«shtĂ« e specifikuar uri â atĂ«herĂ« tĂ« ndiqesh atĂ«, pĂ«rndryshe tĂ« marrĂ«sh «/».
Me http_ssl pasi qĂ« ngjarjat janĂ« disi qesharake â kjo ishte njĂ« problem qĂ« nuk donte tĂ« çaktivizohej sipas kĂ«rkesĂ«s. Kaluar njĂ« kohĂ« tĂ« gjatĂ« duke u ndalur pĂ«r kĂ«tĂ« rresht, kisha kuptuar se ndryshimi nĂ« definicionin e hostit:
http_ssl: falseZëvendësohej në shprehjen
if(host.vars.http_ssl) { return false } else { return true }si false dhe në fund del
if(false) { return false } else { return true }pra kontrollimi ssl është gjithmonë aktiv. E zgjidhëm duke ndryshuar sintaksën:
http_ssl: noPërfundimet:
Avantazhet:
- Tani kemi një sistem të vetëm monitorimi, dhe jo dy, si ishte për 7-8 muajt e fundit, apo një të vjetruar dhe të brishtë.
- Struktura e të dhënave të hosteve / shërbimeve (kontrollimeve) tani (në mendimin tim) është shumë më e lexueshme dhe e kuptueshme. Për të tjerët, kjo nuk ishte aq e qartë, kështu që isha i detyruar të krijoj disa faqe në wikin lokal për të sqaruar si funksionon gjithçka dhe çfarë duhet edituar.
- Ka mundësi për konfigurimin fleksibël të kontrollimeve duke përdorur variabla dhe funksione, për shembull për kontrollimin http_regexp, modeli i kërkuar, kodi i rikthimit, URL dhe porti mund të definohen në cilësimet e hostit.
- Ka disa panele (dashboards), për secilën prej të cilëve mund të përcaktohet lista e alarmave të shfaqura dhe të menaxhohet gjithçka përmes Puppet dhe merge requests.
Disavantazhet:
- Inercia e anĂ«tarĂ«ve tĂ« ekipit â NagiOS punonte, punonte dhe punonte, ndĂ«rsa ajo e Icinga vazhdimisht dĂ«shtonte dhe ngadalĂ«sohej. Si mund ta shoh histori? Ah, tĂ« drejtat, ajo nuk pĂ«rditĂ«sohet⊠(Problemi real â historia e alarmave nuk pĂ«rditĂ«sohet automatikisht, vetĂ«m pĂ«rmes F5)
- Inercia e sistemit â kur klikoja nĂ« ndĂ«rfaqen web mbi «refresh» (kontrollo tani) â rezultati i ekzekutimit varet nga moti nĂ« Mars, sidomos pĂ«r shĂ«rbimet e ndĂ«rlikuara qĂ« kĂ«rkojnĂ« disa sekonda pĂ«r ekzekutimin. NjĂ« rezultat i tillĂ« Ă«shtĂ« diçka normale.

- Duke parë statistikat për gjashtë muaj të dy sistemeve paralelisht, NagiOS gjithmonë e realizoi më shpejt sesa Icinga dhe kjo më shqetësonte shumë. Sikur të ishte një problem me timerat dhe kontrolli çdo pesë minuta është në fakt çdo 5:30 ose diçka e tillë.
- NĂ«se e rinis shĂ«rbimin nĂ« çdo kohĂ« (systemctl restart icinga2) â tĂ« gjitha kontrollimet qĂ« ishin nĂ« proces nĂ« atĂ« moment do tĂ« raportojnĂ« alarmin kritike <terminuar nga sinjali 15> nĂ« ekran dhe nga jashtĂ« duket si tĂ« kishte rĂ«nĂ« gjithçka ().
Por nĂ« pĂ«rgjithĂ«si â po funksionon.
Burimi: habr.com

