Service tomcat

De wiki.nexiat.fr
Aller à la navigation Aller à la recherche
Fiche express
Domaine Script d'init SysV pour Apache Tomcat
Emplacement /etc/init.d/tomcat
Motif de base Service generique3
Alternative moderne unit systemd — voir Systemctl
Voir aussi Service complet · Chkconfig · Java

Trois versions d'un script d'init SysV pour Apache Tomcat, de la plus simple à la plus robuste. Les trois partagent le même motif de base — lancement via su - utilisateur -c script (voir Service generique3), sans passer par la bibliothèque /etc/init.d/functions — mais divergent sur la fiabilité de la détection d'état et la gestion des erreurs.

Version 1 : basique

Application directe du motif Service generique3 à Tomcat : détection par ps/grep, pas de gestion fine des codes retour.

#!/bin/bash
#
# chkconfig: 345 85 15
# description: service tomcat

## Variables
CATALINA_HOME=/opt/tomcat/apache-tomcat-6.0.20
JAVA_HOME=/usr/local/java
TOMCAT_OWNER=tomcat
export CATALINA_HOME JAVA_HOME TOMCAT_OWNER

## Fonctions
start() {
    echo -n "Starting Tomcat: "
    su - "$TOMCAT_OWNER" -c "$CATALINA_HOME/bin/startup.sh"
    sleep 2
}

stop() {
    echo -n "Stopping Tomcat: "
    su - "$TOMCAT_OWNER" -c "$CATALINA_HOME/bin/shutdown.sh"
}

status() {
    numproc=$(ps -ef | grep catalina | grep -v grep | wc -l)
    if [ "$numproc" -gt 0 ]; then
        echo "Tomcat is running..."
    else
        echo "Tomcat is stopped..."
    fi
}

case "$1" in
    start)   start ;;
    stop)    stop ;;
    restart) stop; start ;;
    status)  status ;;
    *)
        echo "Usage: tomcat {start|stop|restart|status}"
        exit 1
        ;;
esac

Correction : les liens wiki [[grep]] insérés directement dans les commandes de l'original cassaient le script une fois copié tel quel — remplacés par grep.

Version 2 : suivi par PID, journalisation

Ajoute une détection par PID (plus fiable que compter les lignes de ps), un réglage d'ulimit, et une trace via logger.

#!/bin/bash
#
# tomcat7     Démarre/arrête Tomcat
#
# chkconfig: 345 85 15
### BEGIN INIT INFO
# Provides: tomcat7
# Required-Start: $network $syslog
# Required-Stop: $network $syslog
# Description: Release implementation for Servlet 2.5 and JSP 2.1
# Short-Description: start and stop tomcat
### END INIT INFO

. /etc/rc.d/init.d/functions

USER=tomcat
APP_NAME=tomcat
JAVA_HOME=/usr/bin/java
LOG_HOME=/var/log/$APP_NAME
PATH=$JAVA_HOME/bin:$PATH
TOMCAT_HOME=/opt/tomcat/$APP_NAME

SHUTDOWN_WAIT=20
RETVAL=0
umask 077

# JAVA_OPTS="-Dfile.encoding=UTF-8 -XX:+UseConcMarkSweepGC -Xms512m -Xmx512m"

tomcat_pid() {
    ps aux | grep "$USER" | grep -v grep | awk '{ print $2 }'
}

start() {
    pid=$(tomcat_pid)
    if [ -n "$pid" ]; then
        echo "Tomcat is already running (pid: $pid)"
        return 0
    fi

    echo "Starting tomcat"
    ulimit -n 100000
    umask 007
    logger -s "Start $APP_NAME"
    su - "$USER" -c "$TOMCAT_HOME/bin/startup.sh"
    return $RETVAL
}

