Führen Sie eine Java-Anwendung als Dienst unter Linux aus


128

Ich habe eine Java-Serveranwendung geschrieben, die auf einer virtuellen virtuell gehosteten Linux-Lösung ausgeführt wird. Die Anwendung läuft ständig und wartet auf Socket-Verbindungen und erstellt neue Handler für diese. Es ist eine serverseitige Implementierung für eine Client-Server-Anwendung.

Ich starte es, indem ich es in das Startskript rc.local des Servers einbinde. Einmal gestartet, weiß ich jedoch nicht, wie ich darauf zugreifen soll, um es zu stoppen, und wenn ich ein Update installieren möchte, muss ich den Server neu starten, um die Anwendung neu zu starten.

Auf einem Windows-PC kann ich für diese Art von Anwendung einen Windows-Dienst erstellen und ihn dann stoppen und starten, wie ich möchte. Gibt es so etwas auf einer Linux-Box, so dass ich diese Anwendung stoppen und neu starten kann, wenn ich sie starte, ohne den Server vollständig neu zu starten?

Meine Anwendung heißt WebServer.exe. Es wird beim Serverstart gestartet, indem es als solches in meine rc.local aufgenommen wird :

java -jar /var/www/vhosts/myweb.com/phpserv/WebServer.jar &

Ich bin ein bisschen ein Noob unter Linux, daher wäre jedes Beispiel für Beiträge willkommen. Ich habe jedoch SSH und vollen FTP-Zugriff auf die Box, um alle Updates zu installieren, sowie Zugriff auf ein Plesk-Panel.

Antworten:


239

Ich habe hier einen weiteren einfachen Wrapper geschrieben:

#!/bin/sh
SERVICE_NAME=MyService
PATH_TO_JAR=/usr/local/MyProject/MyJar.jar
PID_PATH_NAME=/tmp/MyService-pid
case $1 in
    start)
        echo "Starting $SERVICE_NAME ..."
        if [ ! -f $PID_PATH_NAME ]; then
            nohup java -jar $PATH_TO_JAR /tmp 2>> /dev/null >> /dev/null &
            echo $! > $PID_PATH_NAME
            echo "$SERVICE_NAME started ..."
        else
            echo "$SERVICE_NAME is already running ..."
        fi
    ;;
    stop)
        if [ -f $PID_PATH_NAME ]; then
            PID=$(cat $PID_PATH_NAME);
            echo "$SERVICE_NAME stoping ..."
            kill $PID;
            echo "$SERVICE_NAME stopped ..."
            rm $PID_PATH_NAME
        else
            echo "$SERVICE_NAME is not running ..."
        fi
    ;;
    restart)
        if [ -f $PID_PATH_NAME ]; then
            PID=$(cat $PID_PATH_NAME);
            echo "$SERVICE_NAME stopping ...";
            kill $PID;
            echo "$SERVICE_NAME stopped ...";
            rm $PID_PATH_NAME
            echo "$SERVICE_NAME starting ..."
            nohup java -jar $PATH_TO_JAR /tmp 2>> /dev/null >> /dev/null &
            echo $! > $PID_PATH_NAME
            echo "$SERVICE_NAME started ..."
        else
            echo "$SERVICE_NAME is not running ..."
        fi
    ;;
esac 

Sie können einem vollständigen Tutorial für init.d hier und für systemd (Ubuntu 16+) hier folgen

Wenn Sie das Ausgabeprotokoll benötigen, ersetzen Sie das 2

nohup java -jar $PATH_TO_JAR /tmp 2>> /dev/null >> /dev/null &

Zeilen für

nohup java -jar $PATH_TO_JAR >> myService.out 2>&1&

@PbxMan danke dafür. Ich könnte es versuchen und sehen, wie wir uns verstehen. Prost.
Dreza

2
aber wie kann ich diese Datei ausführen? wo muss ich es hinstellen
Jack Daniel

3
@JackDaniel Auf Debian-basierten Distributionen wie Debian selbst und Ubuntu können Sie dieses Skript zu /etc/init.d hinzufügen. Dann können Sie es folgendermaßen aufrufen: /etc/init.d/MyService start. Und Sie können es automatisch starten lassen, indem Sie die Standardeinstellungen für update-rc.d MyService ausführen.
Andre

