Esegui un'applicazione Java come servizio su Linux


128

Ho scritto un'applicazione server Java che gira su una soluzione Linux ospitata virtuale standard. L'applicazione funziona continuamente ascoltando le connessioni socket e creando nuovi gestori per loro. È un'implementazione lato server in un'applicazione client-server.

Il modo in cui lo avvio è includendolo nello script di avvio rc.local del server. Tuttavia, una volta avviato, non so come accedervi per interromperlo e se voglio installare un aggiornamento, quindi devo riavviare il server per riavviare l'applicazione.

Su un PC Windows, per questo tipo di applicazione potrei creare un servizio Windows e quindi posso fermarlo e avviarlo come voglio. Esiste qualcosa di simile su una scatola Linux in modo che se avvio questa applicazione posso fermarla e riavviarla senza fare un riavvio completo del server.

La mia applicazione si chiama WebServer.exe. Viene avviato all'avvio del server includendolo nel mio rc.local come tale:

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

Sono un po 'indecente su Linux, quindi qualsiasi esempio sarebbe apprezzato con qualsiasi post. Tuttavia ho SSH e accesso FTP completo alla scatola per installare eventuali aggiornamenti, nonché l'accesso a un pannello di Plesk.

Risposte:


239

Ho scritto un altro semplice wrapper qui:

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

Puoi seguire un tutorial completo per init.d qui e per systemd (ubuntu 16+) qui

Se è necessario il registro di output, sostituire 2

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

linee per

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

@PbxMan grazie per questo. Potrei provare e vedere come andiamo avanti. Saluti.
Dreza,

2
ma come posso eseguire questo file? dove devo metterlo?
Jack Daniel,

3
@JackDaniel su distribuzioni basate su debian, come debian stesso e ubuntu, puoi aggiungere quello script a /etc/init.d. Quindi puoi invocarlo in questo modo: /etc/init.d/MyService start. E puoi avviarlo automaticamente eseguendo update-rc.d i valori predefiniti di MyService.
Andre

1
@ ThorbjørnRavnAndersen Dipenderebbe dal tuo programma Java. Se non riesci a uccidere il tuo programma java Dai un'occhiata a stackoverflow.com/questions/2541597/… . Eliminerei MyService-pid invece di kill e avrei un thread Deamon nella parte Java che controlla se esiste.
PbxMan,

1
Dove sarà il file di output del vaso? come posso configurare il suo nome?
M. Schena,

48

Una soluzione semplice è quella di creare uno script start.sh che esegua Java attraverso nohup e quindi memorizzi il PID in un file:

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

Quindi lo script stop stop.sh leggerà il PID dal file e ucciderebbe l'applicazione:

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

Naturalmente ho tralasciato alcuni dettagli, come verificare se il processo esiste e rimuovere pid.txtse hai finito.


2
Domanda: il comando kill $ PID non causerebbe la fine del processo senza essere completato? Sto scrivendo un programma server che si interfaccia con un database e vorrei che tutti i thread attualmente in esecuzione finissero prima che il programma terminasse, in modo da garantire che il programma non muoia nel mezzo di una scrittura sul DB o qualcosa del genere .
Scuba Steve,

2
@ scuba-steve sorta di. kill invierà il segnale TERM, che richiamerà tutti gli hook di arresto presenti, quindi usali per terminare il processo con garbo. Non verranno eseguiti se il processo riceve un segnale di kill (ovvero, kill -9). Il sistema operativo potrebbe interrompere i tuoi hook di arresto se impiegano troppo tempo per il completamento, quindi
tienili concisi

34

Lo script di init del servizio Linux è archiviato in /etc/init.d. È possibile copiare e personalizzare il /etc/init.d/skeletonfile, quindi chiamare

service [yourservice] start|stop|restart

vedi http://www.ralfebert.de/blog/java/debian_daemon/ . È per Debian (quindi anche Ubuntu) ma si adatta a una maggiore distribuzione.


Sembra promettente. Daremo un'occhiata più da vicino a questo. evviva
dreza il

11

Forse non è la migliore soluzione di sviluppo, ma buona per l'uso generale di un server per una festa in lan o simili.

Utilizzare screenper eseguire il server e quindi scollegarlo prima di disconnettersi, ciò manterrà il processo in esecuzione, quindi è possibile ricollegarsi in qualsiasi momento.

Flusso di lavoro:

Avvia una schermata: screen

Avvia il tuo server: java -jar minecraft-server.jar