stop() {
    pid=$(tomcat_pid)
    if [ -z "$pid" ]; then
        echo "Tomcat is not running"
        return 0
    fi

    echo "Stopping Tomcat"
    logger -s "Stop $APP_NAME"
    su - "$USER" -c "$TOMCAT_HOME/bin/shutdown.sh"

    count=0
    while ps -p "$pid" > /dev/null 2>&1 && [ "$count" -le "$SHUTDOWN_WAIT" ]; do
        echo -n -e "\nwaiting for process $pid to exit"
        sleep 1
        count=$((count + 1))
    done

    if [ "$count" -gt "$SHUTDOWN_WAIT" ]; then
        echo -n -e "\nkilling process $pid after ${SHUTDOWN_WAIT}s"
        kill -9 "$pid"
    fi

    return $RETVAL
}

version() {
    if [ -f "$TOMCAT_HOME/bin/version.sh" ]; then
        logger -s "Display $APP_NAME Version"
        su -l "$USER" -c "$TOMCAT_HOME/bin/version.sh"
        return $RETVAL
    fi
}

case "$1" in
    start)           start ;;
    stop)             stop ;;
    restart|reload)   stop; start ;;
    status)
        pid=$(tomcat_pid)
        if [ -n "$pid" ]; then
            echo "Tomcat is running with pid: $pid"
        else
            echo "Tomcat is not running"
        fi
        ;;
    version) version ;;
    *)
        echo "Usage: $0 {start|stop|restart|reload|status|version}"
        exit 1
        ;;
esac

exit 0

Bug corrigé : dans le script d'origine, stop() contenait return $RETVAL avant la boucle d'attente d'arrêt (until ... done) — cette boucle et le kill -9 de secours qui la suit n'étaient donc jamais exécutés, code mort après un return prématuré. Le script « fonctionnait » quand même car shutdown.sh suffit en général, mais le filet de sécurité (kill forcé après timeout) ne se déclenchait jamais. Corrigé ici en déplaçant return $RETVAL à la fin de la fonction.

Version 3 : version distribution (paquet RPM tomcat)

