Pershendetje te gjitheve
Unë jam një administrator i sistemit Linux, u transferova nga Rusia në Australi me një vizë të pavarur profesionale në 2015, por artikulli nuk do të jetë se si të filloni një traktor për një derr. Tashmë ka mjaft artikuj të tillë (megjithatë, nëse ka interes, do të shkruaj edhe për këtë), kështu që do të doja të flisja se si, në punën time në Australi si inxhinier linux-ops, fillova migrimin nga një monitorim i sistemit tek një tjetër. Konkretisht - Nagios => Icinga2.
Artikulli është pjesërisht teknik dhe pjesërisht për komunikimin me njerëzit dhe problemet që lidhen me dallimet në kulturë dhe metoda të punës.
Fatkeqësisht, etiketa "kodi" nuk nxjerr në pah kodin Puppet dhe yaml, kështu që më duhej të përdorja "tekst të thjeshtë".
Nuk ka pasur shenja telashe në mëngjesin e 21 dhjetorit 2016. Si zakonisht, po lexoja Habr nga një përdorues anonim i paregjistruar në gjysmën e parë të ditës së punës, teksa pija kafe dhe hasa. .
Meqenëse kompania ime përdorte Nagios, pa u menduar dy herë, krijova një biletë në Redmine dhe dërgova lidhjen në bisedën e përgjithshme, sepse e konsiderova të rëndësishme. Nisma është e dënueshme edhe në Australi, kështu që inxhinieri kryesor ma vuri problemin që kur e zbulova.
Pamja e ekranit nga Redmine
Në departamentin tonë, përpara se të shprehni mendimin tuaj, është zakon të ofroni të paktën një alternativë, edhe nëse zgjedhja është e qartë, kështu që fillova duke kërkuar në google se çfarë lloj sistemesh monitorimi janë aktualisht të rëndësishme, pasi në Rusi në vendin tim të fundit të punës kishte sistemin tim të vetë-shkruar, shumë primitiv, por gjithsesi mjaft funksional dhe duke kryer të gjitha detyrat që i ngarkoheshin. Python, Politekniku i Shën Petersburgut dhe rregulli i metrosë. Jo, metroja është e keqe. Kjo është personale (11 vjet punë) dhe e denjë për një artikull të veçantë, por jo tani.
Pak për rregullat për të bërë ndryshime në konfigurimin e infrastrukturës në vendin tim aktual. Ne përdorim Puppet, Gitlab dhe Infrastrukturën si një parim Kodi, kështu që:
- Nuk ka ndryshime manuale nëpërmjet SSH duke ndryshuar manualisht ndonjë skedar në makinat virtuale. Gjatë tre viteve të punës, unë u godita me kapele për këtë shumë herë, hera e fundit ishte një javë më parë dhe nuk mendoj se ishte hera e fundit. Epo, me të vërtetë - korrigjoni një rresht në konfigurim, rinisni shërbimin dhe shikoni nëse problemi është zgjidhur - 10 sekonda. Krijoni një degë të re në Gitlab, shtyni ndryshimet, prisni që r10k të punojë në Puppetmaster, ekzekutoni Puppet -environment=mybranch dhe prisni disa minuta të tjera derisa gjithçka të funksionojë - minimumi 5 minuta.
- Çdo ndryshim bëhet duke krijuar një kërkesë për bashkim në Gitlab dhe duhet të miratohet nga të paktën një anëtar i ekipit. Ndryshimet e mëdha të vendosura nga drejtuesi i ekipit kërkojnë dy ose tre miratime.
- Të gjitha ndryshimet janë tekst në një mënyrë ose në një tjetër (meqenëse manifestet e Puppet, skriptet dhe të dhënat e Hiera janë tekst), binarët janë shumë të dekurajuar dhe duhet të ketë një arsye bindëse për të miratuar skedarë të tillë.
Pra, opsionet që konsiderova:
- Munin - nëse ka më shumë se 10 serverë në infrastrukturë, administrimi kthehet në ferr (nga . Nuk kisha ndonjë dëshirë të veçantë për ta kontrolluar këtë, kështu që mora fjalën e tij për të).
- Zabbix - E kisha parë për një kohë të gjatë, në Rusi, por më pas ishte e tepërt për detyrat e mia. Këtu - duhej të hidhej për shkak të përdorimit të Puppet si menaxher konfigurimi dhe Gitlab si një sistem kontrolli versioni. Në atë kohë, me sa kuptova, Zabbix ruan të gjithë konfigurimin në bazën e të dhënave, dhe për këtë arsye nuk ishte e qartë se si të menaxhohej konfigurimi në kushtet aktuale dhe si të gjurmoheshin ndryshimet.
- Prometeu është ajo që do të arrijmë në fund, duke gjykuar nga disponimi në departament, por në atë kohë nuk e zotërova dhe nuk isha në gjendje të demonstroja një mostër vërtet funksionale (Proof of Concept), kështu që më duhej të refuzoja.
- Kishte gjithashtu disa opsione të tjera që ose kërkonin një ripërpunim të plotë të sistemit, ose ishin në fillimet e tyre / të braktisura dhe u refuzuan për të njëjtën arsye.
Në fund, u vendosa në Icinga2 për tre arsye:
1 - pajtueshmëria me Nrpe (një shërbim klienti që kryen kontrolle komanduese nga Nagios). Kjo ishte shumë e rëndësishme, sepse në atë kohë kishim 135 (tani janë 2019 në 165) makina virtuale me një mori shërbimesh/kontrollesh të shkruara me porosi, dhe ribërja e të gjithave do të ishte një dhimbje e vërtetë.
2 - të gjithë skedarët e konfigurimit janë tekst, gjë që e bën të lehtë modifikimin e kësaj çështje, krijimin e kërkesave për bashkim me aftësinë për të parë se çfarë është shtuar ose fshirë.
3 është një projekt OpenSource i gjallë dhe në zhvillim. Ne vërtet e duam OpenSource dhe japim çdo kontribut të mundshëm për të duke krijuar kërkesa për tërheqje dhe çështje për të zgjidhur problemet.
Pra, le të shkojmë, Icinga2.
Gjëja e parë me të cilën duhej të përballesha ishte inercia e kolegëve të mi. Të gjithë janë mësuar me Nagios/Naggios (megjithëse edhe këtu nuk mund të arrinin në një kompromis se si ta shqiptonin) dhe ndërfaqen CheckMK. Ndërfaqja icinga duket krejtësisht e ndryshme (kjo ishte një minus), por është e mundur të personalizoni në mënyrë fleksibël atë që duhet të shihni duke përdorur filtra për fjalë për fjalë çdo parametër (ky ishte një plus, por unë luftova shumë për të).
Filtra
Vlerësoni raportin e madhësisë së shiritit të lëvizjes me madhësinë e fushës së lëvizjes.
Së dyti, të gjithë janë mësuar të shohin të gjithë infrastrukturën në një monitor, sepse CheckMk ju lejon të punoni me disa host Nagios, por ndërfaqja Icinga nuk mund ta bënte këtë (në fakt, mundet, por më shumë për këtë më poshtë). Alternativa ishte diçka e quajtur Thruk, por dizajni i saj i bëri të gjithë në ekip të gënjejnë, përveç njërit - atij që e sugjeroi atë (jo mua).
Në furrën Thruk - vendimi unanim i ekipit
Pas disa ditësh idesh, unë propozova idenë e monitorimit të grupimeve, kur ka një host master në zonën e prodhimit dhe dy skllevër - një në dev/test dhe një host i jashtëm i vendosur në një ofrues tjetër për të monitoruar tonë shërbimet nga këndvështrimi i një klienti ose një vëzhguesi të jashtëm. Ky konfigurim bëri të mundur shikimin e të gjitha problemeve në një ndërfaqe në internet dhe funksionoi mjaft mirë, por Puppet... Problemi me Puppet ishte se hosti kryesor tani duhej të dinte për të gjitha hostet dhe shërbimet/kontrollet në sistem dhe kishte për t'i shpërndarë ato midis zonave (dev-test, staging-prod, ext), por dërgimi i ndryshimeve përmes Icinga API zgjat disa sekonda, por përpilimi i drejtorisë Puppet të të gjitha shërbimeve për të gjithë hostet zgjat disa minuta. Kjo ende po më fajësohet, megjithëse tashmë e kam shpjeguar disa herë se si funksionon gjithçka dhe pse e gjithë kjo zgjat kaq shumë.
Së treti, ka një tufë SnowFlakes - gjëra që dallohen nga sistemi i përgjithshëm sepse kanë diçka të veçantë, kështu që rregullat e përgjithshme nuk vlejnë për to. Ajo u zgjidh nga një sulm frontal - nëse ka alarme, por në fakt gjithçka është në rregull, atëherë duhet të gërmoj më thellë dhe të kuptoj pse më alarmon, megjithëse nuk duhet. Ose anasjelltas - pse Nagios ka panik, por Icinga jo.
Së katërti, Nagios punoi këtu para meje për tre vjet dhe fillimisht kishte më shumë besim tek ai sesa në sistemin tim të ri të hipsterit, kështu që sa herë që Icinga ngrinte një panik, askush nuk bëri asgjë derisa Nagios u emocionua për të njëjtën çështje. Por shumë rrallë Icinga gjeneroi alarme reale më herët se Nagios dhe unë e konsideroj këtë një problem serioz, për të cilin do të flas në seksionin "Përfundime".
Si rezultat, vënia në punë u vonua për më shumë se 5 muaj (i planifikuar për 28 qershor 2018, në fakt - 3 dhjetor 2018), kryesisht për shkak të "kontrollit të barazisë" - asaj katrahure kur ka disa shërbime në Nagios që askush nuk i di rreth nuk kam dëgjuar asgjë për dy vitet e fundit, por TANI ata dhanë kritika pa asnjë arsye dhe më duhej të shpjegoja pse nuk ishin në panelin tim dhe duhej t'i shtoja në Icinga në mënyrë që "kontrolli i barazisë të jetë i plotë" (Të gjitha shërbimet/kontrollet në Nagios korrespondojnë me shërbimet/kontrollet në Icinga)
Zbatimi:
E para është lufta e kodit kundër të dhënave, siç është Stili i Kukullave. Të gjitha të dhënat, absolutisht gjithçka, duhet të jenë në Hiera dhe asgjë tjetër. I gjithë kodi është në skedarët .pp. Variablat, abstraksionet, funksionet - gjithçka shkon në f.
Si rezultat, ne kemi një sërë makinash virtuale (165 në kohën e shkrimit) dhe 68 aplikacione ueb që duhet të monitorohen për performancën dhe vlefshmërinë e certifikatave SSL. Por për shkak të hemorroideve historike, informacioni për monitorimin e aplikacioneve merret nga një depo e veçantë gitlab dhe formati i të dhënave nuk ka ndryshuar që nga Puppet 3, gjë që krijon kompleksitet shtesë në konfigurim.
Kodi i kukullave për aplikacione, mbroni sytë tuaj
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
}
}
}
}
}
}
}
}Kodi i konfigurimit për hostet dhe shërbimet duket gjithashtu i tmerrshëm:
monitorim/konfigurim.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ë jam ende duke punuar në këto petë dhe duke i përmirësuar ato sa më mirë që mundem. Sidoqoftë, ishte ky kod që na lejoi të përdorim një sintaksë të thjeshtë dhe të kuptueshme në Hiera:
Të dhëna
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 kontrollet janë të ndara në grupe, secili grup ka cilësimet e paracaktuara, si ku dhe sa shpesh të kryhen këto kontrolle, çfarë njoftimesh dhe kujt t'i dërgohen.
Në çdo kontroll, ju mund të anashkaloni çdo opsion, dhe e gjithë kjo përfundimisht shtohet në cilësimet e paracaktuara të të gjitha kontrolleve në tërësi. Kjo është arsyeja pse një marrëzi e tillë është shkruar në config.pp - bashkon të gjitha cilësimet e paracaktuara me cilësimet e grupit dhe më pas me çdo kontroll individual.
Një tjetër ndryshim shumë i rëndësishëm ishte aftësia për të përdorur funksione në cilësimet, për shembull, funksioni i zëvendësimit të portit, adresës dhe url-së për të kontrolluar 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 ka një variabël në përkufizimin e hostit http_port — përdorni atë, përndryshe 443. Për shembull, ndërfaqja e internetit jabber varet në 9090 dhe Unifi varet në 7443.
http_vhost do të thotë të injorosh DNS dhe të marrësh këtë adresë.
Nëse uri është specifikuar në host, atëherë ndiqni atë, përndryshe merrni "/".
Një histori qesharake doli me http_ssl - ky infeksion nuk donte të shkëputej sipas kërkesës. Unë isha i hutuar për këtë rresht për një kohë të gjatë derisa më kuptoi se ndryshorja në përkufizimin e hostit është:
http_ssl: falseZëvendësohet në shprehje
if(host.vars.http_ssl) { return false } else { return true }si i rremë dhe në fund rezulton
if(false) { return false } else { return true }dmth kontrolli ssl është gjithmonë aktiv. E zgjidha duke zëvendësuar sintaksën:
http_ssl: noGjetjet:
Pro:
- Tani kemi një sistem monitorimi dhe jo dy, siç kemi pasur në 7-8 muajt e fundit, ose një sistem të vjetëruar dhe të pambrojtur.
- Struktura e të dhënave të hosteve/shërbimeve(kontrollit) tani (për mendimin tim) është shumë më e lexueshme dhe e kuptueshme. Për të tjerët, kjo doli të mos ishte aq e qartë, kështu që më duhej të postoja disa faqe në wiki-në lokale për të shpjeguar se si funksionon gjithçka dhe çfarë të modifikoja ku.
- Është e mundur të konfiguroni në mënyrë fleksibël kontrollet duke përdorur variabla dhe funksione, për shembull, për të kontrolluar http_regexp, modeli i dëshiruar, kodi i kthimit, url dhe porti mund të vendosen në cilësimet e hostit.
- Ka disa panele kontrolli, për secilën prej të cilave ju mund të përcaktoni listën tuaj të alarmeve të shfaqura dhe t'i menaxhoni të gjitha këto përmes kërkesave Puppet dhe bashkimit.
Cons:
- Inercia e anëtarëve të ekipit - Nagios punoi, punoi dhe punoi, dhe ky Isinga juaj është vazhdimisht me bug dhe i ngadalshëm. Si mund ta shihni historinë këtu? Oh, dreqin, nuk është i përditësuar... (Problemi i vërtetë është se historia e alarmit nuk përditësohet automatikisht, vetëm nga F5)
- Inercia e sistemit - kur klikoj "përditëso" (kontrollo tani) në ndërfaqen e internetit - rezultati i ekzekutimit varet nga moti në Mars, veçanërisht nga shërbimet komplekse që kërkojnë dhjetëra sekonda për t'u ekzekutuar. Një rezultat i tillë është normal.

- Në përgjithësi, sipas statistikave gjashtëmujore të funksionimit të dy sistemeve krah për krah, Nagios ka punuar gjithmonë më shpejt se Icinga dhe kjo më ka mërzitur vërtet. Më duket se kanë ngatërruar diçka me kohëmatësit dhe kontrolli bëhet çdo pesë minuta, në fakt ndodh çdo 5:30 ose diçka e tillë.
- Nëse e rinisni shërbimin në çdo kohë (systemctl rinisni icinga2) - të gjitha kontrollet që ishin në proces në atë kohë do të gjenerojnë një alarm kritik në ekran dhe nga jashtë duket sikur gjithçka kishte rënë ().
Por në përgjithësi, funksionon.
Burimi: www.habr.com

