Java Server als Daemon auf Debian Linux

Ich habe einige Tage nach einer einfachen Möglichkeit gesucht, meine Java Programme als Daemon auf Debian Linux zu starten. Es gibt einiges an Scripten für SuSe und davon auch Portierungen auf Debian. Allerdings fand‘ ich diese Implementierungen immer unnötig kompliziert und unübersichtlich.

Gestern bin ich endlich auf eine einfache und klar programmierte Lösung gestossen. Ein einfacher Wrapperskript der alle benötigten Funktionen unterstützt. Der Skript ist von 2009 läuft aber noch einwandfrei. Allerdings ist er nicht auf Debian spezialisiert und ist für die KSH geschrieben. Ich bin mal alles durchgegangen und habe einige Anpassungen gemacht. Herausgekommen ist folgende Debian interpretation:

#! /bin/sh
### BEGIN INIT INFO
# Provides:          skeleton
# Required-Start:    $remote_fs $syslog $network
# Required-Stop:     $remote_fs $syslog $network
# Default-Start:     2 3 4 5
# Default-Stop:      0 1 6
# Short-Description: Java Daemon Script
# Description:       This file should be used to construct scripts to be
#                    placed in /etc/init.d.
### END INIT INFO

# Author: Jens Heuschkel <jens@3und20.eu>

# Do NOT "set -e"

# PATH should only include /usr/* if it runs after the mountnfs.sh script
PATH=/sbin:/usr/sbin:/bin:/usr/bin

APP_NAME="MyApp"
APP_LONG_NAME="My App Server"

#the location of the pid files.
PIDDIR="/var/run"
PIDFILE="${PIDDIR}/${APP_NAME}.pid"
TIMESTAMP=$( date +%Y%m%d_%H%M%S )

#number of seconds to wait after starting up.
WAIT_AFTER_STARTUP=2

#the location of the log files
LOG_DIR="/var/log"
STDOUT="${LOG_DIR}/${APP_NAME}.stdout.log"

#PURGE_EXPRESSION="-mtime +2"
PURGE_EXPRESSION="${LOG_DIR}/${APP_NAME}*"

HEAPSIZE_INIT=16
HEAPSIZE_MAX=100
VMARGS="-Xms${HEAPSIZE_INIT}M -Xmx${HEAPSIZE_MAX}M -verbose:gc"
MAINCLASS="com.wordpress.jensheuschkel.MyApplication"
JARFILE="MyApp.jar"
ARGS=""

JAVA_COMMAND="/usr/bin/java"

# Startup with Classpath
#START_COMMAND="${JAVA_COMMAND} $VMARGS $MAINCLASS $ARGS"
# Startup with jar
START_COMMAND="${JAVA_COMMAND} $VMARGS -jar ${JARFILE} ${ARGS}"
#-----------------------------------------------------------------------------
# Do not modify anything beyond this point
#-----------------------------------------------------------------------------

checkroot() {
 if [[ $EUID -ne 0 ]]; then
  echo "This script must be run as root" 1>&2
  exit 1
 fi
}

getpid() {
  pid=""
  if [ -f "$PIDFILE" ]
  then
    if [ -r "$PIDFILE" ]
    then
      pid=`cat "$PIDFILE"|cut -d: -f1`
      host=`cat "$PIDFILE"|cut -d: -f2`
      currhost=`hostname`
      if [ "$host" != "$currhost" ]
      then
       echo "You are on the wrong host. $APP_LONG_NAME runs on $host."
       exit 1
      fi

      if [ "X$pid" != "X" ]
      then
       kill -0 $pid > /dev/null 2>&1
  if [ $? -ne 0 ]
  then
   # Process doesn't exist, so remove pidfile
   rm -f "$PIDFILE"
            echo "Removed stale pid file: $PIDFILE"
   pid=""
  fi
      fi
    else
      echo "Cannot read $PIDFILE."
      exit 1
    fi
  fi
}

