Hej alle sammen.
Jeg er en Linux-systemadministrator, jeg flyttede fra Rusland til Australien på et uafhængigt professionelt visum i 2015, men artiklen vil ikke handle om, hvordan man starter en traktor til en gris. Der er allerede nok sådanne artikler (ikke desto mindre, hvis der er interesse, vil jeg også skrive om dette), så jeg vil gerne tale om, hvordan jeg i mit arbejde i Australien som linux-ops-ingeniør startede migrering fra én systemovervågning til en anden. Nærmere bestemt - Nagios => Icinga2.
Artiklen handler dels teknisk og dels om kommunikation med mennesker og problemer forbundet med forskelle i kultur og arbejdsmetoder.
Desværre fremhæver "code" tagget ikke Puppet og yaml kode, så jeg var nødt til at bruge "plaintext".
Der var ingen tegn på problemer om morgenen den 21. december 2016. Som sædvanlig læste jeg Habr af en uregistreret anonym bruger i den første halve time af arbejdsdagen, mens jeg drak kaffe, og stødte på .
Da mit firma brugte Nagios, oprettede jeg uden at tænke to gange en billet i Redmine og sendte linket til den generelle chat, fordi jeg anså det for vigtigt. Initiativet er strafbart selv i Australien, så den ledende ingeniør har sat problemet på mig, siden jeg opdagede det.
Skærmbillede fra Redmine
I vores afdeling, før du udtrykker din mening, er det sædvanligt at tilbyde mindst ét alternativ, selvom valget er indlysende, så jeg startede med at google, hvilken slags overvågningssystemer der er relevante i øjeblikket, da jeg i Rusland på mit sidste arbejdssted havde mit eget selvskrevne system, meget primitivt, men ikke desto mindre fungerende og udfører alle de opgaver, det er tildelt. Python, St. Petersburg Polytechnic og metro reglen. Nej, metroen stinker. Dette er personligt (11 års arbejde) og fortjener en separat artikel, men ikke nu.
Lidt om reglerne for at lave ændringer i infrastrukturkonfigurationen på mit nuværende sted. Vi bruger Puppet, Gitlab og infrastrukturen som et kodeprincip, så:
- Ingen manuelle ændringer via SSH ved manuelt at ændre nogen filer på de virtuelle maskiner. I løbet af de tre års arbejde, blev jeg ramt med en hat for dette mange gange, sidste gang var for en uge siden, og jeg tror ikke, det var sidste gang. Nå, virkelig - ret en linje i konfigurationen, genstart tjenesten og se om problemet er løst - 10 sekunder. Opret en ny filial i Gitlab, tryk på ændringerne, vent på, at r10k virker på Puppetmaster, kør Puppet -environment=mybranch og vent et par minutter mere, indtil det hele virker - mindst 5 minutter.
- Eventuelle ændringer foretages ved at oprette en Merge Request i Gitlab og skal modtage godkendelse fra mindst ét teammedlem. Større ændringer besluttet af teamlederen kræver to eller tre godkendelser.
- Alle ændringer er tekst på den ene eller anden måde (da Puppet-manifester, scripts og Hiera-data er tekst), er binære filer stærkt frarådige, og der skal være en tvingende grund til at godkende sådanne filer.
Så de muligheder jeg overvejede:
- Munin - hvis der er mere end 10 servere i infrastrukturen, bliver administrationen til et helvede (fra . Jeg havde ikke noget særligt ønske om at tjekke dette, så jeg tog hans ord for det).
- Zabbix - Jeg havde kigget på det længe, tilbage i Rusland, men så var det overflødigt til mine opgaver. Her - måtte kasseres på grund af brugen af Puppet som konfigurationsmanager og Gitlab som versionskontrolsystem. På det tidspunkt gemmer Zabbix, så vidt jeg forstod, hele konfigurationen i databasen, og derfor var det ikke klart, hvordan man administrerer konfigurationen under de nuværende forhold, og hvordan man sporer ændringer.
- Prometheus er det, vi kommer til i sidste ende, at dømme efter stemningen i afdelingen, men på det tidspunkt mestrede jeg det ikke og var ikke i stand til at demonstrere en virkelig fungerende prøve (Proof of Concept), så jeg måtte afslå.
- Der var også flere andre muligheder, som enten krævede en fuldstændig omarbejdelse af systemet, eller som var i deres vorden/opgivet og blev afvist af samme grund.
Til sidst slog jeg mig til Icinga2 af tre grunde:
1 - kompatibilitet med Nrpe (en klienttjeneste, der kører kommandotjek fra Nagios). Dette var meget vigtigt, for på det tidspunkt havde vi 135 (nu er der 2019 i 165) virtuelle maskiner med en masse specialskrevne tjenester/checks, og det ville have været en reel smerte at lave om på det hele.
2 - alle konfigurationsfiler er tekst, hvilket gør det nemt at redigere denne sag, oprette fletteforespørgsler med mulighed for at se, hvad der er blevet tilføjet eller slettet.
3 er et levende og udviklende OpenSource-projekt. Vi elsker OpenSource meget og yder ethvert muligt bidrag til det ved at oprette Pull Requests og Issues for at løse problemer.
Så lad os gå, Icinga2.
Det første, jeg måtte se, var mine kollegers træghed. Alle er vant til Nagios/Nagios (selvom de ikke selv her kunne komme til et kompromis om, hvordan man udtaler det) og CheckMK-grænsefladen. Icinga-grænsefladen ser helt anderledes ud (dette var et minus), men det er muligt fleksibelt at tilpasse, hvad du har brug for at se ved hjælp af filtre til bogstaveligt talt enhver parameter (dette var et plus, men jeg kæmpede meget for det).
Filtre
Estimer forholdet mellem størrelsen af rullepanelet og størrelsen af rullefeltet.
For det andet er alle vant til at se hele infrastrukturen på én skærm, fordi CheckMk giver dig mulighed for at arbejde med flere Nagios-værter, men Icinga-grænsefladen kunne ikke gøre dette (det kunne den faktisk, men mere om det nedenfor). Alternativet var noget, der hed Thruk, men dets design fik alle på holdet til at gage undtagen én – ham, der foreslog det (ikke mig).
Ind i Thruk-ovnen - holdets enstemmige beslutning
Efter et par dages brainstorming foreslog jeg ideen om klyngeovervågning, når der er en masterhost i produktionszonen og to slaver - en i dev/test og en ekstern vært placeret hos en anden udbyder for at overvåge vores tjenester fra en klients eller en ekstern observatørs synspunkt. Denne konfiguration gjorde det muligt at se alle problemerne i én web-grænseflade og fungerede ganske godt, men Puppet... Problemet med Puppet var, at master-værten nu skulle kende til alle værterne og tjenester/tjek i systemet og havde at distribuere dem mellem zoner (dev-test, staging-prod, ext), men at sende ændringer via Icinga API tager et par sekunder, men at kompilere Puppet-biblioteket med alle tjenester for alle værter tager et par minutter. Dette får mig stadig skylden, selvom jeg allerede flere gange har forklaret, hvordan alting fungerer, og hvorfor det hele tager så lang tid.
For det tredje - en flok SnowFlakes - ting, der skiller sig ud fra det generelle system, fordi de har noget særligt, så de generelle regler gælder ikke for dem. Det blev løst ved et frontalangreb - hvis der er alarmer, men i virkeligheden er alt i orden, så skal jeg grave dybere og finde ud af, hvorfor det advarer mig, selvom det ikke burde. Eller omvendt - hvorfor Nagios går i panik, men det gør Icinga ikke.
For det fjerde arbejdede Nagios her før mig i tre år, og der var i starten mere tillid til ham end til mit nymodens hipstersystem, så hver gang Icinga fik panik, var der ingen, der gjorde noget, før Nagios blev begejstret for det samme problem. Men meget sjældent genererede Icinga rigtige alarmer tidligere end Nagios, og jeg betragter dette som et alvorligt problem, som jeg vil tale om i afsnittet "Konklusioner".
Som et resultat blev idriftsættelsen forsinket i mere end 5 måneder (planlagt til 28. juni 2018, faktisk - 3. december 2018), hovedsageligt på grund af "paritetstjek" - det lort, når der er flere tjenester i Nagios, om hvilke ingen man har ikke hørt noget i de sidste par år, men LIGE NU gav de fandme kritik uden grund, og jeg var nødt til at forklare, hvorfor de ikke var på mit panel og var nødt til at tilføje dem til Icinga, så "paritetstjek er komplet" (Alle tjenester/tjek i Nagios svarer til tjenester/tjek i Icinga)
Implementering:
Den første er Code vs Data-krigen, såsom Puppet Style. Alle data, absolut alt, skal være i Hiera og intet andet. Al kode er i .pp-filer. Variabler, abstraktioner, funktioner - alt foregår på pp.
Som et resultat har vi en masse virtuelle maskiner (165 i skrivende stund) og 68 webapplikationer, der skal overvåges for ydeevne og gyldigheden af SSL-certifikater. Men på grund af historiske hæmorider tages information til overvågning af applikationer fra et separat gitlab-lager, og dataformatet har ikke ændret sig siden Puppet 3, hvilket skaber yderligere kompleksitet i konfigurationen.
Dukkekode til applikationer, beskyt dine øjne
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
}
}
}
}
}
}
}
}Konfigurationskoden for værter og tjenester ser også forfærdelig ud:
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',
}
}Jeg arbejder stadig på disse nudler og forbedrer dem så godt jeg kan. Det var imidlertid denne kode, der gjorde det muligt for os at bruge en enkel og forståelig syntaks i Hiera:
Data
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'Alle kontroller er opdelt i grupper, hver gruppe har standardindstillinger såsom hvor og hvor ofte disse kontroller skal køres, hvilke notifikationer der skal sendes og til hvem.
I hver kontrol kan du tilsidesætte enhver mulighed, og alt dette lægger i sidste ende op til standardindstillingerne for alle kontroller som helhed. Det er derfor sådan noget sludder er skrevet i config.pp - det fusionerer alle standardindstillingerne med gruppeindstillingerne og derefter med hver enkelt kontrol.
En anden meget vigtig ændring var muligheden for at bruge funktioner i indstillingerne, for eksempel funktionen til at erstatte port, adresse og url for at kontrollere 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: trueDet betyder - hvis der er en variabel i værtsdefinitionen http_port — brug det, ellers 443. For eksempel hænger jabber-webgrænsefladen ved 9090, og Unifi hænger ved 7443.
http_vhost betyder at ignorere DNS og tage denne adresse.
Hvis uri'en er angivet i værten, så følg den, ellers tag "/".
En sjov historie kom ud med http_ssl - denne infektion ønskede ikke at afbryde forbindelsen efter behov. Jeg var forvirret over denne linje i lang tid, indtil det gik op for mig, at variablen i værtsdefinitionen er:
http_ssl: falseSubstitueret til udtryk
if(host.vars.http_ssl) { return false } else { return true }som falsk og til sidst viser det sig
if(false) { return false } else { return true }det vil sige, at ssl-kontrollen altid er aktiv. Jeg løste det ved at erstatte syntaksen:
http_ssl: noFund:
Teknikere:
- Vi har nu ét overvågningssystem, og ikke to, som vi har haft de sidste 7-8 måneder, eller et, der er forældet og sårbart.
- Hosts/services(checks) datastrukturen er nu (efter min mening) meget mere læsbar og forståelig. For andre viste det sig ikke at være så indlysende, så jeg var nødt til at poste et par sider på den lokale wiki for at forklare, hvordan det hele fungerer, og hvad der skal redigeres hvor.
- Det er muligt fleksibelt at konfigurere checks ved hjælp af variabler og funktioner, for eksempel at kontrollere http_regexp, det ønskede mønster, returkode, url og port kan indstilles i værtsindstillingerne.
- Der er adskillige dashboards, for hver af dem kan du definere din egen liste over viste alarmer og administrere alt dette gennem Puppet og flette anmodninger.
Ulemper:
- Teammedlemmernes træghed - Nagios arbejdede, arbejdede og arbejdede, og din Isinga er konstant buggy og langsom. Hvordan kan du se historien her? Åh, for fanden, den er ikke opdateret... (Det virkelige problem er, at alarmhistorikken ikke opdateres automatisk, kun med F5)
- Systemets træghed - når jeg klikker på "opdater" (tjek nu) i webgrænsefladen - afhænger udførelsesresultatet af vejret på Mars, især af komplekse tjenester, der tager ti sekunder at udføre. Et sådant resultat er normalt.

- Generelt, ifølge seks måneders statistik over driften af de to systemer side om side, arbejdede Nagios altid hurtigere end Icinga, og det irriterede mig virkelig. Det forekommer mig, at de har rodet noget med timerne og kontrollerne hvert femte minut, faktisk sker de en gang hver 5:30 eller sådan noget.
- Hvis du til enhver tid genstarter tjenesten (systemctl genstart icinga2) - vil alle kontroller, der var i gang på det tidspunkt, generere en kritisk alarm på skærmen og udefra ser det ud som om alt var faldet ().
Men overordnet set virker det.
Kilde: www.habr.com

