Автоматизация системы мониторинга на базе Icinga2 и Puppet

 Автоматизация системы мониторинга на базе Icinga2 и Puppet

Поговорим немного о… Infrastructure as code (IaC).

На Хабре есть несколько очень хороших статей про Icinga2, есть также отличные статьи про Puppet:

Icinga2 простой вариант
Поднимаем микромониторинг на icinga2 с минимальными затратами
Настройка современного Puppet сервера с нуля

Однако тема автоматизации и интеграции этих двух потрясающих систем совсем не раскрыта.
В данном руководстве, я покажу на «живом» примере, как можно, объединив эти две
системы, получить мощный инструмент мониторинга вашей инфраструктуры со всем набором необходимых функций. Статья является своего рода руководством к действию по установке пакета «все в одном флаконе». После выполнения этого руководства у вас в наличии будет полностью рабочее решение мониторинга, которое в дальнейшем можно будет «допиливать» под себя. Давайте попробуем!

Итак:

Мы подняли новый хост. И нам нужно:

1. Чтобы его мониторинг автоматически появился в Icinga2, и создались базовые проверки:

Проверки Снимки Пояснения
Host

С заданной периодичностью проверяем командой ping, что хост «живой».
Disk usage

Проверям, что у нас достаточно свободного места на дисках.
Load average

Мониторим нагрузку на сервере динамически. Учитывается количество процессоров на нём.
Free memory

Проверяем, что у нас достаточно свободной памяти на сервере.
Open ports

Сканируем порты на сервере и создаём карту открытых портов. Мониторим, что у нас не появились новые открытые или закрытые порты.
Critical updates

Мониторим наличие критических обновлений на сервере.

2. Добавлять кастомные проверки на различные сервисы в удобном и понятном виде. Что бы потом директору показать какие мы молодцы и премию получить!

Некоторые примеры:

Сервис YAML-код проверки

Virtual host

Проверяем «живой» хост или нет.



    '%{::fqdn} virtual host' :         target: /etc/icinga2/zones.d/master/%{::fqdn}.conf         apply: true         assign: [ 'host.name == %{::fqdn}' ]         display_name: '%{::fqdn} virtualhost'         check_command: 'http'         vars:             http_uri: /             http_ssl: true             http_vhost: 'hostname'             http_address: "%{lookup('host_address')}"     

PostgreSQL

Проверяем, что мы можем соединиться с БД PostgreSQL.



    '%{::fqdn} PostgreSQL':         target: /etc/icinga2/zones.d/master/%{::fqdn}.conf         apply: true         assign: [ 'host.name == %{::fqdn}' ]         display_name: 'PostgreSQL'         command_endpoint: '%{::fqdn}'         check_command: "postgres"         vars:             postgres_host: "localhost"             postgres_action: "connection"             phone_notifications: true     

Nginx Status

Мониторим статус Nginx через stub_status.



    '%{::fqdn} nginx status' :         target: /etc/icinga2/zones.d/master/%{::fqdn}.conf         apply: true         assign: [ 'host.name == %{::fqdn}' ]         command_endpoint: '%{::fqdn}'         display_name: 'nginx status'         check_command: 'nginx_status'         vars:             nginx_status_host_address: localhost             nginx_status_servername: server.com             nginx_status_critical: '1600,60,30'             nginx_status_warn: '1500,55,25'     

3. Чтобы всё было аккуратно, надёжно и красиво. И главное, потратить не более 30 минут на возню с первоначальной настройкой.

У вас должен быть опыт работы с Docker’ом, а значит и с Linux — само собой.

Данный сетап описан под Debian/Ubuntu. И, хотя я не вижу причин ему не работать на других Unix-подобных системах, сам я таких гарантий дать не могу. У меня есть пара машин с CentOS, там это работает, но большинство, всё же — это Debian/Ubuntu.

Начнём

Скажу сразу, мне удобно, когда вся конфигурация хоста — сервисы, конфиги, софт, аккаунты и т.п. — описываются одним yaml-файлом, это фактически позволяет избежать документирования инфраструктуры и даёт наглядность конфигурации. Открыл соответствующий проект в git-репозитории, где имена файлов соответствуют имени хоста, затем открыл конфиг нужного хоста. И сразу видно, какие сервисы есть на хосте, что из этого бэкапится, что мониторится и т.д.

Вот так выглядит структура проекта в репозитории:

project_1/hostname1.com.yaml project_2/hostname2.com.yaml project_3/hostname3.com.yaml 

У себя я использую вот такой шаблон, в котором описывается конфигурация любого из наших серверов:

Полный шаблон

 #============================|INPUT DATA|=================================# #---------------------------------------|VARS|----------------------------# #---//Information about variables, keys & contacts//----------------------#  host_address: x.x.x.x my_company:  my_mail_domain:  my_ssh_port:     #---------------------------------------|CLASSES|-------------------------# #---//Classes are modules installed on the server.//----------------------# #---//These modules process the arguments typed below.//------------------# #---//Without classes nothing will work.//--------------------------------# #---//Class default_role is mandatory. This class will install//----------# #---//etckeeper, some required perl modules and manages all the logics.//-#  classes:   - default_role  #---------------------------------------|TIMEZONE|------------------------# #---//Set timezone, which will be used on the host.//---------------------#  timezone::timezone: Europe/Moscow  #---------------------------------------|FACTS|---------------------------# #---//Facts are variables which puppet agent uses.//----------------------#  facter::facts_hash:  role:    value: 'name'  company:    value: 'name of company'    file: 'location.txt' #=========================================================================#  #============================|PUPPET|=====================================# #---//Settings for puppet agent.//----------------------------------------#  puppet::runmode: cron puppet::ca_server: "%{lookup('puppet_ca')}"  puppet::puppetmaster: "%{lookup('puppet_master')}" #=========================================================================#   #============================|CRON TASKS|=================================#  cron_tasks:     Name:         command: ""         user:          minute: ''         hour: ''     #=========================================================================#  #============================|SUPERVISOR|=================================# #---//Supervisor is a process manager//-----------------------------------#  supervisord::install_pip: false supervisord::install_init: false supervisord::service_name: supervisor supervisord::package_provider: apt supervisord::executable: /usr/bin/supervisord supervisord::executable_ctl: /usr/bin/supervisorctl supervisord::config_file: /etc/supervisor/supervisord.conf supervisord::programs:   'name':     ensure: present     command: 'su - rails -c "/home/name/s2"'     autostart: no     autorestart: 'false'     directory: /home/name/domainName/current  #=========================================================================#   #============================|SECURITY|===================================# #-------------------------------------|FIREWALL|--------------------------# #---//Iptables rules//----------------------------------------------------#  firewall:     096 Allow inbound SSH:       dport: "%{lookup('my_ssh_port')}"       proto: tcp       action: accept  #-------------------------------------|FAIL2BAN|--------------------------#   #-------------------------------------|ACCESS|----------------------------# #--------------------------------------------|ACCOUNTS|-------------------# #---//Discription of accounts which will be created on server.//----------#  accounts:     user:         shell: '/bin/bash'         password: ''         locked: false         purge_sshkeys: true          groups:             - docker         sshkeys:             - "%{alias('admins_ssh_keys')}"     #--------------------------------------------|SUDO|-----------------------# #---//Appointment permissions for users.//--------------------------------#  sudo::config_file_replace: false sudo::configs:     user:         content: "user ALL=(ALL) NOPASSWD: ALL"      #--------------------------------------------|SSH|------------------------# #--------//Settings for ssh server.//-------------------------------------#  ssh::storeconfigs_enabled: true ssh::server_options:     Protocol: '2'     Port: "%{lookup('my_ssh_port')}"     PasswordAuthentication: 'yes'     PermitRootLogin: 'without-password'     SyslogFacility: 'AUTHPRIV'     UsePAM: 'yes'     X11Forwarding: 'no'  #--------------------------------------------|VPN|------------------------# #---//Settings for vpn server.//------------------------------------------#  openvpn::servers:   'namehost':     country: ''     province: ''     city: ''     organization: ''     email: ''     server: 'x.x.x.x 255.255.255.0'     dev: tun     local: "%{lookup('host_address')}"  openvpn::client_defaults:   server: 'namehost'  openvpn::clients:   # Firstname Lastname   'user': {}  openvpn::client_specific_configs:   'user':     server: 'namehost'     redirect_gateway: true     route:     - x.x.x.x 255.255.255.255  #=========================================================================#   #============================|OPERATING SYSTEM|===========================# #---------------------------------------------|SYSCTL|--------------------# #---//set sysctl parameters//---------------------------------------------#  sysctl::base::values:   fs.file-max:     value: '2097152000'   net.netfilter.nf_conntrack_max:     value: '1048576'   net.nf_conntrack_max:     value: '1048576'   net.ipv6.conf.all.disable_ipv6:     value: '1'   vm.oom_kill_allocating_task:     value: '1'       net.ipv4.ip_forward:     value: '0'   net.ipv4.tcp_keepalive_time:      value: '3'   net.ipv4.tcp_keepalive_intvl:     value: '60'   net.ipv4.tcp_keepalive_probes:     value: '9'      #---------------------------------------------|RCS|-----------------------# #---//Managment of RC scenario//------------------------------------------#  rcs::tmptime: '-1'  #---------------------------------------------|WEB SERVERS|---------------# #---------------------------------------------------------|HAPROXY|-------# #---//HAProxy is software that provides a high availability load//--------# #---//balancer and proxy server for TCP and HTTP-based applications//-----#  #---// that spreads requests across multiple servers.//-------------------#  haproxy::merge_options: true haproxy::defaults_options:     log: global     maxconn: 20000     option: [         'tcplog',         'redispatch',         'dontlognull'     ]     retries: 3     stats: enable     timeout: [         'http-request 10s',         'queue 1m',         'check 10s',         'connect 300000000ms',         'client 300000000ms',         'server 300000000ms'     ]  haproxy_server:   stats:     ipaddress: "%{lookup('host_address')}"     ports: '9090'     options:       mode: 'http'       stats: [ 'uri /', 'auth puppet:123123123' ]    postgres:     collect_exported: false     ipaddress: '0.0.0.0'     ports: '5432'      options:         option:             - tcplog         balance: roundrobin haproxy_balancemember:   hostname1:     listening_service: postgres     server_names: hostname1     ipaddresses: "%{lookup('host1_ip')}"     ports: 6432     options: check   hostname2:     listening_service: postgres     server_names: hostname2     ipaddresses: "%{lookup('host2_ip')}"     ports: 6432     options:         - check         - backup          #---------------------------------------------|NGINX|---------------------# #---//Nginx is a web server which can also be used as a reverse proxy,//--# #---//load balancer, mail proxy and HTTP cache//--------------------------#   nginx::nginx_cfg_prepend:   'load_module':       - modules/ngx_http_geoip_module.so nginx::http_raw_append:   - 'real_ip_header X-Forwarded-For;'   - 'geoip_country /usr/share/GeoIP/GeoIP.dat;'   - 'set_real_ip_from 0.0.0.0/0;' nginx::worker_rlimit_nofile: 16384 nginx::confd: true nginx::server_purrge: true nginx::server::maintenance: true    #---------------------------------------------nginx-|MAPS|----------------#  nginx::string_mappings:   allowed_country:     ensure: present     string: '$geoip_country_code'     mappings:       - key: 'default'         value: 'yes'       - key: 'US'         value: 'no'  #---------------------------------------------nginx-|UPSTREAMS|-----------# nginx::nginx_upstreams:   "upstreamName":     ensure: present     members:       - "localhost:9999" #---------------------------------------------nginx-|VHOSTS|--------------# nginx::nginx_servers:    'hostname':     proxy: 'http://'     location_raw_append:         - 'if ($allowed_country = no) {return 403;}'     try_files:     - ''     - /index.html     - =404     ssl: true     ssl_cert: "/etc/letsencrypt/live/hostname/fullchain.pem"     ssl_key: "/etc/letsencrypt/live/hostname/privkey.pem"     ssl_trusted_cert: "/etc/letsencrypt/live/hostname/chain.pem"     ssl_redirect: false     ssl_port: 443     error_pages:       '403': /usa-restrict.html  #---------------------------------------------nginx-|HTTPAUTH|------------#  httpauth:   'admin':     file: "/etc/nginx/htaccess"     password: ''     realm: realm     mechanism: basic     ensure: present  #---------------------------------------------nginx-|LOCATIONS|-----------#  nginx::nginx_locations:   'domain1.com/usa-restricted':     location: /usa-restrict.html     www_root: /home/clientName1/clientName1-client-release/current/dist     server: domain1.com     ssl: true   '^~ domain2.com/resources/upload/':     location: '^~ /resources/upload/'     server: domain2.com     location_alias: '/home/clientName2/upload/'     raw_append:         - 'if ($allowed_country = no) {return 403;}'   '/nginx_status-domain3.com':     location: /nginx_status     stub_status: on     raw_append:         - access_log off;         - allow 127.0.0.1;         - deny all;        #---------------------------------------------nginx-|WELL-KNOWN|----------# #---//These locations are needed for SSL certificates generating//--------# #---//with Letsencrypt.//-------------------------------------------------#    'x.hostname.zz/.well-known':     location: '/.well-known'     server: x.hostname.zz     proxy: 'http://kibana'      auth_basic: "ciao"     auth_basic_user_file: "/etc/nginx/htaccess     www_root: /var/www/html     ssl: true   'hostname.zz/~* \.(?:ico|css|js|html|map|gif|jpg|png|svg|ttf|woff|appcache|pdf)$':     location: '~* \.(?:ico|css|js|html|map|gif|jpg|png|svg|ttf|woff|appcache|pdf)$'     www_root: '/home/hostname/hostname-client-release/current/dist'     expires: max     raw_append:     - "add_header Pragma public;"     - 'add_header Cache-Control "public, must-revalidate, proxy-revalidate";'      #---------------------------------------------------|NGINS STATUS|--------#  #----------------------------|LETSENCRYPT|--------------------------------# #---//Let's Encrypt is a certificate authority that provides #---//free X.509 certificates for Transport Layer Security (TLS)//--------# #---//encryption via an automated process designed to eliminate//---------# #---//the hitherto complex process of manual creation, validation,//------# #---//signing, installation, and renewal of certificates//----------------# #---//for secure websites.//----------------------------------------------#  letsencrypt::email: client@mail.com letsencrypt_certonly:     hostname:         manage_cron: true         domains:             - hostname         plugin: webroot         webroot_paths:             - '/var/www/html'  #----------------------------|FILE SERVERS|-------------------------------# #-----------------------------------------|FILES|-------------------------# #---//Creating files & folders on the server.//---------------------------#  file:     "/home/hostname/hostname-release/shared/ecosystem.config.js":         ensure: present         owner: hostname         content: |             module.exports = {               /**                * Application configuration section                * http://pm2.keymetrics.io/docs/usage/application-declaration/                */               apps : [                 // First application                 {                   name      : 'api',                   script    : '/home/hostname/hostname-release/current/dist/index.js',                   cwd       : '/home/hostname/hostname-release/current/dist/',                   watch     : false,                   ignore_watch : ["logs"],                   "log_type": "format",                   env: {                     COMMON_VARIABLE: 'true'                   },                   env_production : {                     NODE_ENV: 'production',                     PORT: 9999,                     DEBUG   : '*'                   },                   env_development : {                     NODE_ENV: 'development',                     PORT: 9999,                     DEBUG   : '*'                   }                 },                 // Second application                 {                   name      : 'WEB',                   script    : 'web.js'                 }               ],               /**                * Deployment section                * http://pm2.keymetrics.io/docs/usage/deployment/                */               deploy : {                 production : {                   user : 'node',                   host : '0.0.0.0',                   ref  : 'origin/master',                   repo : 'name@name.com:repo.git',                   path : '/var/www/production',                   'post-deploy' : 'npm install && pm2 reload ecosystem.config.js --env production'                 },                 dev : {                   user : 'node',                   host : '0.0.0.0',                   ref  : 'origin/master',                   repo : 'name@name.com:repo.git',                   path : '/var/www/development',                   'post-deploy' : 'npm install && pm2 reload ecosystem.config.js --env dev',                   env  : {                     NODE_ENV: 'dev'                   }                 }               }             };  #-----------------------------------------|FTP|----------------------------# #---//Very Secure FTP Daemon is an FTP server for Unix-like systems.//-----#  vsftpd::ftpd_banner: 'ASCII FTP Server' vsftpd::anonymous_enable: 'NO' vsftpd::write_enable: 'YES' vsftpd::chroot_local_user: 'YES' vsftpd::allow_writeable_chroot: 'YES' vsftpd::userlist_enable: 'YES' vsftpd::userlist_deny: 'NO'  #-----------------------------------------|NFS|---------------------------# #---//Network File System is a distributed file system protocol,//--------# #---//allowing a user on a client computer to access files over//---------#  #---//a computer network much like local storage is accessed.//-----------#  nfs::server_enabled: true nfs::client_enabled :  false nfs::nfs_v4:  true nfs::nfs_v4_idmap_domain:  "%{::domain}" nfs::nfs_v4_export_root:  '/share' nfs::nfs_v4_export_root_clients:  "%{lookup('host_address')}/32(rw,fsid=root,insecure,no_subtree_check,async,no_root_squash)" nfs::nfs_exports_global:   /var/www: {}   /var/smb: {}  #----------------------------|PACKAGES|-----------------------------------# #---//Install of packages to server.//------------------------------------#  packages:     namePackage:         ensure: installed  #-------------------------------------|APT|-------------------------------# #---//Management of repository of packages.//---#  apt::sources:   'debian_unstable':     comment: 'This is the iWeb Debian unstable mirror'     location: 'http://debian.mirror.iweb.ca/debian/'     release: 'unstable'     repos: 'main contrib non-free'     pin: '-10'     key:       id: 'IDIDIDIDIDIDIDIDIDIDIDIDIDIDIDID'       server: 'subkeys.pgp.net'     include:       src: true       deb: true   'puppetlabs':     location: 'http://apt.puppetlabs.com'     repos: 'main'     key:       id: 'IDIDIDIDIDIDIDIDIDIDIDIDIDIDIDID'       server: 'pgp.mit.edu'   #-------------------------------------|PHP|-------------------------------#  php_pool:   myadmin:    listen: 'x.x.x.x:x'  #-------------------------------------|RVM|-------------------------------# #---//Ruby Version Manager  is a unix-like software platform designed//---# #---//to manage multiple installations of Ruby on the same device.//------#  rvm_ruby:   user1_rvm:     user: user1     version: ruby-2.5.1 white_label_platform: default  #-------------------------------------|PYTHON|----------------------------#  python::version: system python::dev: present python::virtualenv: true  #----------------------------|NODEJS|-------------------------------------# #-----------------------------------|NVM|---------------------------------# #---//Node Version Manager for Node.js//----------------------------------# #---//Node.js lets developers use JavaScript to write Command Line//------# #---//tools and for server-side scripting—running scripts server-side//---# #---//to produce dynamic web page content before the page is sent//-------# #---//to the user's web browser.//----------------------------------------#  nodejs::repo_url_suffix: '8.x' nvm::user: name nvm::install_node: 8.10.0  #----------------------------|DOCKER|-------------------------------------# #---//Docker's management//-----------------------------------------------#   docker::run_instance::instance:   nats:     image: 'nats'     extra_parameters: '-p 8222:8222 -p 4222:4222 -p 6222:6222 --name nats --network admin_default' docker::compose::ensure: present docker_compose:     /etc/admin/gitlab/docker-compose.yaml:         ensure: present docker::iptables: false docker::tcp_bind: tcp://0.0.0.0:2375   docker::compose::ensure: present docker_swarm:     'agent':         ensure: present         join: true         advertise_addr: '%{::ipaddress_enp2s0}'         listen_addr: '%{::ipaddress_enp2s0}'         manager_ip: '%{lookup("host_address")}'         token: ''   docker_registry:     'host.com:5000':        username: ''       password: ''       email: 'mail@mail.com'  #=========================================================================#   #============================|BACKUPS UPDATES|============================# #--------------------------------------------|UPDATES|--------------------# #---//Unattended upgrades is the linux-like mechanism//-------------------# #---//automatic updates.//------------------------------------------------#  unattended_upgrades::origins:     - "o=Debian,n=${distro_codename}"     - "o=Debian,n=${distro_codename}-security"     - "o=Debian,n=${distro_codename}-updates"     - "o=Debian,n=${distro_codename}-proposed"     - "o=Debian,n=${distro_codename}-backports"     - "o=debian icinga,n=icinga-${distro_codename}"     - "o=Zabbix,n=${distro_codename}"  #--------------------------------------------|BACKUPS|--------------------# #---//The backups are processed by gembackup.//---------------------------#  backup_jobs:     #Creates full backup     type_files:         types: ['archive']         add:             - '/path'         storage_type: 'ftp'         storage_host: "%{lookup('my_ftp_hostname')}"         path: '/files/'         storage_username: "%{lookup('my_backup_ftp_username')}"         storage_password: "%{lookup('my_backup_ftp_password')}"         compressor: "%{lookup('my_backup_compressor')}"         keep: 7         weekday: [1-7]         hour: 0         minute: 0  #--------------------------------------------|MOUNT|----------------------# #---//Сontrol the mounting of remote & local mount points.//--------------#  mount:     #Mount folder from other server to keep backups     "/tmp/mediastagetv_netbynet":         device: "%{lookup('host_address')}:/"         ensure: mounted         fstype: nfs4         options: defaults         atboot: false  #--------------------------------------------|S3 AMAZON|------------------# #---//Simple Storage Service is a cloud computing web service.//----------#  hostname1-archives: '/home/hostname1/hostname1/shared/log_amazon' hostname2-archives: '/home/hostname2/hostname2/shared/log_amazon' yas3fs::mounts:   #=========================================================================#   #============================|MONITORING|=================================# #---------------------------------------|ICINGA SERVICES|-----------------# #---//Managment of monitoring system.//-----------------------------------#  icinga2_service:         '%{::fqdn} virtual host' :         target: /etc/icinga2/zones.d/master/%{::fqdn}.conf         apply: true         assign: [ 'host.name == %{::fqdn}' ]         display_name: '%{::fqdn} virtualhost'         check_command: 'http'         vars:             http_uri: /             http_ssl: true             http_vhost: 'hostname'             http_address: "%{lookup('host_address')}"          '%{::fqdn} nginx status' :         target: /etc/icinga2/zones.d/master/%{::fqdn}.conf         apply: true         assign: [ 'host.name == %{::fqdn}' ]         command_endpoint: '%{::fqdn}'         display_name: 'nginx status'         check_command: 'nginx_status'         vars:             nginx_status_host_address: localhost             nginx_status_servername: server.com             nginx_status_critical: '1600,60,30'             nginx_status_warn: '1500,55,25'          '%{::fqdn} redis':         target: /etc/icinga2/zones.d/master/%{::fqdn}.conf         apply: true         assign: [ 'host.name == %{::fqdn}' ]         display_name: 'Redis'         command_endpoint: '%{::fqdn}'         check_command: "redis"         vars:             redis_hostname: localhost             redis_port: 6379             redis_perfvars: '*'  #=========================================================================#   #============================|MAIL & LOGS|================================# #----------------------------------------|MAIL|---------------------------# #---------------------------------------------|POSTFIX|-------------------# #---//Management of mail-server Postfix.//--------------------------------#  postfix::manage_conffiles: false postfix_config:     relayhost:         ensure: present         value: "%{lookup('host_address')}"     virtual_maps:         value: hash:/etc/postfix/virtual         ensure: present     sender_canonical_map:         value: hash:/etc/postfix/canonical_sender         ensure: present postfix_hash:     '/etc/postfix/virtual':         ensure: present         content: |           root %{lookup('hostname_admin_emails')}           rails %{lookup('hostname_emails')}     '/etc/postfix/canonical_sender':         ensure: present         content: |             name@%{lookup('my_domain')} name@my_domain.com             root@%{lookup('my_domain')} root@my_domain.com  #----------------------------------------|LOGS|---------------------------# #---------------------------------------------|RSYSLOG|-------------------# #---//Rsyslog is a software utility for forwarding log messages//---------# #---//in an IP network. It implements the basic syslog protocol,//--------# #---//extends it with content-based filtering, rich filtering//-----------# #---//capabilities, flexible configuration options and adds features//----# #---//such as using TCP for transport.//----------------------------------#  rsyslog::client:   log_local: true  my_rsyslog_snippet:   99_everything:     content: "*.*;auth,authpriv.none /var/log/syslog\n"   01_mail:     content: "mail.*  -/var/log/mail.log\n& stop"   02_auth:     content: "auth,authpriv.* /var/log/auth\n& stop"   03_puppetagent:     content: ":programname,contains,\"puppet-agent\" /var/log/puppetlabs/puppet/puppet-agent.log\n& stop"   04_iptables:     content: ":msg,contains,\"IPTABLES INPUT\" /var/log/iptables/iptables.log\n& stop"   05_pam_unix:     content: ":msg,regex,\".*session opened for.*(uid=0)\" /var/log/admin/auth.log\n& stop"   06_sshd:     content: ":msg,regex,\".*publickey for username.*0.0.0.0\" /var/log/admin/auth.log\n& stop  #---------------------------------------------|LOGWATCH|------------------# #---//Logwatch is a log-analysator for create short reports.//------------#  logwatch::format: text logwatch::service:     # Ignore this servie     - -http     - -iptables  #---------------------------------------------|LOGROTATE|-----------------# #---//Management of rotation of log files.//------------------------------#  my_rclogs_path: '/home/hostname/hostname/shared/log' my_rclogs_amazon_path: '/home/hostname1/hostname1/shared/log_amazon' my_ttlogs_path: '/home/hostname2/hostname2/shared/log' my_ttlogs_amazon_path: '/home/hostname/hostname/shared/log_amazon' logrotate::ensure: latest logrotate::config:   dateext: true   compress: true logrotate::rules:   booking-logs:     path: '%{lookup("my_rclogs_path")}/booking_com.log'     size: 2500M     rotate: 20     copytruncate: true     delaycompress: true     dateext: true     dateformat: -%Y%m%d-%s     compress: true     postrotate: mv %{lookup('my_rclogs_path')}/booking_com.log*.gz %{lookup('my_rclogs_amazon_path')}/  #---------------------------------------------|ATOP|----------------------# #---//ATOP service displays a new information about CPU//-----------------# #---//and memory utilization.//-------------------------------------------#  atop::service: true atop::interval: 30  #----------------------------------------|DNS|----------------------------# #---//Management of file /etc/resolv.conf//-------------------------------#  resolv_conf::nameservers:     - 0.0.0.0     - 0.0.0.0  #=========================================================================#   #============================|DATABASES|==================================# #--------------------------------------|MYSQL|----------------------------# #---//MySQL is a relational database management system.//-----------------#  mysql::server::package_ensure: 'installed' #· mysql::server::root_password: "ooy5ieneePahnei" mysql::server::manage_config_file: true mysql::server::service_name: 'mysql' # required for puppet module mysql::server::override_options:   'mysqld':     'bind-address': '*'          "userName": "",         "password": "",         "databaseName": "",  mysql::server::db:   "hostname":     user: ""     password: ""     host: "%"     grant:       - "ALL"  #-------------------------------------|ELASTICSEARCH|---------------------# #---//Elasticsearch is a search engine based on Lucene.//-----------------# #---//It provides a distributed, multitenant-capable full-text search//---# #---//engine with an HTTP web interface and schema-free JSON documents.//-#  elasticsearch::version: 5.5.1 elasticsearch::manage_repo: true elasticsearch::repo_version: 5.x elasticsearch::java_install: false elasticsearch::restart_on_change: true elasticsearch_instance:     'es-01':       ensure:  'present'  #-------------------------------------|REDIS|-----------------------------# #---//Redis is an in-memory database project implementing//---------------# #---//a distributed, in-memory key-value store with//---------------------# #---//optional durability.//----------------------------------------------#  redis::bind: 0.0.0.0  #-------------------------------------|ZOOKEPER|--------------------------# #---//Zooker is a centralized service for distributed systems//-----------# #---//to a hierarchical key-value store, which is used to provide//-------# #---//a distributed configuration service, synchronization service,//-----# #---//and naming registry for large distributed systems.//----------------#  zookeeper::init_limit: '1000' zookeeper::id: '1' zookeeper::purge_interval: '1' zookeeper::servers:   - "%{lookup('host')}"  #-------------------------------------|POSTGRES|--------------------------# #---//Postgres, is an object-relational database management system//------# #---//with an emphasis on extensibility and standards compliance.//-------# #---//As a database server, its primary functions are to store  data//----# #---//securely and return that data in response to requests from other//--# #---//software applications.//--------------------------------------------#  postgresql::server::postgres_password:  postgresql::server::ip_mask_allow_all_users: '0.0.0.0/0'  postgresql::postgresql::server:   ip_mask_allow_all_users: '0.0.0.0/32'  postgres_db:   master:     user:      password:    confluence:     user:      password:  postgres_config:     'max_connections':        value: 300  postgres_hba:     'Allow locals without password':         order: 1         description: 'locals postgres no password'         type: 'host'         address: '127.0.0.1/32'         database: 'all'         user: 'all'         auth_method: 'trust'    #----------------------------------------------|PGBOUNCER|----------------# #---//PgBouncer is a connection pooler for PostgreSQL//-------------------#  pgbouncer::group: postgres pgbouncer::user: postgres pgbouncer::userlist:    - user:        password:   pgbouncer::databases:    - source_db: recommender      host: "%{lookup('')}"      dest_db: recommender      auth_user: recommender      pool_size: 200      auth_pass:     - source_db: master      host: "%{lookup('')}"      dest_db: recommender      auth_user: recommender      pool_size: 50      auth_pass:     - source_db: slave      host: "%{lookup('')}"      dest_db: recommender      auth_user: recommender      pool_size: 200      auth_pass:   #=========================================================================#  #==============================|APPLICATION SERVICES|=====================# #---------------------------------------------------|CONFLUENCE|----------# #---------------------------------------------------|JENKINS|-------------#  #=========================================================================#   

