Uruchom aplikację Java jako usługę w systemie Linux


128

Napisałem aplikację serwerową Java, która działa na standardowym wirtualnym hostowanym rozwiązaniu Linux. Aplikacja działa cały czas nasłuchując połączeń gniazd i tworząc dla nich nowe programy obsługi. Jest to implementacja po stronie serwera do aplikacji klient-serwer.

Zacząłem od włączenia go do skryptu startowego rc.local serwera. Jednak po uruchomieniu nie wiem, jak uzyskać do niego dostęp, aby go zatrzymać i jeśli chcę zainstalować aktualizację, muszę ponownie uruchomić serwer, aby ponownie uruchomić aplikację.

Na komputerze z systemem Windows dla tego typu aplikacji mogę utworzyć usługę systemu Windows, a następnie mogę ją zatrzymać i uruchomić, jak chcę. Czy jest coś takiego na Linuksie, więc jeśli uruchomię tę aplikację, mogę ją zatrzymać i ponownie uruchomić bez wykonywania całkowitego restartu serwera.

Moja aplikacja nazywa się WebServer.exe. Jest uruchamiany przy starcie serwera, włączając go do mojego rc.local jako takiego:

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

Jestem trochę noobem w Linuksie, więc każdy przykład byłby doceniony w przypadku jakichkolwiek postów. Jednak mam SSH i pełny dostęp FTP do skrzynki, aby zainstalować aktualizacje, a także dostęp do panelu Plesk.

Odpowiedzi:


239

Napisałem tutaj kolejny prosty wrapper:

#!/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 

Możesz zapoznać się z pełnym samouczkiem dotyczącym init.d tutaj, a dla systemd (ubuntu 16+) tutaj

Jeśli potrzebujesz dziennika wyjściowego, zastąp plik 2

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

linie dla

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

@PbxMan dzięki za to. Mogę spróbować i zobaczyć, jak sobie radzimy. Twoje zdrowie.
— dreza

2
ale jak mogę uruchomić ten plik? gdzie mam to położyć?
— Jack Daniel,

3
@JackDaniel w dystrybucjach opartych na Debianie, takich jak sam debian i ubuntu, możesz dodać ten skrypt do /etc/init.d. Następnie możesz wywołać go w ten sposób: /etc/init.d/MyService start. I możesz uruchomić go automatycznie, uruchamiając update-rc.d MyService defaults.
— Andre,

1
@ ThorbjørnRavnAndersen To zależy od twojego programu java. Jeśli nie możesz zabić programu java, sprawdź stackoverflow.com/questions/2541597/… . Usunąłbym MyService-pid zamiast kill i miałbym wątek demona w części Java, który sprawdza, czy istnieje.
— PbxMan

1
Gdzie będzie plik ouput pliku jar? jak mogę skonfigurować jego nazwę?
— M. Schena

48

Prostym rozwiązaniem jest utworzenie skryptu start.sh, który uruchamia Javę przez nohup, a następnie zapisuje PID do pliku:

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

Wtedy twój skrypt zatrzymujący stop.sh odczytałby PID z pliku i zabił aplikację:

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

Oczywiście pominąłem kilka szczegółów, takich jak sprawdzenie, czy proces istnieje i usunięcie, pid.txtjeśli skończysz.


2
Pytanie: Czy polecenie kill $ PID nie spowodowałoby zabicia procesu bez jego zakończenia? Piszę program serwera, który łączy się z bazą danych i chciałbym, aby wszystkie aktualnie uruchomione wątki zakończyły się przed zakończeniem programu, aby upewnić się, że program nie umrze w środku zapisu do bazy danych lub coś w tym stylu .
— Scuba Steve

2
@ scuba-steve w pewnym sensie. kill wyśle ​​sygnał TERM, który wywoła wszelkie haki zamykające, które są na miejscu, więc użyj ich, aby z wdziękiem zakończyć proces. Nie zostaną wykonane, jeśli proces otrzyma sygnał zabicia (tj. Kill -9). System operacyjny może przerwać haki
— zamykające,

34

Skrypty startowe usługi Linux są przechowywane w plikach /etc/init.d. Możesz skopiować i dostosować /etc/init.d/skeletonplik, a następnie zadzwonić

service [yourservice] start|stop|restart

patrz http://www.ralfebert.de/blog/java/debian_daemon/ . Jest przeznaczony dla Debiana (więc również Ubuntu), ale pasuje do większej dystrybucji.


Wygląda obiecująco. Przyjrzę się temu bliżej. okrzyki
— dreza

11

Może nie jest to najlepsze rozwiązanie dla deweloperów, ale dobre do ogólnego użytku serwera na imprezę LAN lub podobną.

Służy screendo uruchamiania serwera, a następnie odłączania go przed wylogowaniem. Dzięki temu proces będzie działał, możesz ponownie podłączyć w dowolnym momencie.

Przepływ pracy:

Uruchom ekran: screen

Uruchom swój serwer: java -jar minecraft-server.jar

Odłączyć naciskając: Ctl-a,d

Podłącz ponownie: screen -r

Więcej informacji tutaj: https://www.gnu.org/software/screen/manual/screen.html


7

Inną alternatywą, która jest również dość popularna, jest Java Service Wrapper . Jest to również dość popularne w społeczności OSS.


