Une unit systemd pour le Solr embarqué dans EzPublish
EzPublish est un CMS open-source basé sur Symfony, qui traîne ses guêtres depuis quelques années déjà. Via son extension ezfind, il embarque un moteur Solr pour servir de moteur de recherche externe (plus rapide que la base de données). Si des scripts de démarrage sont proposés pour différents OS, il ne sont pas exploitables sur CentOS 7, et il a fallu pondre une solution alternative. Je me suis reposé sur systemd. L’occasion de voir une de ses forces.
Le client veut utiliser Solr : soit. Malgré le fait que c’est du Java, si l’on sait où on va c’est un outil puissant et performant pour les recherches et l’indexation sur le site. En plus il est déjà fourni avec EzPublish, pourquoi se priver ? Sauf que l’extension commence à dater et les options pour le démarrer ne sont pas super pratiques. En l’occurrence voilà le script qu’utilise le client (enfin, plus précisément l’agence web) :
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 |
#!/bin/bash for JAVA in "$JAVA_HOME/bin/java" "/usr/bin/java" "/usr/local/bin/java" do if [ -x $JAVA ] then break fi done if [ ! -x $JAVA ] then echo "Unable to locate java. Please set JAVA_HOME environment variable." exit fi # start solr exec $JAVA -jar start.jar |
Ça va à l’essentiel, pour le lancer en arrière plan il fallait jouer avec du nohup et de l’esperluette, et c’est pas pratique pour en faire un script de démarrage/extinction automatique. Il se trouve cependant qu’il y a un script dans un sous-dossier d’ezfind pour le démarrage, dédié à RedHat et dérivés (donc CentOS), et il a cette tronche :
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 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 |
#!/bin/bash # # eZ Find init script for RHEL and CENTOS. # # Usage: # # Set the correct SOLR_HOME value, and copy this file to /etc/init.d, then # - either run chkconfig --add solr, or # - symlink to /etc/init.d/solr to /etc/rc3.<n>/S70solr and /etc/rc5.<n>/k70solr # # Example: # cp solr /etc/init.d/solr # cd /etc/init.d && chmod 755 solr # cd /etc/rc3.d && ln -s ../init.d/solr S70solr # cd /etc/rc5.d && ln -s ../init.d/solr S70solr # cd /etc/rc3.d && ln -s ../init.d/solr K70solr # cd /etc/rc5.d && ln -s ../init.d/solr K70solr # # # chkconfig: 2345 64 36 # description: SOLR indexing server # processname: solr # pidfile: /var/run/solr.pid DESC="Solr indexing server" NAME=solr SOLR_HOME= # Set solr home here (example: /var/www/ezpublish/extension/ezfind/java) JAVA_HOME= # Set java home here if java is not available in /usr/bin/java or /usr/local/bin/java source /etc/rc.d/init.d/functions for JAVA in "$JAVA_HOME/bin/java" "/usr/bin/java" "/usr/local/bin/java" do if [ -x "$JAVA" ] then break fi done if [ ! -x "$JAVA" ] then echo "Unable to locate java. Please set JAVA_HOME environment variable." exit fi RETVAL=0 d_start() { CURRENT_DIR=`pwd` cd "$SOLR_HOME" daemon --check "$NAME" --pidfile "/var/run/$NAME.pid" nohup $JAVA -jar start.jar > /dev/null 2>&1 & cd "$CURRENT_DIR" sleep 1 # Sleep 1 second, to make sure java is registered. # Using pidof is not good, as there might be other java processes as well. # Replaced this by calling ps. Still, this is somewhat awkward. # 2014-10-10 alex.schuster@ez.no #pid=`pidof java` pid=`ps ax | grep '[/]usr/bin/java -jar start.jar' | grep -v nohup | awk '{ print $1 }'` if [ -z $pid ] then echo "Error starting $NAME!" return 1 fi echo $pid > "/var/run/$NAME.pid" touch "/var/lock/subsys/$NAME" return 0 } d_stop() { killproc -p /var/run/solr.pid "$NAME" >> /dev/null 2>&1 RETVAL=$? [ $RETVAL -eq 0 ] && rm -f "/var/lock/subsys/$NAME" return $RETVAL } d_restart() { d_stop > /dev/null 2>&1 sleep 1 d_start > /dev/null 2>&1 } d_reload() { killproc -p /var/run/solr.pid "$NAME" -HUP > /dev/null 2>&1 RETVAL=$? return $RETVAL } d_status() { status -p /var/run/solr.pid "$NAME" > /dev/null 2>&1 return $? } case "$1" in start) echo " * Starting $DESC ($NAME)" d_status if [ $? -eq 0 ] then echo " ...already running." else if d_start then echo " ...done." else echo " ...failed." RETVAL=1 fi fi ;; stop) echo " * Stopping $DESC ($NAME)" if d_stop then echo " ...done." else echo " ...failed." RETVAL=1 fi ;; restart) echo " * Restarting $DESC ($NAME)" d_status if [ $? -ne 0 ] then echo " ...not running." RETVAL=1 else if d_restart then echo " * ...done." else echo " * ...failed." RETVAL=1 fi fi ;; reload) echo " * Reloading $DESC ($NAME): " d_reload echo " ...done." ;; status) d_status if [ $? -eq 0 ] then echo " * $DESC ($NAME) is running" else echo " * $DESC ($NAME) is not running" fi ;; *) echo $"Usage: $0 {start|stop|restart|reload|status}" RETVAL=1 esac exit $RETVAL |
Là au moins on a la structure d’un script de démarrage qui a de la gueule. J’ai tenté de l’exécuter, systemd a pris le relai, et a échoué. Après coup, et en analysant le fichier, ça ne risquait pas de fonctionner, et ce n’est pas la faute de systemd : la commande daemon présente dans le script n’existe plus sur CentOS 7. Après quelques tergiversations, des recherches Google, et un ou deux fails dont j’ai le secret, j’ai fini par pondre une unit systemd que je me permet de partager avec vous :
unit final
1 2 3 4 5 6 7 8 9 10 11 12 13 |
[Unit] Description=Apache SOLR After=syslog.target network.target remote-fs.target nss-lookup.target [Service] PIDFile=/var/run/solr.pid WorkingDirectory=/home/sites_web/client/www/solr ExecStart=/usr/bin/java -jar start.jar User=www-data ExecReload=/bin/kill -s HUP $MAINPID ExecStop=/bin/kill -s QUIT $MAINPID PrivateTmp=true [Install] WantedBy=multi-user.target |
Attardons-nous sur les directives :
- After permet de décrire les dépendances du service; systemd compile toutes les lignes After et Before pour construire un arbre de dépendances afin de lancer un max de services en parallèle tout en s’assurant qu’ils ne manquent de rien, ici les besoins sont basiques;
- WorkingDirectory Permet de définir un dossier dans lequel travailler; le script du client était lancé directement dans ce dossier, et surtout assumait qu’il était lancé depuis ce dossier;
- ExecStart est la ligne qui permet de lancer le service; j’ai repris la commande du script d’origine, ce qui est amplement suffisant.
Si on compare la taille de ce fichier avec le script d’init « à l’ancienne », on comprend l’une des forces de systemd. La ligne de lancement est également réduite à l’essentiel, à comparer avec les bricolages à base de nohup et d’esperluette pour obtenir un processus qui ressemble à un service. Le nombre de lignes est beaucoup, beaucoup plus petit et c’est une bonne chose pour la lisibilité. systemd s’occupe tout seul de la journalisation, de la construction des dépendances, tout ce que vous avez à faire est de définir s’il doit démarrer ou pas avec le reste des services.
En tout cas, vous pourrez tenter de réutiliser ce script pour construire vos propres services. Pour ma part j’ai dans l’idée de reprendre de zéro le développement de l’API pour la refonte de ma base de données de films, toujours en Python, avec Flask, Bottle n’ayant pas bougé d’un pouce depuis quelques années. Je pense qu’il sera mis à contribution pour gérer son lancement.