Пример секции мониторинга:

#============================|MONITORING|=================================# #---------------------------------------|ICINGA SERVICES|-----------------# #---//Managment of monitoring system.//-----------------------------------#    icinga2_service:        '%{::fqdn} virtual host' :         target: /etc/icinga2/zones.d/master/%{::fqdn}.conf         apply: true         assign: [ 'host.name == %{::fqdn}' ]         display_name: '%{::fqdn} virtualhost'         check_command: 'http'         vars:             http_uri: /             http_ssl: true             http_vhost: 'hostname'             http_address: "%{lookup('host_address')}"            '%{::fqdn} nginx status' :         target: /etc/icinga2/zones.d/master/%{::fqdn}.conf         apply: true         assign: [ 'host.name == %{::fqdn}' ]         command_endpoint: '%{::fqdn}'         display_name: 'nginx status'         check_command: 'nginx_status'         vars:             nginx_status_host_address: localhost             nginx_status_servername: server.com             nginx_status_critical: '1600,60,30'             nginx_status_warn: '1500,55,25'          '%{::fqdn} redis':         target: /etc/icinga2/zones.d/master/%{::fqdn}.conf         apply: true         assign: [ 'host.name == %{::fqdn}' ]         display_name: 'Redis'         command_endpoint: '%{::fqdn}'         check_command: "redis"         vars:             redis_hostname: localhost             redis_port: 6379             redis_perfvars: '*'    #=========================================================================#  