Staccare premendo: Ctl-a,d

Re-attach: screen -r

Maggiori informazioni qui: https://www.gnu.org/software/screen/manual/screen.html


7

Un'altra alternativa, che è anche abbastanza popolare è Java Service Wrapper . Questo è anche abbastanza popolare nella comunità OSS.


Saluti. Ne avevo già parlato. Guarderemo più da vicino.
Dreza,



4

Ecco uno script di shell di esempio (assicurati di sostituire il nome MATH con il nome dell'applicazione):

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

Per qualche motivo questo segnala sempre che il servizio è già stato avviato. Sembra che pgrep stia restituendo 0 quando viene eseguito dall'interno dello script, ma se inserisco manualmente il comando pgrep restituisce 1.
HomeIsWhereThePcIs

Il motivo per cui pgrep pensa che il servizio sia in esecuzione è perché rileva "/ bin / sh / sbin / service MATH start" e "/ bin / bash /etc/init.d/MATH start" e restituisce 0
HomeIsWhereThePcIs

3

Dall'applicazione Spring Boot come servizio , posso consigliare l' supervisordapplicazione basata su Python . Vedi quella domanda di overflow dello stack per ulteriori informazioni. È davvero semplice da configurare.


supervisordè fantastico, per coloro che non lo sanno, consente i servizi di monitoraggio (che devono essere foreground- non daemonized), quindi riavvia automaticamente i servizi (e può inviare e-mail di avviso quando si verificano i riavvii tramite plug-in)
wired00

2

Altre risposte fanno un buon lavoro fornendo script e configurazioni personalizzate a seconda della piattaforma. Oltre a questi, ecco i programmi maturi e speciali che conosco:

  • JSW di TanukiSoftware
  • YAJSW è un clone open source di cui sopra. È scritto in Java ed è un processo tata che gestisce il processo figlio (il tuo codice) in base alle configurazioni. Funziona su Windows / Linux.
  • JSVC è un'applicazione nativa. È anche un processo di babysitter, ma richiama la tua applicazione figlio attraverso il JNI, piuttosto che come un sottoprocesso.


1

Dalla guida di riferimento di Spring Boot

Installazione come servizio init.d (Sistema V)

Semplicemente link simbolico il vaso per init.dsupportare lo standard start, stop, restarte statuscomandi. Supponendo di avere un'applicazione Spring Boot installata in / var / myapp, per installare un'applicazione Spring Boot come servizio init.d è sufficiente creare un collegamento simbolico:

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

Una volta installato, è possibile avviare e interrompere il servizio nel solito modo. Ad esempio, su un sistema basato su Debian:

$ service myapp start

ManciaSe la tua applicazione non si avvia, controlla gli /var/log/<appname>.logerrori nel file di registro scritto .

Continua a leggere per sapere come proteggere un servizio distribuito.

Dopo aver fatto ciò che ho scritto, ho scoperto che il mio servizio non si avvia con questo messaggio di errore nei registri: start-stop-daemon: opzione non riconosciuta --no-close . E sono riuscito a risolverlo creando un file di configurazione /var/myapp/myapp.confcon il seguente contenuto

USE_START_STOP_DAEMON=false

1

Sto avendo l'applicazione Netty Java e voglio eseguirlo come un servizio con systemd. Sfortunatamente l'applicazione si interrompe indipendentemente dal tipo che sto usando. Alla fine ho spostato java start nella schermata. Ecco i file di configurazione:

servizio

[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

inizio

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

da quel punto puoi usare systemctl [start|stop|status] service.



0

Tuttavia, una volta avviato, non so come accedervi per fermarlo

È possibile scrivere un semplice script di arresto che si aggira per il processo java, estrae il PID e chiama kill su di esso. Non è lussuoso, ma è semplice. Qualcosa del genere potrebbe essere di aiuto come inizio:

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

2
Non sono molto bravo in Linux ma non pkill nameofprocessfaccio la stessa cosa?
Denys Séguret,

0

È possibile eseguire la guerra come servizio Linux e potresti voler forzare il tuo file pom.xml prima del confezionamento, poiché alcune distro potrebbero non riconoscere in modalità automatica. Per farlo, aggiungi la seguente proprietà all'interno del plugin spring-boot-maven-plugin.

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

Quindi, imposta init.d con:

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

e sarai in grado di correre

service myapp start|stop|restart

Esistono molte altre opzioni che puoi trovare nella documentazione di Spring Boot , incluso il servizio Windows.

Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.