1
@ ThorbjørnRavnAndersen Das würde von deinem Java-Programm abhängen. Wenn Sie Ihr Java-Programm nicht beenden können , lesen Sie stackoverflow.com/questions/2541597/… . Ich würde die MyService-PID anstelle des Kill löschen und einen Deamon-Thread im Java-Teil haben, der prüft, ob er existiert.
PbxMan

1
Wo wird die Ausgabedatei des Glases sein? Wie kann ich den Namen konfigurieren?
M. Schena

48

Eine einfache Lösung besteht darin, ein Skript start.sh zu erstellen, das Java über nohup ausführt und dann die PID in einer Datei speichert:

nohup java -jar myapplication.jar > log.txt 2> errors.txt < /dev/null &
PID=$!
echo $PID > pid.txt

Dann würde Ihr Stoppskript stop.sh die PID aus der Datei lesen und die Anwendung beenden:

PID=$(cat pid.txt)
kill $PID

Natürlich habe ich einige Details ausgelassen, z. B. zu überprüfen, ob der Prozess vorhanden ist, und zu entfernen, pid.txtwenn Sie fertig sind.


2
Frage: Würde der Befehl kill $ PID nicht dazu führen, dass der Prozess abgebrochen wird, ohne beendet zu werden? Ich schreibe ein Serverprogramm, das mit einer Datenbank verbunden ist, und ich möchte, dass alle aktuell ausgeführten Threads beendet werden, bevor das Programm beendet wird, um sicherzustellen, dass das Programm nicht während eines Schreibvorgangs in die Datenbank oder so etwas stirbt .
Scuba Steve

2
@ Scuba-Steve Art von. kill sendet das TERM-Signal, das alle vorhandenen Shutdown-Hooks aufruft. Verwenden Sie diese also, um Ihren Prozess ordnungsgemäß zu beenden. Sie werden nicht ausgeführt, wenn der Prozess ein Kill-Signal erhält (dh kill -9). Das Betriebssystem kann Ihre Shutdown-Hooks unterbrechen, wenn sie zu lange
dauern.

34

Linux Service Init Script werden in gespeichert /etc/init.d. Sie können die /etc/init.d/skeletonDatei kopieren und anpassen und dann aufrufen

service [yourservice] start|stop|restart

Siehe http://www.ralfebert.de/blog/java/debian_daemon/ . Es ist für Debian (also auch für Ubuntu), passt aber zu mehr Distribution.


Sieht vielversprechend aus. Ich werde mir das genauer ansehen. prost
dreza

11

Vielleicht nicht die beste Entwicklungslösung, aber gut für die allgemeine Verwendung eines Servers für eine LAN-Party oder ähnliches.

Verwenden screenSie diese Option , um Ihren Server vor dem Abmelden zu starten und dann zu trennen. Dadurch wird der Prozess fortgesetzt. Sie können ihn dann jederzeit erneut anhängen.

Arbeitsablauf:

Starten Sie einen Bildschirm: screen

Starten Sie Ihren Server: java -jar minecraft-server.jar

Abnehmen durch Drücken von : Ctl-a,d

Erneut anhängen: screen -r

Weitere Informationen finden Sie hier: https://www.gnu.org/software/screen/manual/screen.html


7

Eine weitere Alternative, die ebenfalls sehr beliebt ist, ist der Java Service Wrapper . Dies ist auch in der OSS-Community sehr beliebt.


Prost. Ich hatte einige Erwähnungen davon gesehen. Werde genauer hinsehen.
Dreza

5

Wenn ich mich auch auf die Spring Boot-Anwendung als Servicesystemd beziehe , würde ich mich für die Version entscheiden, da sie am einfachsten, am wenigsten ausführlich und am besten in moderne Distributionen (und sogar in nicht so moderne wie CentOS 7.x) integriert ist.



4

Hier ist ein Beispiel für ein Shell-Skript (stellen Sie sicher, dass Sie den MATH-Namen durch den Namen Ihrer Anwendung ersetzen):

#!/bin/bash

### BEGIN INIT INFO
# Provides:                 MATH
# Required-Start:           $java
# Required-Stop:            $java
# Short-Description:        Start and stop MATH service.
# Description:              -
# Date-Creation:            -
# Date-Last-Modification:   -
# Author:                   -
### END INIT INFO