Общая схема работы такой схемы заключается всего лишь в двух простых действиях:

  1. Запускаем puppet на хосте — хост видит проверки, которые ему принадлежат и экспортирует их в puppetDB.
  2. Запускаем puppet в контейнере icinga2 — проверки из puppetdb превращаются в реальные конфиги Icinga2.

Тут многие скажут: «А зачем мне всё это городить, если я могу поднять обычную icinga2 и добавлять проверки руками или через веб-интерфейс?»

Действительно, если вам нужно мониторить с десяток хостов с сотней сервисов, и вы достаточно аккуратный человек с хорошей памятью (в природе не встречается), то нет смысла городить огород. Совершенно другое дело, если у вас довольно большая инфраструктура и есть ощущение, что вы что-то где-то могли забыть. В такие моменты автоматизация очень сильно помогает, т.к. помогает разложить всё по полочкам и избежать, во многом, человеческого фактора.

Обозначим основные плюсы:

Посмотрим на вот такой шаблон:

icinga2_service:     '%{::fqdn} disk service':         target: /etc/icinga2/zones.d/master/%{::fqdn}.conf         apply: true         assign: [ 'host.name == %{::fqdn}' ]         display_name: 'Disk usage'         command_endpoint: '%{::fqdn}'         check_command: 'disk'         vars:           #All disks           disk_all: true           disk_exclude_type:             - aufs             - tmpfs           disk_ignore_ereg_path:             - /run/docker/*             - /sys/*             - /var/lib/docker*             - /var/lib/ureadahead/debugfs/*             - /run/user/* 

