[Из песочницы] Автоматизация системы мониторинга на базе Icinga2 и Puppet
Поговорим немного о… Infrastructure as code (IaC).
На Хабре есть несколько очень хороших статей про Icinga2, есть также отличные статьи про Puppet:
Icinga2 простой вариант
Поднимаем микромониторинг на icinga2 с минимальными затратами
Настройка современного Puppet сервера с нуля
Однако тема автоматизации и интеграции этих двух потрясающих систем совсем не раскрыта.
В данном руководстве, я покажу на «живом» примере, как можно, объединив эти две
системы, получить мощный инструмент мониторинга вашей инфраструктуры со всем набором необходимых функций. Статья является своего рода руководством к действию по установке пакета «все в одном флаконе». После выполнения этого руководства у вас в наличии будет полностью рабочее решение мониторинга, которое в дальнейшем можно будет «допиливать» под себя. Давайте попробуем!
Мы подняли новый хост. И нам нужно:
1. Чтобы его мониторинг автоматически появился в Icinga2, и создались базовые проверки:
2. Добавлять кастомные проверки на различные сервисы в удобном и понятном виде. Что бы потом директору показать какие мы молодцы и премию получить!
Некоторые примеры:
Сервис |
YAML-код проверки |
---|---|
Virtual host
Проверяем «живой» хост или нет. |
|
PostgreSQL
Проверяем, что мы можем соединиться с БД PostgreSQL. |
|
Nginx Status
Мониторим статус Nginx через stub_status. |
|
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: '*'
#=========================================================================#
Общая схема работы такой схемы заключается всего лишь в двух простых действиях:
- Запускаем puppet на хосте — хост видит проверки, которые ему принадлежат и экспортирует их в puppetDB.
- Запускаем 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/