Përshëndetje të gjithëve.
UnĂ« jam administrator i sistemit Linux, kam bĂ«rĂ« trasferimin nga Rusia nĂ« Australi me njĂ« vizĂ« profesionale tĂ« pavarur nĂ« vitin 2015, por ky artikull nuk do tĂ« flasĂ« pĂ«r si tĂ« vendosĂ«sh njĂ« traktor pĂ«r njĂ« derr. Ka mjaft artikuj tĂ« tillĂ« (nĂ«se ka interes, mund tĂ« shkruaj edhe pĂ«r kĂ«tĂ«), kĂ«shtu qĂ« do tĂ« doja tĂ« flisja pĂ«r atĂ« se si nĂ« punĂ«n time nĂ« Australi si inxhinier linux-ops kam qenĂ« iniciatori i migrimit nga njĂ« sistem monitorimi nĂ« njĂ« tjetĂ«r. Konkretesht â Nagios => Icinga2.
Artikulli Ă«shtĂ« pjesĂ«risht teknik dhe pjesĂ«risht â pĂ«r komunikimin me njerĂ«zit dhe problemet qĂ« lidhen me ndryshimin e kulturĂ«s dhe metodave tĂ« punĂ«s.
Fatkeqësisht, etiketa «code» nuk ndriçon kodin e Puppet dhe yaml, kështu që duhej të përdorja «plaintext».
Asgjë nuk e parashikonte të keqen në mëngjesin e 21 dhjetorit 2016. Unë, si zakonisht, po lexoja Habr si një anonim i pa regjistruar gjatë dy orëve të para të ditës së punës, duke pirë kafe dhe u ndesha me .
Duke qenë se në kompaninë time përdorej Nagios, pa menduar shumë, krijova një biletë në Redmine dhe dërgova lidhjen në bisedën e përgjithshme, duke e konsideruar këtë të rëndësishme. Iniciativa është e dënueshme edhe në Australi, kështu që inxhinieri kryesor e ngarkoi këtë problem mbi mua, pasi e kisha zbuluar.
Ekran nga Redmine
NĂ« departamentin tonĂ«, para se tĂ« paraqesĂ«sh mendimin tĂ«nd Ă«shtĂ« e zakonshme tĂ« ofrosh tĂ« paktĂ«n njĂ« alternativĂ«, edhe nĂ«se zgjedhja Ă«shtĂ« e qartĂ«, kĂ«shtu qĂ« fillova tĂ« kĂ«rkoja nĂ« Google se cilat sistemi monitorimi ishin aktualisht nĂ« treg, pasi nĂ« RusinĂ« nĂ« vendin tim tĂ« fundit tĂ« punĂ«s kisha njĂ« sistem tĂ« vetĂ«-shkruar, shumĂ« primitiv, por megjithatĂ« plotĂ«sisht funksional dhe duke pĂ«rmbushur tĂ« gjitha detyrat e caktuara. Python, Politekniku i ShĂ«n Petersburgut dhe metro janĂ« tĂ« shkĂ«lqyera. Jo, metro â Ă«shtĂ« e tmerrshme. Kjo Ă«shtĂ« personale (11 vjet punĂ«) dhe meriton njĂ« artikull tĂ« veçantĂ«, por jo tani.
Pak për rregullat e ndryshimeve në konfigurimin e infrastrukturës në vendin tim aktual të punës. Ne përdorim Puppet, Gitlab dhe parimin Infrastructure as Code, kështu që:
- Nuk ka ndryshime manuale pĂ«rmes SSH duke modifikuar ndonjĂ« skedĂ« nĂ« makinat virtuale. GjatĂ« tre viteve tĂ« punĂ«s kam marrĂ« shumĂ« herĂ« kritikĂ« pĂ«r kĂ«tĂ«, herĂ«n e fundit njĂ« javĂ« mĂ« parĂ« dhe nuk mendoj se do tĂ« jetĂ« hera e fundit. E vĂ«rteta Ă«shtĂ« â tĂ« korrigjosh njĂ« rresht nĂ« konfigurim, tĂ« rinisĂ«sh shĂ«rbimin dhe tĂ« shikosh nĂ«se problemi Ă«shtĂ« zgjidhur â 10 sekonda. TĂ« krijosh njĂ« degĂ« tĂ« re nĂ« Gitlab, tĂ« bĂ«sh push, tĂ« presĂ«sh derisa r10k tĂ« funksioni nĂ« Puppetmaster, tĂ« nisĂ«sh Puppet âenvironment=mybranch dhe tĂ« presĂ«sh disa minuta derisa tĂ« pĂ«rfundojĂ« â minimumi 5 minuta.
- Ădo ndryshim bĂ«het duke krijuar njĂ« Merge Request nĂ« Gitlab dhe kĂ«rkohet miratimi nga tĂ« paktĂ«n njĂ« anĂ«tar tĂ« ekipit. Ndryshimet serioze sipas vendimeve tĂ« liderit tĂ« ekipit kĂ«rkojnĂ« dy ose tre miratime.
- Të gjitha ndryshimet në një mënyrë ose tjetër janë tekstuale (pasi manifestet e Puppet, skriptet dhe të dhënat Hiera janë tekst), skedarët binary janë tepër të papërshtatshëm dhe për miratimin e atyre skedarëve nevojiten arsye të forta.
Pra, opsionet që kam shqyrtuar:
- Munin â nĂ«se infrastruktura ka mĂ« shumĂ« se 10 serverĂ«, administrimi kthehet nĂ« njĂ« ferr (nga . Nuk kisha dĂ«shirĂ« tĂ« veçantĂ« ta kontrolloja kĂ«tĂ«, kĂ«shtu qĂ« besoja nĂ« fjalĂ«n e tjetrit).
- Zabbix â e kam vĂ«zhguar prej kohĂ«sh, qĂ« nga koha nĂ« Rusi, por atĂ«herĂ« ishte tepĂ«r i tepĂ«rt pĂ«r detyrat e mia. KĂ«tu â u detyrova ta braktis pĂ«r shkak tĂ« pĂ«rdorimit tĂ« Puppet si menaxher konfigurimi dhe Gitlab si sistem kontrolli versioni. NĂ« atĂ« moment, aq sa kam kuptuar â Zabbix ruan tĂ« gjithĂ« konfigurimin nĂ« njĂ« bazĂ« tĂ« dhĂ«nash, dhe nga ajo erdhi pyetja se si tĂ« menaxhohej konfigurimi nĂ« kushtet aktuale dhe si tĂ« ndiqeshin ndryshimet.
- Prometheus â Ă«shtĂ« ajo nĂ« tĂ« cilĂ«n do tĂ« arrijmĂ« pĂ«rfundimisht, sipas ndjenjave nĂ« departament, por nĂ« atĂ« moment nuk arrita ta realizoja dhe nuk arrita tĂ« demonstroja njĂ« mostĂ«r funksionuese nĂ« mĂ«nyrĂ« reale (Proof of Concept), kĂ«shtu qĂ« u detyrova tĂ« heq dorĂ«.
- Ishte edhe disa opsione të tjera, të cilat kërkonin një riparim të plotë të sistemit, ose ishin në fazat fillestare / braktisur dhe për këtë arsye u hodhën poshtë.
Në fund, u ndala te Icinga2 për tre arsye:
1 â kompatibilitet me Nrpe (shĂ«rbimi klientor qĂ« ekzekuton kontrollet pĂ«rmes komandave nga Nagios). Kjo ishte shumĂ« e rĂ«ndĂ«sishme, sepse nĂ« atĂ« kohĂ« kishim 135 (tani nĂ« 2019 janĂ« 165) makina virtuale me shumĂ« shĂ«rbime/kontrolle tĂ« krijuara vetĂ« dhe ristrukturimi i gjithĂ« kĂ«saj do tĂ« ishte njĂ« stres i madh.
2 â tĂ« gjithĂ« skedarĂ«t e konfigurimit janĂ« tekstualĂ«, çka lejon qĂ« tĂ« redaktohet lehtĂ«, tĂ« krijohen kĂ«rkesa pĂ«r bashkimin e skedarĂ«ve me mundĂ«sinĂ« pĂ«r tĂ« parĂ«, çfarĂ« Ă«shtĂ« shtuar ose fshirĂ«.
3 â ky Ă«shtĂ« njĂ« projekt OpenSource i gjallĂ« dhe nĂ« zhvillim. Ne e duam shumĂ« OpenSource dhe kontribuojmĂ« sa mundemi nĂ« tĂ« pĂ«rmes krijimit tĂ« KĂ«rkesave pĂ«r tĂ« TĂ«rhequr dhe Problemesh pĂ«r tĂ« zgjidhur.
Pra, le të fillojmë me Icinga2.
E para me tĂ« cilĂ«n u pĂ«rballa â inertĂ«sia e kolegĂ«ve. TĂ« gjithĂ« ishin mĂ«suar me Nagios/Nadjius (edhe kĂ«tu nuk arritĂ«m tĂ« pajtohemi se si ta shqiptojmĂ«) dhe ndĂ«rfaqen e CheckMK. Tek Icinga, ndĂ«rfaqja duket ndryshe (kĂ«to ishte njĂ« disavantazh), por ka mundĂ«sinĂ« pĂ«r ta konfiguruar fleksibĂ«l atĂ« qĂ« dĂ«shirojmĂ« tĂ« shohim pĂ«rmes filtrave pĂ«r çdo parameter (kĂ«to ishte njĂ« avantazh, por pĂ«r tĂ« luftova shumĂ«).
Filtër
Vlerësoni marrëdhënien e madhësisë së shenjës së rrotullimit me madhësinë e fushës për rrotullim.
E dyta â tĂ« gjithĂ« ishin mĂ«suar tĂ« shihnin tĂ« gjithĂ« infrastrukturĂ«n nĂ« njĂ« monitor, sepse CheckMk lejon tĂ« punosh me disa hoste Nagios, por ndĂ«rfaqja e Icinga nuk e bĂ«ri kĂ«tĂ« (nĂ« tĂ« vĂ«rtetĂ« e bĂ«nte, por pĂ«r kĂ«tĂ« mĂ« poshtĂ«). Alternativa ishte njĂ« gjĂ« qĂ« quhej Thruk, por dizajni i saj shkaktonte ndjenja tĂ« neveritshme te tĂ« gjithĂ« anĂ«tarĂ«t e ekipit pĂ«rveç njĂ«rit â atij qĂ« e propozoi (nuk isha unĂ«).
NĂ« djall me Thruk â vendim unanim i ekipit.
Pas disa ditësh mendimesh, unë propozoja idenë e monitorimit me klaster, ku ka një master-host në zonën e prodhimit dhe dy nënshtrues - një në dev/test dhe një host i jashtëm, i vendosur te një ofrues tjetër me qëllim që të monitorojë shërbimet tona nga pikëpamja e klientit ose një vëzhguesi 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 master-host tani duhej të dinte për të gjitha hostet dhe shërbimet/kontrollimet në sistem dhe duhej të shpërndante ato midis zonave (dev-test, staging-prod, ext), por dërgimi i ndryshimeve përmes Icinga API merrte disa sekonda, ndërsa kompilimi i katalogut Puppet për të gjitha shërbimet për të gjitha hostet merrte disa minuta. Më këtë ende akuzohen, megjithëse kam shpjeguar disa herë si funksionon gjithçka dhe pse gjithçka është kaq e gjatë.
E treta - një mori SnowFlakes (flake që përfaqësojnë gjëra që dalin nga sistemi i përgjithshëm, sepse përmbajnë diçka të veçantë, për këtë arsye rregullat e përgjithshme nuk janë të zbatueshme. Kjo u zgjidh përmes një sulmi të drejtpërdrejtë - nëse ka alarmet, por në fakt gjithçka është në rregull, atëherë këtu duhet të thellohemi dhe të kuptojmë pse po alarmon, megjithëse nuk duhet. Ose përkundrazi - pse Nagios panikohet, ndonëse Icinga jo.
E katĂ«rta - Nagios kishte punuar kĂ«tu pĂ«r tre vjet para meje dhe kishte fillimisht mĂ« shumĂ« besim se sistemi im modern hipster, kĂ«shtu qĂ« çdo herĂ« qĂ« Icinga shkaktonte panik - askush nuk bĂ«ntĂ« asgjĂ«, derisa Nagios tĂ« alarmonte pĂ«r tĂ« njĂ«jtin çështje. Por shumĂ« rrallĂ« Icinga jepte alarmet reale pĂ«rpara Nagios dhe unĂ« e mendoj kĂ«tĂ« si njĂ« gabim tĂ« rĂ«ndĂ«sishĂ«m, pĂ«r tĂ« cilin do tĂ« flas nĂ« seksionin âPĂ«rfundimetâ.
Si rezultat, implementimi u vonua mĂ« shumĂ« se 5 muaj (ishte planifikuar pĂ«r 28 qershor 2018, realisht - 3 dhjetor 2018), kryesisht pĂ«r shkak tĂ« âkontrollit tĂ« paritetitâ - atij dreqi, kur ka disa shĂ«rbime nĂ« Nagios, pĂ«r tĂ« cilat askush nuk kishte dĂ«gjuar pĂ«r disa vite, por PIKĂRISHT TANI ata, e lĂ«nĂ«, dolĂ«n crit pa ndonjĂ« arsye dhe mĂ« duhej tĂ« shpjegoja pse ata nuk ishin nĂ« panelin tim dhe duhej t'i shtoja nĂ« Icinga, qĂ« âkontrolli i paritetit Ă«shtĂ« pĂ«rfunduarâ (TĂ« gjitha shĂ«rbimet/kontrollimet nĂ« Nagios pĂ«rputhen me shĂ«rbimet/kontrollimet nĂ« Icinga)
Zbatimi:
E para e â lufta Code vs Data, nĂ« stilin Puppet. TĂ« dhĂ«nat, pra tĂ« gjitha, duhet tĂ« jenĂ« nĂ« Hiera dhe ashtu siç Ă«shtĂ«. TĂ« gjithĂ« kodin â nĂ« skedarĂ«t .pp. Variablat, abstraksionet, funksionet â gjithçka shkon nĂ« pp.
NĂ« fund â kemi njĂ« sĂ«rĂ« makinash virtuale (165 nĂ« momentin e shkruajtur tĂ« artikullit) dhe 68 aplikacione web, tĂ« cilat duhet tĂ« monitorohen pĂ«r funksionalitetin dhe vlefshmĂ«rinĂ« e certifikatat SSL. Por pĂ«r shkak tĂ« historisĂ« problematike, informacioni pĂ«r monitorimin e aplikacioneve merret nga njĂ« repo tĂ« veçantĂ« gitlab dhe formati i tĂ« dhĂ«nave nuk Ă«shtĂ« ndryshuar qĂ« nga Puppet 3, gjĂ« qĂ« krijon vĂ«shtirĂ«si tĂ« mĂ«tejshme nĂ« konfigurim.
Kodi Puppet për aplikacionet, ruani sytë
përcakto profile::shërbimet::monitorimi::docker_apps(
Hash $lista_aplikacioneve,
Hash $aplikacionet_e_qasshme_nga,
Hash $lista_e_qasshme_e_aplikacioneve,
Hash $defaultet_e_webhost,
Hash $defaultet_e_webcheck,
Hash $përjashtimet_e_shërbimeve,
Hash $objektivat,
Hash $kontrollet_e_aplikacioneve,
)
{
#### APLIKACIONET ####
$zona = $emri
$lista_aplikacioneve.each | String $emri_aplikacioni, Hash $të_Dhënat_e_aplikacionit |
{
$grupi_njoftues = { 'grupi_njoftues' => ($defaultet_e_webcheck[$zona]['grupi_njoftues'] + pick($të_Dhënat_e_aplikacionit['grupi_njoftues'], {} )) } # shton njoftime për grupin e parazgjedhur (sistemet) + çdo grup i përcaktuar në int/pm_docker_apps.eyaml
$të_Dhënat = merge($defaultet_e_webhost, $aplikacionet_e_qasshme_nga, $të_Dhënat_e_aplikacionit)
$domenu_i_saj $të_Dhënat_e_aplikacionit['domenu_i_saj']
$regexp = pick($të_Dhënat_e_aplikacionit['kontrollo_regex'], 'html') # Zgjidh një regex për të kontrolluar
$kontrollo_url = $të_Dhënat_e_aplikacionit['kontrollo_url'] ? {
undef => { 'http_uri' => '\/\' },
default => { 'http_uri' => $të_Dhënat_e_aplikacionit['kontrollo_url'] }
}
$kontrollo_regex = $regexp ?{
'absent' => {},
default => {'http_pritet_trupi_regex' => $regexp}
}
$domenu_i_saj.each | String $vhost, Hash $vdata | { # Ndaj një aplikacion sipas domenesh nëse ka dy ose më shumë
$emri_vhost = {'http_vhost' => $vhost}
$variablat = $të_Dhënat['variablat'] + $emri_vhost + $kontrollo_regex + $kontrollo_url
$adresa_ip_web = is_array($vdata['adresa_ip_web']) ? { # Bëni adresën IP një array nëse nuk është, sepse askizzy ka 2 ips dhe është një array
true => $vdata['adresa_ip_web'],
false => [$vdata['adresa_ip_web']],
}
$qasshmeria_nga_zonat = [$zona] + $lista_e_qasshme_e_aplikacioneve[$të_Dhënat['e_qasshme_nga']] # Kombinoni zonën e parazgjedhur (ku eshte e përcaktuar aplikacioni) dhe zonat shtesë nëse ekzistojnë
$adresa_ip_web.each | String $adresa_ip | { # Për çdo IP (nëse kemi shumë)
$shtesa = length($adresa_ip_web) ? { # Nëse kemi më shumë se një - shtoni IP si një shtesë në këtë emër hosti për të shmangur dyfishimin e burimeve
1 => '',
default => "_${adresa_ip}"
}
$octetet = split($adresa_ip, '.')
$etiketa_ip = "${octetet[2]}.${octetet[3]}" # Përdorimi i oktetëve të fundit shkakton një kolizion midis nginx-vip 203.15.70.94 dhe ip ekst. 49.255.194.94
$qasshmeria_nga_zonat.each | $prefix_zonë |{
$objektivi_zonës = $objektivat[$prefix_zonë]
$emri_nginx_vip = "${prefix_zonë}_nginx-vip-${etiketa_ip}" # Nëse është një host për ext - prefix bëhet 'ext_' (ext_nginx-vip...)
$nginx_host_vip = {
$emri_nginx_vip => {
siguro => prezent,
objektivi => $objektivi_zonës,
adresa => $adresa_ip,
kontrollo_komandë => 'hostalive',
grupe => ['nginx_vip',],
}
}
$variablat_ssl = $kontrollimet_e_aplikacioneve['ssl']
$variablat_regex = $kontrollimet_e_aplikacioneve['http'] + $variablat + $defaultet_e_webcheck[$zona] + $grupi_njoftues
if !defined( Profiles::Services::Monitoring::Host[$emri_nginx_vip] ) {
ensure_resources('profiles::services::monitoring::host', $nginx_host_vip)
}
if !defined( Icinga2::Object::Service["${emri_nginx_vip}_ssl"] ) {
icinga2::object::service {"${emri_nginx_vip}_ssl":
siguro => $të_Dhënat['siguro'],
cakto => ["host.name == $emri_nginx_vip",],
grupe => ['webchecks',],
kontrollo_komandë => 'ssl',
intervali_i_kontrollimit => $përjashtimet_e_shërbimeve['ssl']['intervali_i_kontrollimit'],
objektivi => $objektivat['shërbimet'],
apliko => true,
variablat => $variablat_ssl
}
}
if $regexp != 'absent'{
if !defined(Icinga2::Object::Service["${vhost}${$shtesa} regex"]){
icinga2::object::service {"${vhost}${$shtesa} regex":
siguro => $të_Dhënat['siguro'],
cakto => ["match(*_nginx-vip-${etiketa_ip}, host.name)",],
grupe => ['webchecks',],
kontrollo_komandë => 'http',
intervali_i_kontrollimit => $përjashtimet_e_shërbimeve['regex']['intervali_i_kontrollimit'],
objektivi => $objektivat['shërbimet'],
mundeso_flapping => true,
apliko => true,
variablat => $variablat_regex
}
}
}
}
}
}
}
}Kodi i konfigurimit të hosteve dhe shërbimeve duket gjithashtu tmerrshë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 <> # do të aktivizohet kur të kalojmë plotësisht në icinga
#### APLIKACIONE ####
rast $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']},
}
}
defaut: {
mos dështosh('Ju lutem sigurohuni që nodi të ketë faktorin e $location të vendosur (int, pm, ext)')
}
}
file { '/etc/icinga2/conf.d/':
siguroh => 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}":
siguroh => 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,
}
}
#### HOSTET ####
# Profiles::Services::Monitoring::Host <> # Ky është për invazionin e anijes kur të jetë gati.
$hosts_has_large_disks = query_nodes('mountpoints.*.size_bytes >= 1099511627776')
$hosts.each | String $hostgroup, Hash $list_of_hosts_with_settings | { # Ndarja e listave të site-ve sipas 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 |{ # Ndarja e listave sipas hosteve
# A është ky host në arrayn $hosts_has_large_disks? Nëse po, vendosni 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)) # Ndarja e variablave veçmas
$hostgroups = delete_undef_values([$hostgroup] + $host_data['groups'])
profiles::services::monitoring::host{$host_name:
siguroh => $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){ # TĂ« gjitha hostet e menaxhuara nga API
$hosts_api.each | String $zone, Hash $hosts_api_zone | { # Ndarja e hosteve të api sipas zonave
$hosts_api_zone.each | String $hostgroup, Hash $list_of_hosts_with_settings | { # Ndarja e listave të site-ve sipas 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 |{ # Ndarja e listave sipas hosteve
# A është ky host në arrayn $hosts_has_large_disks? Nëse po, vendosni 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:
siguroh => $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'],
}
}
}
}
}
#### FUND I HOSTEVE ####
#### SHĂRBIME ####
$services.each | String $service_group, Hash $s_list |{ # Grupi i shërbimeve dhe lista e shërbimeve në atë grup
$service_list = $s_list['checks'] # Lista e kontrolleve aktuale, veçmas nga cilësimet e SG
$service_list.each | String $service_name, Hash $data |{
$merged_defaults = merge($service_defaults, $s_list['settings']) # defaultet globale të shërbimeve + defaultet e grupit të shërbimeve
$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)
# Nëse ne e kalojmë kohën e kontrollit të defaultit, por jo nrpe_timeout, bëj që nrpe_timeout të jetë e njëjtë me check_timeout
if ( $merged_data['check_timeout'] and ! $this_service_vars['nrpe_timeout'] ) {
# NB: Icinga do ta konvertojë 1m në 60 automatikisht!
$nrpe = { 'nrpe_timeout' => $merged_data['check_timeout'] }
} else {
$nrpe = {}
}
# Në përgjithësi përdorim nrpe dhe të gjitha urdhërat ekzekutohen përmes nrpe. Pra vars.nrpe_command = $service_name është një vlerë e parazgjedhur
# Nëse është urdhri i Icinga-s nga ana e serverit - nuk na nevojitet 'nrpe_command',
# por nuk ka dëm që të kemi atë variabël dhe kodi është më i shkurtër
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 = {}
}
# Duke mbledhur $vars nga cilësimet globale të shërbimeve, cilësimet e grupit të shërbimeve, këtë cilësim të veçantë të kontrollit dhe mos ta harrojmë cilësimin nrpe.
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 është e nevojshme kudo, përndryshe bëhet "Vlera '' nuk mund të konvertohet në Numeric"
$service_notify_group = $service_notify ? {
[] => $service_defaults['vars']['notify_group'],
default => $service_notify
} # Cakto grupin e parazgjedhur (sistemet) nëse nuk janë përcaktuar grupe të tjera
$vars = $all_service_vars + $nrpe + $check_command + $graphite_template + {'notify_group' => $service_notify_group}
# Kjo duhet të bashkohet veçmas, sepse bashkimi i saj si pjesë e MERGED_DATA do të mbivendosë listat në vend të bashkimit, kështu që humbasim disa "cakto" dhe "injoro" vlera
$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:
siguroh => $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'],
}
}
}
#### FUND I SHĂRBIMEVE ####
#### GJERĂ OTHER BORING ####
$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'],
}
}
# Bashkimi i cilësimeve të njoftimeve për përdoruesit me cilësime të tjera
$users_oncall = deep_merge($users, $oncall)
# Magji. Mos e preki.
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':
siguroh => present,
sudoersd_template => 'profiles/os/redhat/centos7/sudoers/icinga.erb',
}
}Unë vazhdoj të punoj mbi këtë kod dhe ta përmirësoj sa më shumë të jetë e mundur. Megjithatë, ky kod mundësoi 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, ku secili grup ka cilësime të paracaktuara si dhe ku dhe sa shpesh të kryhen këto kontrollime, cilat njoftime të dërgohen dhe kujt.
NĂ« çdo kontrollim mund tĂ« anashkalosh çdo opsion dhe gjithçka kĂ«shtu ka pĂ«rfunduar duke u kombinuar me cilĂ«simet e paracaktuara tĂ« tĂ« gjitha kontrollimeve nĂ« pĂ«rgjithĂ«si. Prandaj, nĂ« config.pp Ă«shtĂ« shkruar njĂ« kod i tillĂ« â atje ndodh kombinimi i tĂ« gjitha cilĂ«simeve tĂ« paracaktuara me cilĂ«simet e grupeve dhe mĂ« pas me çdo kontrollim individual.
Një tjetër ndryshim i rëndësishëm është 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 për kontrollimin 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Ă« pĂ«rkufizimin e hostit ka njĂ« variabĂ«l http_port â pĂ«rdoreni atĂ«, pĂ«rndryshe 443. PĂ«r shembull, ndĂ«rfaqja web e jabber Ă«shtĂ« nĂ« 9090, dhe Unifi â nĂ« 7443.
http_vhost do të thotë të injorosh DNS-në dhe të marrësh këtë adresë.
NĂ«se nĂ« host Ă«shtĂ« pĂ«rcaktuar uri â atĂ«herĂ« shko pĂ«rmes tij, pĂ«rndryshe merr "\/".
Me http_ssl ka ndodhur njĂ« histori qesharake â ky ndryshim nuk donte tĂ« ndizte sipas kĂ«rkesĂ«s. E kosa shumĂ« deri sa arrita tĂ« kuptoj se variabla ishte nĂ« pĂ«rkufizimin e hostit:
http_ssl: falsePërdoret në shprehje
if(host.vars.http_ssl) { return false } else { return true }si false dhe në fund rezulton
if(false) { return false } else { return true }këshilla është se kontrolli i ssl është gjithmonë aktiv. U zgjidh duke ndryshuar sintaksën:
http_ssl: noPërfundimet:
Avantazhet:
- Tani kemi një sistem monitorimi, jo dy siç ishte për 7-8 muajt e fundit, ose një të vjetër dhe të cenueshme.
- Struktura e të dhënave të hosteve / shërbimeve (kontrollit) tani është (në mendimin tim) shumë më e lexueshme dhe e kuptueshme. Për të tjerët, kjo u duk se nuk ishte aq e qartë, kështu që pata nevojë të krijoj disa faqe në wiki-n lokale për të shpjeguar si funksionon gjithçka dhe çfarë duhet të rregullohet.
- Ka mundësi për konfigurimin fleksibël të kontrolleve me ndihmën e variablave dhe funksioneve, për shembull për kontrollin http_regexp modelin e kërkuar, kodin e kthimit, url dhe portin mund të përcaktohen në cilësimet e hostit.
- Ka disa panele (dashboards), për secilën prej të cilave mund të përcaktoni listën e alarmave që do të shfaqen dhe të menaxhoni gjithçka përmes Puppet dhe merge requests.
Disavantazhet:
- Inercia e anĂ«tarĂ«ve tĂ« ekipit â Nagios punonte, punonte dhe punonte, ndĂ«rsa kjo Isinga jote gjithmonĂ« bllokohet dhe ngadalĂ«sohet. Po si tĂ« shoh histori? Oh, e qartĂ«, ajo nuk pĂ«rditĂ«sohet... (Problemi real â historia e alarmave nuk pĂ«rditĂ«sohet automatikisht, vetĂ«m me F5)
- Inercia e sistemit â kur klikoj nĂ« ndĂ«rfaqen web nĂ« 'pĂ«rditĂ«so' (check now) â rezultati i ekzekutimit varet nga moti nĂ« Mars, sidomos pĂ«r shĂ«rbimet e komplikuara qĂ« kĂ«rkojnĂ« dhjetĂ«ra sekonda pĂ«r tĂ« pĂ«rfunduar. NjĂ« rezultat i tillĂ« Ă«shtĂ« njĂ« gjĂ« normale.

- Në përgjithësi, sipas statistikave gjashtë-mujore të punës së dy sistemeve ngjitur, Nagios gjithmonë funksiononte më shpejt se Icinga dhe kjo më irritonte shumë. Siç më duket, atje kanë bërë ndonjë truk me timerat dhe kontrolli çdo pesë minuta në fakt ndodh çdo 5:30 ose diçka e tillë.
- NĂ«se rinis shĂ«rbimin nĂ« çdo moment (systemctl restart icinga2) â tĂ« gjitha kontrollet qĂ« nĂ« atĂ« moment ishin duke u ekzekutuar do tĂ« japin alarmin critical nĂ« ekran dhe nga anash duket se gjithçka ka rĂ«nĂ« ().
Por nĂ« tĂ«rĂ«si â funksionon.
Burimi: habr.com