# Variables
PGREP=/usr/bin/pgrep
JAVA=/usr/bin/java
ZERO=0

# Start the MATH
start() {
    echo "Starting MATH..."
    #Verify if the service is running
    $PGREP -f MATH > /dev/null
    VERIFIER=$?
    if [ $ZERO = $VERIFIER ]
    then
        echo "The service is already running"
    else
        #Run the jar file MATH service
        $JAVA -jar /opt/MATH/MATH.jar > /dev/null 2>&1 &
        #sleep time before the service verification
        sleep 10
        #Verify if the service is running
        $PGREP -f MATH  > /dev/null
        VERIFIER=$?
        if [ $ZERO = $VERIFIER ]
        then
            echo "Service was successfully started"
        else
            echo "Failed to start service"
        fi
    fi
    echo
}

# Stop the MATH
stop() {
    echo "Stopping MATH..."
    #Verify if the service is running
    $PGREP -f MATH > /dev/null
    VERIFIER=$?
    if [ $ZERO = $VERIFIER ]
    then
        #Kill the pid of java with the service name
        kill -9 $($PGREP -f MATH)
        #Sleep time before the service verification
        sleep 10
        #Verify if the service is running
        $PGREP -f MATH  > /dev/null
        VERIFIER=$?
        if [ $ZERO = $VERIFIER ]
        then
            echo "Failed to stop service"
        else
            echo "Service was successfully stopped"
        fi
    else
        echo "The service is already stopped"
    fi
    echo
}

# Verify the status of MATH
status() {
    echo "Checking status of MATH..."
    #Verify if the service is running
    $PGREP -f MATH > /dev/null
    VERIFIER=$?
    if [ $ZERO = $VERIFIER ]
    then
        echo "Service is running"
    else
        echo "Service is stopped"
    fi
    echo
}

# Main logic
case "$1" in
    start)
        start
        ;;
    stop)
        stop
        ;;
    status)
        status
        ;;
    restart|reload)
        stop
        start
        ;;
  *)
    echo $"Usage: $0 {start|stop|status|restart|reload}"
    exit 1
esac
exit 0

Aus irgendeinem Grund wird immer gemeldet, dass der Dienst bereits gestartet ist. Es scheint, dass pgrep 0 zurückgibt, wenn es aus dem Skript heraus ausgeführt wird, aber wenn ich den Befehl pgrep manuell
eingebe, wird

Der Grund, warum pgrep glaubt, dass der Dienst ausgeführt wird, liegt darin, dass er "/ bin / sh / sbin / service MATH start" und "/ bin / bash /etc/init.d/MATH start" erkennt und 0
HomeIsWhereThePcIs vom

3

In der Spring Boot-Anwendung als Dienst kann ich die Python-basierte supervisordAnwendung empfehlen . Weitere Informationen finden Sie in dieser Frage zum Stapelüberlauf. Es ist wirklich einfach einzurichten.


supervisordist großartig, für diejenigen, die es nicht wissen, es erlaubt Überwachungsdienste (was sein muss foreground- nicht daemonized), es wird dann Dienste automatisch neu starten (und kann Benachrichtigungen per E-Mail senden, wenn Neustarts über Plugins erfolgen)
wired00

2

Andere Antworten liefern je nach Plattform benutzerdefinierte Skripte und Setups. Zusätzlich zu diesen sind hier die ausgereiften Spezialprogramme, die ich kenne:

  • JSW von TanukiSoftware
  • YAJSW ist ein Open Source-Klon von oben. Es ist in Java geschrieben und ein Nanny-Prozess, der den untergeordneten Prozess (Ihren Code) gemäß den Konfigurationen verwaltet. Funktioniert unter Windows / Linux.
  • JSVC ist eine native Anwendung. Es ist auch ein Kindermädchen-Prozess, aber es ruft Ihre Kinderanwendung über das JNI auf und nicht als Unterprozess.


1

Aus dem Spring Boot-Referenzhandbuch

Installation als init.d-Dienst (System V)