#tests if the pid is alive
testpid() {
  kill -0 $pid > /dev/null 2>&1
  if [ $? -ne 0 ]
  then
   # Process is gone so remove the pid file.
 rm -f "$PIDFILE"
 pid=""
  fi
}

start() {
  echo "Starting $APP_LONG_NAME..."
  getpid
  if [ "X$pid" = "X" ]
  then
    if [ -s $STDOUT ]
    then
     #backup current file
     mv $STDOUT $STDOUT.sav.${TIMESTAMP}
    fi
    echo CLASSPATH is $CLASSPATH > $STDOUT
    echo ${START_COMMAND} >> $STDOUT
    nohup ${START_COMMAND} >> $STDOUT 2>&1 &
    echo $!:`hostname` > $PIDFILE
  else
    echo "$APP_LONG_NAME is already running."
    exit 1
  fi

  # Sleep for a few seconds to allow for intialization if required
  # then test to make sure we're still running.
  i=0
  while [ $i -lt $WAIT_AFTER_STARTUP ]
  do
    sleep 1
    i=`expr $i + 1`
  done
  if [ $WAIT_AFTER_STARTUP -gt 0 ]
  then
    getpid
    if [ "X$pid" = "X" ]
    then
      echo "WARNING: $APP_LONG_NAME may have failed to start."
      exit 1
    else
      echo "running ($pid)."
    fi
  else
    echo ""
  fi
}

stopit() {

  echo "Stopping $APP_LONG_NAME..."
  getpid
  if [ "X$pid" = "X" ]
  then
    echo "$APP_LONG_NAME was not running."
  else
    # Running so try to stop it.
    kill $pid
    if [ $? -ne 0 ]
    then
      echo "Unable to stop $APP_LONG_NAME."
      exit 1
    fi

    #  If it has not stopped in 10 tries, forcibly kill it
    savepid=$pid
    CNT=0
    TOTCNT=0
    while [ "X$pid" != "X" ]
    do
      # Show a waiting message every 5 seconds.
      if [ "$CNT" -lt "5" ]
      then
        CNT=`expr $CNT + 1`
      else
        echo "Waiting for $APP_LONG_NAME to exit..."
        CNT=0
      fi

      if [ $TOTCNT -gt 11 ]
      then
       echo "Killing by force (kill -9)"
       kill -9 $pid
      fi

      TOTCNT=`expr $TOTCNT + 1`
      sleep 1

      testpid
    done

    pid=$savepid
    testpid
    if [ "X$pid" != "X" ]
    then
      echo "Failed to stop $APP_LONG_NAME."
      exit 1
    else
      echo "Stopped $APP_LONG_NAME."
    fi
  fi
}

purge() {
#  pcmd="find $LOG_DIR -follow -type f $PURGE_EXPRESSION -print -exec rm -f {} +"
  pcmd="rm -f ${PURGE_EXPRESSION}"
  echo "Running purge: $pcmd"
  $pcmd
}

alert() {
  if [ "X$EMAIL" != "X" ]
  then
   echo "$APP_LONG_NAME is not running on `hostname`. Please check and restart." \
   | mailx -s "`hostname`: $APP_LONG_NAME is not running" "$EMAIL"
   echo "Sent alert to $EMAIL"
  fi
}

status() {
  getpid
  if [ "X$pid" = "X" ]
  then
    echo "$APP_LONG_NAME is not running."
    alert
    exit 1
  else
    echo "$APP_LONG_NAME is running (PID:$pid)."
    exit 0
  fi
}

dump() {
  echo "Dumping $APP_LONG_NAME..."
  getpid
  if [ "X$pid" = "X" ]
  then
    echo "$APP_LONG_NAME is not running."
  else
    kill -3 $pid

    if [ $? -ne 0 ]
    then
      echo "Failed to dump $APP_LONG_NAME."
      exit 1
    else
      echo "Dumped $APP_LONG_NAME."
    fi
  fi
}

####################

checkroot