+ 1. Этот шаблон встречается в Hiera только один раз и применяется ко всем хостам в таком виде — т.е. он универсальный. Конфиги на сервере Icinga2, для данного сервиса, будут созданы автоматически для каждого хоста в нашей системе. К тому же, произойдёт создание самих конфигов хостов, ключей, зон и прочей радости.

+ 2. Нам не нужно помнить, добавили мы проверки или нет. Если паппет на хосте был запущен — стандартный набор проверок для этого хоста сгененрирован в нашей системе мониторинга.

+ 3. Мы не переживаем о бекапах нашей системы мониторинга, т.к. все проверки у нас генерируются паппет сервером, и даже при полной потере всех конфигов на сервере Icinga2 их можно будет легко восстановить, запустив puppet на сервере Icinga2.

+ 4. Так так все проверки у нас храняться в единой базе puppetDB мы можем создавать довольно мощные сценарии для дальнейшей автоматизации, в которых будем эту информацию использовать.

Итак, поехали

1. Настроим puppet.

Надеюсь у вас есть настроенный docker и docker-compose.
Если нет, то их необходимо установить:
Установка Docker…
Установка Docker-compose…

2. Склонируем репозиторий к себе на сервер:

git clone http://git.comgress64.com/external/puppet-icinga2-how-to.git 