Einfach Symlink das Glas , um init.dden Standard zu unterstützen start, stop, restartund statusBefehle. Angenommen, Sie haben eine Spring Boot-Anwendung in / var / myapp installiert, um eine Spring Boot-Anwendung als init.d-Dienst zu installieren, erstellen Sie einfach einen Symlink:

$ sudo ln -s /var/myapp/myapp.jar /etc/init.d/myapp

Nach der Installation können Sie den Dienst wie gewohnt starten und beenden. Zum Beispiel auf einem Debian-basierten System:

$ service myapp start

TrinkgeldWenn Ihre Anwendung nicht gestartet werden kann, überprüfen Sie die Protokolldatei, in die geschrieben wurde, /var/log/<appname>.logauf Fehler.

Lesen Sie weiter, um zu erfahren, wie Sie einen bereitgestellten Dienst sichern können.

Nachdem ich wie geschrieben vorgegangen bin, habe ich festgestellt, dass mein Dienst nicht mit dieser Fehlermeldung in den Protokollen gestartet werden kann : start-stop-daemon: nicht erkannte Option --no-close . Und ich habe es geschafft, es zu beheben, indem ich eine Konfigurationsdatei /var/myapp/myapp.confmit dem folgenden Inhalt erstellt habe

USE_START_STOP_DAEMON=false

1

Ich habe Netty Java-Anwendung und ich möchte es als Dienst mit systemd ausführen. Leider stoppt die Anwendung, egal welchen Typ ich verwende. Am Ende habe ich Java Start in Bildschirm eingewickelt. Hier sind die Konfigurationsdateien:

Bedienung

[Unit]
Description=Netty service
After=network.target
[Service]
User=user
Type=forking
WorkingDirectory=/home/user/app
ExecStart=/home/user/app/start.sh
TimeoutStopSec=10
Restart=on-failure
RestartSec=5
[Install]
WantedBy=multi-user.target

Anfang

#!/bin/sh
/usr/bin/screen -L -dmS netty_app java -cp app.jar classPath

Ab diesem Punkt können Sie verwenden systemctl [start|stop|status] service.


1

Um Java-Code als Daemon (Dienst) auszuführen, können Sie einen JNI-basierten Stub schreiben.

http://jnicookbook.owsiak.org/recipe-no-022/

für einen Beispielcode, der auf JNI basiert. In diesem Fall dämonisieren Sie den Code, der als Java gestartet wurde, und die Hauptschleife wird in C ausgeführt. Es ist jedoch auch möglich, die Dienstschleife des Hauptdämons in Java einzufügen.

https://github.com/mkowsiak/jnicookbook/tree/master/recipes/recipeNo029

Viel Spaß mit JNI!


0

Einmal gestartet, weiß ich jedoch nicht, wie ich darauf zugreifen soll, um es zu stoppen

Sie können ein einfaches Stoppskript schreiben, das nach Ihrem Java-Prozess sucht, die PID extrahiert und kill aufruft. Es ist nichts Besonderes, aber es ist einfach. So etwas kann zunächst hilfreich sein:

#!/bin/bash
PID = ps ax | grep "name of your app" | cut -d ' ' -f 1
kill $PID

2
Ich bin nicht sehr gut in Linux, mache aber nicht pkill nameofprocessdas Gleiche?
Denys Séguret

0

Es ist möglich, den Krieg als Linux-Dienst auszuführen, und Sie möchten möglicherweise Ihre Datei pom.xml vor dem Packen erzwingen, da einige Distributionen im automatischen Modus möglicherweise nicht erkennen. Fügen Sie dazu die folgende Eigenschaft in das Spring-Boot-Maven-Plugin-Plugin ein.

                    <embeddedLaunchScriptProperties>
                        <mode>service</mode>
                    </embeddedLaunchScriptProperties>

Als nächstes richten Sie Ihre init.d ein mit:

ln -s myapp.war /etc/init.d/myapp

und du wirst laufen können

service myapp start|stop|restart

Es gibt viele andere Optionen, die Sie in der Spring Boot-Dokumentation finden , einschließlich des Windows-Dienstes.

Durch die Nutzung unserer Website bestätigen Sie, dass Sie unsere Cookie-Richtlinie und Datenschutzrichtlinie gelesen und verstanden haben.
Licensed under cc by-sa 3.0 with attribution required.