Twoje zdrowie. Widziałem o tym wzmiankę. Przyjrzymy się bliżej.
— dreza

5

Odnosząc się również do aplikacji Spring Boot jako usługi , wybrałbym systemdwersję, ponieważ jest to najłatwiejsza, najmniej szczegółowa i najlepiej zintegrowana z nowoczesnymi dystrybucjami (a nawet nie tak nowoczesnymi, jak CentOS 7.x).



4

Oto przykładowy skrypt powłoki (pamiętaj, aby zastąpić nazwę MATEMATYCZNĄ nazwą aplikacji):

#!/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

Z jakiegoś powodu zawsze informuje, że usługa jest już uruchomiona. Wygląda na to, że pgrep zwraca 0 po uruchomieniu z wnętrza skryptu, ale jeśli ręcznie wprowadzę polecenie pgrep, zwraca 1.
— HomeIsWhereThePcIs

Powodem, dla którego pgrep uważa, że ​​usługa jest uruchomiona, jest to, że wykrywa "/ bin / sh / sbin / service MATH start" i "/ bin / bash /etc/init.d/MATH start" i zwraca 0
— HomeIsWhereThePcIs

3

Z aplikacji Spring Boot as a Service mogę polecić supervisordaplikację opartą na Pythonie . Zobacz pytanie o przepełnienie stosu, aby uzyskać więcej informacji. Konfiguracja jest naprawdę prosta.


supervisordjest świetny, dla tych, którzy nie wiedzą, umożliwia monitorowanie usług (które muszą być foreground- nie daemonized), a następnie automatycznie restartuje usługi (i może wysyłać powiadomienia e-mail po ponownym uruchomieniu za pośrednictwem wtyczek)
— wired00

2

Inne odpowiedzi wykonują dobrą robotę, dając niestandardowe skrypty i konfiguracje w zależności od platformy. Oprócz tych, oto dojrzałe programy specjalnego przeznaczenia, o których wiem:

  • JSW firmy TanukiSoftware
  • YAJSW jest klonem open source z powyższego. Jest napisany w Javie i jest procesem niani, który zarządza procesem potomnym (kodem) zgodnie z konfiguracjami. Działa na Windows / Linux.
  • JSVC to aplikacja natywna. Jest to również proces niania, ale wywołuje aplikację dziecka za pośrednictwem JNI, a nie jako podproces.


1

Z przewodnika po rozruchu sprężynowym

Instalacja jako usługa init.d (System V)

Wystarczy podlinkowujemy słoik aby init.dwspierać standard start, stop, restarti statuspoleceń. Zakładając, że masz aplikację Spring Boot zainstalowaną w / var / myapp, aby zainstalować aplikację Spring Boot jako usługę init.d, po prostu utwórz dowiązanie symboliczne:

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

Po zainstalowaniu możesz uruchamiać i zatrzymywać usługę w zwykły sposób. Na przykład w systemie opartym na Debianie:

$ service myapp start

WskazówkaJeśli aplikacja nie uruchamia się, sprawdź, czy plik dziennika, w którym został zapisany, nie zawiera /var/log/<appname>.logbłędów.

Kontynuuj czytanie aby dowiedzieć się, jak zabezpieczyć wdrożoną usługę.

Po wykonaniu tego, co napisałem, odkryłem, że moja usługa nie uruchamia się i wyświetla ten komunikat o błędzie w dziennikach: start-stop-daemon: unrecognized opcja --no-close . I udało mi się to naprawić, tworząc plik konfiguracyjny /var/myapp/myapp.confz następującą zawartością

USE_START_STOP_DAEMON=false

1

Mam aplikację java Netty i chcę ją uruchomić jako usługę z systemd. Niestety aplikacja zatrzymuje się niezależnie od używanego typu. Na koniec zawinąłem start Java w screen. Oto pliki konfiguracyjne:

usługa

[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

początek

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

od tego momentu możesz użyć systemctl [start|stop|status] service.



0

Jednak po uruchomieniu nie wiem, jak uzyskać do niego dostęp, aby go zatrzymać

Możesz napisać prosty skrypt zatrzymujący, który grepuje dla twojego procesu java, wyodrębnia PID i wywołuje na nim kill. To nie jest wyszukane, ale jest proste. Coś takiego może być pomocne na początek:

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

2
Nie jestem zbyt dobry w Linuksie, ale nie pkill nameofprocessrobię tego samego?
— Denys Séguret

0

Możliwe jest prowadzenie wojny jako usługa Linuksa i możesz chcieć wymusić plik pom.xml przed pakowaniem, ponieważ niektóre dystrybucje mogą nie rozpoznawać w trybie automatycznym. Aby to zrobić, dodaj następującą właściwość wewnątrz wtyczki spring-boot-maven-plugin.

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

Następnie skonfiguruj swój init.d za pomocą:

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

i będziesz mógł biec

service myapp start|stop|restart

Istnieje wiele innych opcji, które można znaleźć w dokumentacji Spring Boot , w tym usługa Windows.

Korzystając z naszej strony potwierdzasz, że przeczytałeś(-aś) i rozumiesz nasze zasady używania plików cookie i zasady ochrony prywatności.
Licensed under cc by-sa 3.0 with attribution required.