3. Откроем docker-compose.yaml любимым редактором и посмотрим на него.

Мы видим, что в данной пачке у нас поднимается сразу несколько контейнеров — PuppetServer, PuppetDb, PostgreSQL сервер и PuppetBoard. Так же монтируются volumes из текущей директории. Не для всех эта конфигурация является оптимальной, поэтому учитывайте свою инфраструктуру. У кого-то уже есть PostgreSQL сервер, кто-то хочет хранить код на другом разделе — тут свобода для творчества. На данном этапе я предлагаю оставить шаблон по умолчанию — к нему всегда можно будет вернуться позже. Поднимем нашу пачку контейнеров и посмотрим, что у нас вышло:

4. Запустим контейнер Puppet, Postgres, Puppetdb и Graphite

#Запустим контейнер Puppet, Postgres и Puppetdb #Запустим контейнер Puppet, Postgres, Puppetdb и Graphite cd puppet-icinga2-how-to docker-compose up -d puppet puppetdb-postgres puppetdb graphite  && docker-compose logs -f 

Сейчас у нас загрузилось несколько образов и запустились контейнеры, создались базы данных в PostgreSQL. Дождемся, пока все серверы будут запущены — ошибки можно игнорировать, т.к они через какое-то время должны стабилизироваться. Жмём Ctrl+C, чтобы выйти из режима просмотра логов.

