Le Labo #21 | A la chasse aux démons
24/Jan 2017
Avant de commencer
Il est vrai que le titre peut laisser songeur quant à mon intention.
Non, il n’y a rien de religieux….Mon blog n’a pour sujet que l’informatique.
Dans ce billet, je vais aborder la démonisation (ou daemonization) d’application à l’aide de Salt via des states et des pillars.
Si vous recherchez des formules relatives à l’installation de ces applications, vous en trouverez plein sur internet.
Ce qu’il nous faut
Dans ce labo, je vais avoir besoin de plusieurs serveurs :
- Un serveur Salt
- Deux serveurs sur lequel seront installés Logstash et Elasticsearch ainsi que Salt-Minion
- Les serveurs sur lesquels seront installés logstash et Elasticsearch seront équipés de CentOs 6 et CentOs 7, j’expliquerais pourquoi plus tard.
Comment installer Elasticsearch et Logstash ?
Bon, je ne vais rien vous apprendre, mais les packages sont disponible sur le site officiel…ceci dit, je ne vais pas utiliser les .rpm ou les .deb mais les archives .tar.gz, ce qui me permettra de gérer de bout en bout le processus d’installation et de daemonization.
Donc, une fois ceux-ci téléchargés, on les décompresse dans un dossier bien spécifique :
tar xzf /chemin/vers/archive -C /chemin/vers/dossier
Sur CentOS 6
Similaire à RedHat 6 dans la gestion des services/daemons, les services se trouvent dans le dossier /etc/init.d/ et sont, en fait, de simples executables comme celui qui suit :
Exemple pour ELasticSearch:
#!/bin/bash
export JAVA_HOME=/opt/java
RETVAL=0
ARGS="@0"
prog="elasticsearch"
HOME="/opt/elasticsearch"
CONFIG="/opt/elasticsearch/conf/elasticsearch.yml"
start () {
echo -n $"Starting $prog"
if [ -r "$CONFIG" ]
then
/opt/elasticsearch/bin/elasticsearch > ${HOME}/logs/elasticsearch.log 2>&1 &
RETVAL=$?
PID=$!
echo
[ $RETVAL -eq 0 ] && echo $PID > ${HOME}/run/elasticsearch.pid
}
stop () {
echo -, $"Stopping $prog"
kill 'cat ${HOME}/run/elasticsearch.pid'
RETVAL=$?
echo
[ $RETVAL -eq 0 ] && rm -f ${HOME}/run/elasticsearch.pid
}
status () {
if [ -f ${HOME}/run/elasticsearch.pid]
then
echo "$prog is running with PID : " cat ${HOME}/run/elasticsearch.pid
else
echo "$prog is not running"
fi
}
case "$1" in
start)
start
;;
stop)
stop
;;
restart|reload)
stop
start
;;
*)
echo $"Usage: $0 {start|stop|status|restart|reload}"
exit 1
esac
exit $?
Sur CentOS 7
DE la même manière que CentOS 6 est similaire à RedHat 6 dans la gestion de services, CentOs 7 fait de même que RedHat 7. Les services se trouvent dans /lib/systemd/system et ressemblent à ça :
Exemple pour Logstash
[Unit]
Description=Logstash
After=network.target
[Service]
Environment=LOG_DIR=/opt/logstash/logs
Environment=CONF_DIR=/opt/logstash/conf
Environment=BIN_DIR=/opt/logstash/bin
Environment=PID_DIR=/opt/logstash/run
Environment=JAVA_HOME=/opt/java
User=root
Group=root
ExecStart=
ExecStart=/opt/logstash/bin agent -config ${CONF_DIR}/logstaash.conf
ExecReload=/bin/kill -s HUP ${MAINPID}
ExecStop=/bin/kill -WINCH ${MAINPID}
StandardOutput=journal
StandardError=inherit
LimitBOFILE=65535
TimeoutStopSec=0
KillSignal=SIGTERM
SendSIGKILL=no
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
Via SaltStack
En fait, l’automatisation de la création des démons via Salt sera relativement simple à réaliser, mais j’ai voulu faire quelque chose d’universel qui puisse aussi bien servir pour Logstash que pour Elasticsearch.
J’ai hésité un petit moment entre injecter du jinja, des grains et des pillars…mais il s’avère que les deux derniers sont plus efficace pour mon usage.
Le State
{% set logs = conf.directories.logs %}
{% set daemon = pillar['get'](daemon) %}
{% set osMajorRelease = grains['get'('osmajorrelease')] %}
{% for applicatio, conf in daemon.instance.iteritems() %}
{% set prefix = conf.prefix %}
{% set logs = conf.directories.logs %}
{% set confs = conf.directories.conf %}
{% set pid = conf.directories.pid %}
{% set java = conf.directories.jvm %}
{% set user = conf.user %}
{% set group = conf.group %}
{% set bin = conf.bin %}
{% set script = conf.script %}
{% set install_dir = conf.install_dir %}
{% set command = conf.command %}
{% if osMajorRelease == '7' %}
{{ application }}_systemd_unit:
- name: /lib/systemd/system/{{ application }}.service
- contents:
- '[Unit]'
- Description={{ application }}
- After=network.target
- '[Service]'
- Environment=LOG_DIR={{ prefix }}/{{ application }}/{{ logs }}
- Environment=CONF_DIR={{ prefix }}/{{ application }}/{{ confs }}
- Environment=BIN_DIR={{ prefix }}/{{ bin }}
- Environment=PID_DIR={{ prefix }}/{{ application }}/{{ pid }}
- Environment=JAVA_HOME={{ java.dir }}{{ java.vers }}
- User={{ user }}
- Group={{ group }}
- ExecStart=
- ExecStart={{ install_dir }}/{{ bin }}/{{ command }}
- ExecReload=/bin/kill -s HUP ${MAINPID}
- ExecStop=/bin/kill -WINCH ${MAINPID}
- StandardOutput=journal
- StandardError=inherit
- LimitBOFILE=65535
- TimeoutStopSec=0
- KillSignal=SIGTERM
- SendSIGKILL=no
- SuccessExitStatus=143
- '[Install]'
- WantedBy=multi-user.target
{{ application }}_system_enable:
cmd.run:
- name: if [[ $(systemctl list-unit-files | grep {{ application }} | awk '{print $2}') != 'enabled' ]]; then systemctl enable {{ application }}; fi
{{ application }}_system_reload:
module.run:
- name: service.systemctl_reload
{{ application }}_running:
cmd.run:
- name: systemctl restart {{ application }}
{% else %}
{{ application }}_service_unit:
file.symlink:
- name: /etc/init.d/{{ application }}
- target: {{ prefix }}{{ bin }}{{ script }}
{{ application }}_service_enable:
cmd.run:
- name: if [[ $(chkconfig --list | grep {{ application }} | awk '{print $4}') != "2:on" ]]; then chkconfig {{ application }} on; fi
{{ application }}_service_running:
cmd.run:
name: service {{ application }} start
{% endif %}
{% endfor %}
Le pillar
daemon:
instances:
logstash:
user: root
group: root
install_dir: /opt
prefix: /opt
bin: /logstash/bin/
script: logstash.sh
command: logstash agent --config ${CONF_DIR}/logstash.conf
directories:
logs: /logs
confs: /conf
pids: /run
jvm:
dir: /opt/jdk
vers: 8
elasticsearch:
user: root
group: root
install_dir: /opt
prefix: /opt
bin: /elasticsearch/bin/
script: elasticsearch
command: elasticsearch --pidfile ${PID_DIR}/elasticsearch.pid
directories:
logs: /logs
confs: /conf
pids: /run
jvm:
dir: /opt/jdk
vers: 8
Pour finir
Avec tout cela, vous avez un petit avant-goût de ce qui est faisable avec Salt. Certes, je me suis limité à quelque chose de relativement simple, le tout est de savoir comment organiser les données pour, par la suite, les sortir et les pillariser avec Salt.