case "$1" in

  'start')
    start
    ;;

  'stop')
    stopit
    ;;

  'restart')
    stopit
    start
    ;;

  'status')
    status
    ;;

  'dump')
    dump
    ;;

  'purge')
    purge
    ;;

  *)
    echo "Usage: $0 { start | stop | restart | status | dump | purge }"
    exit 1
    ;;
esac

exit 0

 

Die VM Einstellungen sind für das Rapberry Pi und sollten noch angepasst werden. Es wird auch nicht gecheckt ob JAVA installiert ist aber das kann man ja im Install-Skript des Servers machen 😉

Quelle:
http://fahdshariff.blogspot.de/2009/09/unix-wrapper-script-for-java.html

Advertisements

3 Kommentare zu “Java Server als Daemon auf Debian Linux

  1. Hallo Jens,
    Dein Script ist genau das, was ich gesucht habe :-). Ich habe einen Server-Dienst derzeit nur in Java verfügbar und möchte ihn auf dem Raspberry Pi starten lassen.
    Bisher funktioniert alles ganz gut, nur erhalte ich eine Fehlermeldung in Zeile 56: [[: not found.

    Hat es einen Grund, warum Du hier zwei eckige Klammern benutzt?

    Grüße,
    Siegmund

    • Hi,
      ja das hat irgend einen Grund den ich aber vergessen habe:D. Wie im Artikel beschrieben, ist das eine Adaption von einem anderen Skript; vllt. findest du in der Quelle einen Hinweis warum dort zwei Klammern nötig sind. Alternativ kannst du mal in der Bash Syntax nachsehen 😉

      Allerdings ist mir der Fehler auf dem Pi auch schon unter gekommen. Das liegt daran, dass das Raspbian scheinbar diese Variable nicht unterstützt. Mit folgendem Code sollte es laufen:

      checkroot() {
       if [ $(id -u) -ne 0 ] 
       then
        echo "This script must be run as root" 1>&2
        exit 1
       fi
      }
      
  2. Hallo Jens,

    1)
    habe das schon getan ;-). Allerdings ist es noch sicherer, Apostrophe zu verwenden:
    if [ „$(id -u)“ -ne „0“ ]

    2)
    Damit das script /usr/bin/service mit dem Dienst zurechtkommt, müssen noch ein paar weitere Änderungen gemacht werden:

    Zunächst mal habe ich die InitFunctions eingebunden:
    . /lib//lsb/init-functions

    Dann habe ich nur die PID ins PID-File geschrieben, nicht den Hostnamen und dann bei getpid() die Prüfung vereinfacht::
    pid=’cat „$PIDFILE“
    (Ich sehe das zum ersten Mal – wofür ist die Host-Prüfung überhaupt notwendig?)

    Analog dazu wird bei start() natürlich nicht mehr der Hostname miteingetragen:
    echo $! > $PIDFILE

    Die Funktion status() wird gar nicht benötigt, das kann man ebenfalls machen mit:
    status_of_proc -p $PIDFILE $JAVA_COMMAND $APP_NAME && exit 0 || exit $?

    Zu guter Letzt sollten in der letzten case-Anweisung die Hochkommas entfernt werden, da ansonsten „service –status-all“ fehlschlägt:
    ’status)‘ wird also zu status)
    usw.

    Mit diesen Änderungen funktionieren nun auch
    service –status-all
    service MyJavaDaemon start
    service My JavaDaemon stop
    service MyJavaDaemon status
    usw.

    Siegmund

Kommentar verfassen

Trage deine Daten unten ein oder klicke ein Icon um dich einzuloggen:

WordPress.com-Logo

Du kommentierst mit Deinem WordPress.com-Konto. Abmelden /  Ändern )

Google+ Foto

Du kommentierst mit Deinem Google+-Konto. Abmelden /  Ändern )

Twitter-Bild

Du kommentierst mit Deinem Twitter-Konto. Abmelden /  Ändern )

Facebook-Foto

Du kommentierst mit Deinem Facebook-Konto. Abmelden /  Ändern )

w

Verbinde mit %s

This site uses Akismet to reduce spam. Learn how your comment data is processed.