5. Проверим работу нашего puppet master:

 docker run --net puppeticinga2howto_default --link puppet:puppet puppet/puppet-agent 

6. Если все ок, вы увидите вот такой вывод:

     Notice: Applied catalog in 0.03 seconds Changes:             Total: 1 Events:           Success: 1             Total: 1 Resources:           Changed: 1       Out of sync: 1             Total: 8 Time:          Schedule: 0.00              File: 0.00    Transaction evaluation: 0.01    Catalog application: 0.03    Convert catalog: 0.04    Config retrieval: 0.45    Node retrieval: 1.38          Last run: 1532605377    Fact generation: 2.24       Plugin sync: 4.50        Filebucket: 0.00             Total: 8.65 Version:            Config: 1532605376            Puppet: 5.5.1     

Настроим cервер Icinga2.

7. Сделаем образ из Dockerfile, выполнив:

 docker-compose build icinga 

8. Запустим контейнер, в котором у нас будет жить сервер Icinga2.

 docker-compose up -d icinga 

9. Пока что у нас контейнер пустой. Давайте настроим icinga2 сервер при помощи нашего Puppet сервера, выполнив:

 #Сгенерируем модули для puppet запустив librarian-puppet в контейнере puppet docker-compose exec puppet bash -c 'cd /etc/puppetlabs/code && gem install librarian-puppet && librarian-puppet install --verbose' #Запускаем Puppet в контейнере Icinga для первичной конфигурации контейнера docker-compose exec icinga puppet agent --server puppet --waitforcert 60 --test 

