Während wir unseren Icinga2-Core mittlerweile funktionsfähig haben, wollen wir auch mal einen Blick auf unsere Checks werfen.
Hier hat man dann die Wahl zwischen dem klassischen UI, welches man noch von Nagios oder Icinga1 kennt, oder dem moderneren IcingaWeb2. Ich empfehle hier IcingaWeb2. Nicht nur wegen dem fancy Aussehen, sondern weil es auch noch ein CLI Tool mitbringt. :)
IcingaWeb2 ist eine PHP basierte Webanwendung. Wir benötigen also neben dem reinen IcingaWeb Paket auch noch einen Webserver und PHP. Da ich mich mittlerweile vom Apache abgewandt und vermehrt nginx einsetze, werde ich das auch hier nutzen.
Beim schreiben ist mir aufgefallen, dass dieser eine Part doch umfangreicher als gedacht geworden ist. Ich werde also ggf. einen zweiten Teil schreiben müssen, da mir selbst ein paar Dinge fehlen.
Falls jemand Anregungen haben sollte, der kann gern die Kommentarfunktion nutzen, oder mir einfach eine EMail schreiben.
Vorbereitungen
Bevor wir an die hiera Konfiguration gehen, müssen wir uns erst einmal die benötigten puppet-Module
besorgen.
Da ich als Distribution etwas Debian basiertes nutze, beziehe ich mich hier auch auf dessen
Paketmanagement, für rpm basierendes kann ich auf Wunsch gern etwas nachliefern.
Diese lassen sich einfach folgendermaßen in das eigene Module Verzeichniss installieren (ggf.
mit sudo
arbeiten):
- apt
puppet module install puppetlabs-apt
- php-fpm
git clone https://github.com/bodsch/puppet-phpfpm /etc/puppet/modules/phpfpm
- nginx
puppet module install jfryman-nginx
(alternativ muss man das modul von github clonen) - memcached
puppet module install saz-memcached
(alternativ muss man das modul von github clonen) - icingaweb2
git clone https://dev.icinga.org/projects/puppet-icingaweb2 /etc/puppet/modules/icingaweb2
Nach der Installation der benötigten Pakete (und deren Abhängigkeiten) können wir endlich los legen.
apt
Wir benötigen einige Pakete, die nicht im offiziellen Zweigen zu finden sind, daher fangen wir damit an, die nötigen Repositories zu integrieren:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
# --------------------------------------------------------------
# = APT
apt::sources:
dotdeb:
location: http://ftp.hosteurope.de/mirror/packages.dotdeb.org
repos: all
include_src: false
key: 6572BBEF1B5FF28B28B706837E3F070089DF5277
debmon:
location: http://debmon.org/debmon
release: debmon-%{::lsbdistcodename}
repos: main
include_src: false
key: 7E55BD75930BB3674BFD6582DC0EE15A29D662D2
Bei der Integration in das puppet-Modul nutzen wir ein spezielles Feature von puppet, das ‚UFO‘:
1
2
3
4
5
6
# APT
include apt
Package <| |> {
require => Class[ 'apt' ]
}
Die Package <| |> ...
Notation zwingt puppet vor dem Aufruf von jedem package{ ... }
, welcher
der Installation von Paketen dient, die Klasse apt
aufzurufen.
Dadurch werden die Repositories zuerst angezogen und erst danach versucht das Paket zu installieren.
Das Repository dotdeb
stellt eine aktuelle PHP Version zur Verfügung, debmon
beinhaltet das
icingaweb2 Paket.
Memcached
Da es das einfachste ist, den memcached gleich zum Anfang. Die hiera Konfiguartion:
1
2
3
4
5
6
# --------------------------------------------------------------------------
# == memcached
memcached::listen_ip: '127.0.0.1'
memcached::max_connections: 512
memcached::logfile: /var/log/memcached.log
memcached::max_memory: 64
Hier reicht ein simples include memcached
und fertig.
PHP
PHP-FPM ist etwas kniffliger.
Hintergrundinformationen
Traditionell (im Apache Kontext) wird PHP als Modul (
mod_php
)genutzt. D.h. bei jedem Aufruf wird der PHP-Interpreter gestartet und dann dem Request das ganze wieder weggeworfen. Und das passiert bei jedem Request, der beim Apachen ankommt. Das kostet Zeit und Ressouren .. Zudem läuft der Interpreter immer mit den Rechten des Webservers. Beim php-fpm läuft das ganze im Hintergrund als eigener Prozess. Der PHP-Interpreter wird nur ein einziges Mal gestartet und ist über einen UNIX-Socket oder eine IP:Port erreichbar. Somit entfällt das ständige Neustarten des Interpreters und – als Zugabe sozusagen – man kann den PHP-Interpreter als eigenen User starten, was noch einmal ein Mehrwert bei der Sicherheit bringen kann. Vom Aufbau eines Pools für verschiedene Applikationen will ich gar nicht erst anfangen. Interessanterweise ist man auf dem Einsatz von php-fpm angewiesen, wenn man sich vom Apachen abwendet.
Unsere hiera Konfiguration sollte ungefähr so aussehen:
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
# --------------------------------------------------------------------------
# == PHP-FPM
phpfpm::logdir: /var/log/php-fpm
phpfpm:
ensure: present
poold_purge: true
error_log: "%{hiera('phpfpm::logdir')}/error.log"
phpfpm::log_level: notice
phpfpm::emergency_restart_threshold: 10
phpfpm::emergency_restart_interval: 30
phpfpm::process_control_timeout: 5
phpfpm::process_max: 32
phpfpm::pools::defaults:
listen: /var/run/php5-fpm-$pool.sock
user: www-data
group: www-data
slowlog: /var/log/php-fpm/$pool/slow.log
request_slowlog_timeout: 30s
request_terminate_timeout: '120s'
catch_workers_output: 'yes'
phpfpm::pools:
worker-01:
php_flag:
display_errors: 'off'
php_admin_flag:
expose_php: 'off'
php_admin_value:
upload_max_filesize: '8M'
max_execution_time: 300
log_errors: 'off'
date.timezone: '"Europe/Berlin"'
memory_limit: '256M'
error_log: /tmp/php-fpm-worker-01-error.log
session.save_handler: 'memcached'
session.save_path: '"127.0.0.1:11211"'
Hier wird über hiera die Basiskonfiguration des PHP-FPM definiert.
Zusätzlich richten wir einen eigenen worker
(worker-01) ein, der unter /var/run/php5-fpm-worker-01.sock
einen Socket zur Kommunikation zur Verfügung stellt.
Logfiles werden unterhalb von /var/log/php-fpm/worker-01/
weggeschrieben.
Als Session Handler verwenden wir den zuvor installierten Memcached.
Die Integration in unser puppet-Modul geschieht dann folgendermaßen:
1
2
3
4
5
6
7
8
9
# PHP-FPM
include phpfpm
$pools = hiera_hash( phpfpm::pools, undef )
$pools_defaults = hiera_hash( phpfpm::pools::defaults, undef )
if( $pools ) {
if( $pools_defaults ) { create_resources( phpfpm::pool, $pools, $pools_defaults ) }
else { create_resources( phpfpm::pool, $pools ) }
}
nginx
Als nächstes folgt die Installation des nginx.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
# --------------------------------------------------------------------------
# == nginx
nginx::configtest_enable: true
nginx::confd_purge: true
nginx::vhost_purge: false
nginx::server_tokens: 'off'
nginx::http_access_log: '/var/log/nginx/access.log main'
nginx::nginx_error_log: '/var/log/nginx/error.log info' # notice | debug | info | ...
nginx::worker_processes: 1
nginx::keepalive_timeout: 65
nginx::log_format:
main: '$remote_addr - $remote_user [$time_local] "$request" $status $body_bytes_sent "$http_referer" "$http_user_agent" "$http_x_forwarded_for"'
nginx::conf::proxy_buffers: '64k'
nginx::nginx_vhosts:
icingaweb2:
ensure: present
server_name:
- "%{::fqdn}"
- "mon.%{::domain}"
listen_port: 80
www_root: /usr/share/icingaweb2/public
index_files:
- index.php
- index.html
nginx::nginx_locations:
icingaweb2:
ensure: present
vhost: icingaweb2
location: '~ ^/icingaweb2/index\.php(.*)$'
location_custom_cfg:
fastcgi_pass: unix:/var/run/php5-fpm-worker-01.sock
fastcgi_index: index.php
include: fastcgi_params
fastcgi_param SCRIPT_FILENAME: /usr/share/icingaweb2/public/index.php
fastcgi_param ICINGAWEB_CONFIGDIR: /etc/icingaweb2
icingaweb2_2:
ensure: present
vhost: icingaweb2
location: '~ ^/icingaweb2(.+)?'
location_custom_cfg:
alias: /usr/share/icingaweb2/public
index: index.php
try_files: '$1 $uri $uri/ /icingaweb2/index.php$is_args$args'
favicon:
vhost: icingaweb2
location: '= /favicon.ico'
location_custom_cfg:
log_not_found: 'off'
access_log: 'off'
expires: 'max'
Die Integration im puppet-Modul erfolgt dann über ein einfaches include nginx
Icinga Web 2
Die entsprechende hiera Konfiguration ist ziemlich kurz. Als Installationsquelle wählen wir
package
wo durch das passende Paket genutzt wird. Es gibt auch noch git
zur Auswahl, welches
dann logischerweise ein git clone
des Code-Repositorys ausführt. Hierzu muss dann aber auch
noch das Paket git
installiert werden.
IcingaWeb2 nutzt zum einen den Datenbestand, den icinga2 in seine IDO-Datenbank schreibt um
die Resultate und eine Historie anzuzeigen, zum anderen ein davon unabhängiges Datenbankschema
um Benutzer zu pflegen.
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
# --------------------------------------------------------------------------
# == icingaweb2
icingaweb2::install_method: package
icingaweb2::ido_db : "%{hiera('icinga2::ido_db')}"
icingaweb2::ido_db_host : "%{hiera('icinga2::ido_db_host')}"
icingaweb2::ido_db_name : "%{hiera('icinga2::ido_db_name')}"
icingaweb2::ido_db_pass : "%{hiera('icinga2::ido_db_pass')}"
icingaweb2::ido_db_user : "%{hiera('icinga2::ido_db_user')}"
icingaweb2::ido_type : "%{hiera('icinga2::ido_type')}"
icingaweb2::web_db : "%{hiera('icinga2::web_db')}"
icingaweb2::web_db_host : "%{hiera('icinga2::web_db_host')}"
icingaweb2::web_db_name : "%{hiera('icinga2::web_db_name')}"
icingaweb2::web_db_pass : "%{hiera('icinga2::web_db_pass')}"
icingaweb2::web_db_prefix : "%{hiera('icinga2::web_db_prefix')}"
icingaweb2::web_db_user : "%{hiera('icinga2::web_db_user')}"
Die puppet-Modul integration ist denkbar einfach: include icingaweb2
.
Nach dem Aufruf von http://$WEBBROWSER/icingaweb2/
Ab diesem Zeitpunkt haben wir die aktuellen Möglichkeiten des IcingaWeb2 puppet-Modules fast ausgeschöpft. Es gibt noch die Möglichkeit Rollen für ein Berechtigungskonzept zu konfigurieren oder den LiveStatus einzubinden:
1
2
3
4
5
6
7
8
9
10
11
icingaweb2::config::roles:
full-admins:
role_users: bodsch
role_permissions: '*'
users:
role_users: foo,bar
role_permissions: 'monitoring/command/*'
icingaweb2::config::resource_livestatus:
livestatus:
resource_socket: /var/run/icinga2/cmd/livestatus
Mit der Erweiterung in unserem puppet-Modul:
1
2
3
4
5
6
7
# IcingaWeb2 - Roles
$icingaweb_roles = hiera_hash( icingaweb2::config::roles, undef )
if( $icingaweb_roles ) { create_resources( icingaweb2::config::roles, $icingaweb_roles ) }
# IcingaWeb2 - LiveStatus
$icingaweb_livestatus = hiera_hash( icingaweb2::config::resource_livestatus, undef )
if( $icingaweb_livestatus ) { create_resources( icingaweb2::config::resource_livestatus, $icingaweb_livestatus ) }
WAS bei dem bis jetzt erstellten Setup noch fehlt ist die Benutzerauthentifizierung! Initial würde man das bestimmt über die Datenbank machen, allerdings wurden die entsprechenden Tabellen nicht über puppet angelegt. Möglicherweise ein Bug, oder Zeit für einen Pull-Request ;)
Per Hand kann man das folgendermaßen machen:
1
root@mon:~# mysql icinga2_auth < /usr/share/icingaweb2/etc/schema/mysql.schema.sql
Anschließend muß man sich noch seinen User - auch per Hand - in die Datenbank schreiben. Dazu muß das Passwort entsprechend verschlüsselt werden:
1
2
openssl passwd -1 "vollgeheimes-ding"
echo "insert into icingaweb_user values ( 'bodsch', '1', '\$1\$FI6haHHl\$yQ4wO0ZdkxXfUNs2rOEjM.', now(), now() );" | mysql icinga2_auth
Man beachte die escapten Dollarzeichen! Das ist WICHTIG!
Jetzt fehlt nur noch noch das aktivieren der ersten Module