Version la plus robuste, proche de celle fournie par les paquets RPM Tomcat historiques (auteurs d'origine cités dans les commentaires du script : Henri Gomez, Keith Irwin, Nicolas Mailhot, réécriture Deepak Bhole et Jason Corley) : bibliothèque LSB, fichier de configuration externe, PID file, gestion de SELinux via runuser, distinction fine des états (arrêté / en cours / fichier PID orphelin).

#!/bin/bash
#
# tomcat6      Démarre/arrête Tomcat
#
# chkconfig: - 80 20
### BEGIN INIT INFO
# Provides: tomcat6
# Required-Start: $network $syslog
# Required-Stop: $network $syslog
# Description: Release implementation for Servlet 2.5 and JSP 2.1
# Short-Description: start and stop tomcat
### END INIT INFO
#
# - originally written by Henri Gomez, Keith Irwin, and Nicolas Mailhot
# - heavily rewritten by Deepak Bhole and Jason Corley

if [ -r /lib/lsb/init-functions ]; then
    . /lib/lsb/init-functions
else
    exit 1
fi

DISTRIB_ID=$(lsb_release -i -s 2>/dev/null)
NAME="$(basename "$0")"

# Sous SELinux, utiliser 'runuser' plutôt que 'su'
if [ -x /sbin/runuser ]; then
    SU="/sbin/runuser -s /bin/sh"
else
    SU="/bin/su -s /bin/sh"
fi

TOMCAT_CFG="/etc/tomcat6/tomcat6.conf"
[ -r "$TOMCAT_CFG" ] && . "$TOMCAT_CFG"
[ -r "/etc/sysconfig/${NAME}" ] && . "/etc/sysconfig/${NAME}"

CONNECTOR_PORT="${CONNECTOR_PORT:-8080}"
TOMCAT_SCRIPT="/usr/sbin/tomcat6"
TOMCAT_PROG="${NAME}"
TOMCAT_USER="${TOMCAT_USER:-tomcat}"
TOMCAT_LOG="${TOMCAT_LOG:-/var/log/${NAME}-initd.log}"
export CATALINA_PID="${CATALINA_PID:-/var/run/${NAME}.pid}"

RETVAL="0"

start() {
    echo -n "Starting ${TOMCAT_PROG}: "
    if [ -f "${CATALINA_PID}" ]; then
        read -r kpid < "${CATALINA_PID}"
        if [ -d "/proc/${kpid}" ]; then
            log_success_msg
            return
        fi
    fi
    touch "$CATALINA_PID" 2>&1 || RETVAL="4"
    [ "$RETVAL" = "0" ] && chown "${TOMCAT_USER}:${TOMCAT_USER}" "$CATALINA_PID"
    [ "$RETVAL" = "0" ] && $SU - "$TOMCAT_USER" -c "${TOMCAT_SCRIPT} start" >> "$TOMCAT_LOG" 2>&1 || RETVAL="4"
    if [ "$RETVAL" = "0" ]; then
        log_success_msg
        touch "/var/lock/subsys/${NAME}"
    else
        log_failure_msg "Error code ${RETVAL}"
    fi
}

stop() {
    echo -n "Stopping ${TOMCAT_PROG}: "
    if [ -f "/var/lock/subsys/${NAME}" ]; then
        $SU - "$TOMCAT_USER" -c "${TOMCAT_SCRIPT} stop" >> "$TOMCAT_LOG" 2>&1 || RETVAL="4"
        if [ "$RETVAL" = "0" ] && [ -f "${CATALINA_PID}" ]; then
            read -r kpid < "${CATALINA_PID}"
            count=0
            while [ -d "/proc/${kpid}" ] && [ "$count" -le "$SHUTDOWN_WAIT" ]; do
                sleep 1
                count=$((count + 1))
            done
            [ "$count" -gt "$SHUTDOWN_WAIT" ] && kill -9 "$kpid"
            log_success_msg
        fi
        rm -f "/var/lock/subsys/${NAME}" "$CATALINA_PID"
    else
        log_success_msg
    fi
}

status() {
    if [ -f "${CATALINA_PID}" ]; then
        read -r kpid < "${CATALINA_PID}"
        if [ -d "/proc/${kpid}" ]; then
            log_success_msg "${NAME} (pid ${kpid}) is running..."
            return
        fi
    fi
    pid="$(pgrep -u "${TOMCAT_USER}" -f "${NAME}")"
    if [ -z "$pid" ]; then
        log_success_msg "${NAME} is stopped"
        RETVAL="3"
    else
        log_success_msg "${NAME} (pid $pid) is running..."
    fi
}

case "$1" in
    start)   start ;;
    stop)    stop ;;
    restart) stop; start ;;
    condrestart|try-restart)
        [ -f "/var/run/${NAME}.pid" ] && { stop; start; }
        ;;
    status) status ;;
    *)
        echo "Usage: $0 {start|stop|restart|condrestart|try-restart|status}"
        RETVAL="2"
        ;;
esac

exit "$RETVAL"

Cette version 3 est nettement plus longue à maintenir mais gère des cas que les deux précédentes ignorent : fichier PID orphelin (process disparu sans nettoyer son verrou), redémarrage sous SELinux, configuration externalisée par instance.

Quelle version choisir

  • Aujourd'hui, sur un système avec systemd (RHEL7+/Debian9+), aucune de ces trois versions n'est le premier choix : une unit systemd dédiée est plus simple à écrire et à maintenir — voir Systemctl pour la syntaxe, et s'appuyer sur l'unit fournie par le paquet Tomcat de la distribution quand elle existe.
  • Sur un système SysV encore en place, la version 2 offre un bon compromis (suivi par PID, sans la complexité de la version 3).
  • La version 3 reste la référence si le script doit gérer plusieurs instances Tomcat sur la même machine ou tourner sous SELinux en mode enforcing.

Voir aussi

  • Service generique3 — motif générique dont ce script est une application concrète
  • Service complet — motif alternatif basé sur la bibliothèque système (daemon/killproc)
  • Chkconfig — enregistrement/activation du service
  • Systemctl — remplacement moderne (unit systemd)
  • Java — environnement d'exécution requis par Tomcat