10. Установится и сконфигурируется Icinga, Icingaweb2 и Apache.

Ваш сервер Icinga2 готов!

Icingaweb2

1. Давайте посмотрим, что у нас получилось.

Удобно смотреть на состояние системы мониторинга в браузере, выполним:
Откроем в браузере http://ip_адресс_вашего_хоста:8081/icingaweb2 и зайдём в Icinga c дефолтным логином: icingaadmin/icinga.

Видим вот такую картинку:

Через несколько минут мы видим, что у нас все проверки отработали:

Графики тоже работают:

У нас есть рабочая веб-среда для Icinga2, но пока ещё нет ни одного хоста подключённого к Icinga, давайте подключим наш первый хост.

2. Подключим новый хост в систему мониторинга

Сейчас у нас к icinga2 подключен только один хост — сама Icinga. Давайте подключим ещё один.
Показываю на примере в докере, но всё тоже самое будет работать и на голом железе:

Для начала нужно подготовить шаблон и дать некоторую информацию о хосте для puppet:

 #Переходим в директорию шаблонов cd puppet-icinga2-how-to/code/environments/production/hieradata/nodes #Копируем шаблон с новым именем(должен называться именем хоста) cp template.yaml example.com.yaml #Открываем новый фаил любимым редактором и меняем переменные: host_address: 172.18.0.7 my_company: COMGRESS64 my_package_manager: apt my_ssh_port: 22 #Сохраняем фаил и выходим 

Запустим образ докера. Тут самое главное поставить ему hostname такой же как у фаила шаблона, который мы только что создали:

 docker run --hostname example.com --rm -t --link puppet:puppet --net puppeticinga2howto_default -i phusion/baseimage:latest /sbin/my_init -- bash -l 

Установим puppet на нашем хосте:

 apt-get update && apt-get install -y ruby make gcc perl-modules && gem install --no-ri --no-rdoc puppet 

Запускаем puppet:

 puppet agent --server puppet --waitforcert 60 --test 

Сейчас у нас установилась icinga2 на наш новый хост и все проверки для неё выгрузились в базу puppetDB. Давайте их сгенерируем, выполнив puppet в контейнере icinga2:

 docker-compose exec icinga puppet agent --server puppet --waitforcert 60 --test 

Смотрим через браузер, что у нас получилось:

Проверки добавились и ожидают выполнения.
Через 5 минут:

Таким же образом добавляются все остальные хосты в систему. Хочу обратить ваше внимание, что данное руководство является доказательством концепта и не может быть использовано в среде production без доработок.

Если статья покажется интересной, в следующий раз я покажу, как можно добавить всякие интересные кастомные проверки, поделюсь секретами и расскажу про всякие тонкости. Также, если возникнет желание, расскажу более подробно о том как это всё работает изнутри.

Спасибо за внимание!


Ссылка на эту же статью в Confluence:
/Чуть больше форматирования и наглядности./
docs.comgress64.com/…

Ссылки на материал:
https://github.com/Icinga/puppet-icinga2
https://forge.puppet.com/icinga/icingaweb2
https://docs.docker.com/
https://docs.puppet.com/
https://docs.puppet.com/hiera/

FavoriteLoadingДобавить в избранное
Posted in Без рубрики

Добавить комментарий

Ваш e-mail не будет опубликован. Обязательные поля помечены *