Jalankan Aplikasi Java sebagai Layanan di Linux

128

Saya telah menulis aplikasi server Java yang berjalan pada solusi Linux standar virtual host. Aplikasi berjalan setiap saat mendengarkan koneksi soket dan membuat penangan baru untuk mereka. Ini adalah implementasi sisi server ke aplikasi client-server.

Cara saya memulainya adalah dengan memasukkannya dalam skrip start up rc.local dari server. Namun begitu mulai, saya tidak tahu cara mengaksesnya untuk menghentikannya dan jika saya ingin menginstal pembaruan, jadi saya harus me-restart server untuk me-restart aplikasi.

Pada PC windows, untuk jenis aplikasi ini saya dapat membuat layanan windows dan kemudian saya dapat berhenti dan memulainya seperti yang saya inginkan. Apakah ada yang seperti itu pada kotak Linux sehingga jika saya memulai aplikasi ini saya dapat menghentikannya dan memulai kembali tanpa melakukan restart lengkap dari server.

Aplikasi saya disebut WebServer.exe. Itu dimulai pada startup server dengan memasukkannya di rc.local saya seperti:

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

Saya sedikit noob di Linux sehingga contoh apa pun akan dihargai dengan tulisan apa pun. Namun saya memiliki SSH, dan akses FTP penuh ke kotak untuk menginstal pembaruan apa pun serta akses ke panel Plesk.

dreza
sumber

Jawaban:

239

Saya menulis pembungkus sederhana di sini:

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

Anda dapat mengikuti tutorial lengkap untuk init.d di sini dan untuk systemd (ubuntu 16+) di sini

Jika Anda memerlukan log keluaran ganti 2

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

baris untuk

nohup java -jar $PATH_TO_JAR >> myService.out 2>&1&
PbxMan
sumber
@ PBXMan terima kasih untuk ini. Saya mungkin mencobanya dan melihat bagaimana kita maju. Bersulang.
dreza
2
tetapi bagaimana saya bisa menjalankan file ini? di mana saya harus meletakkannya?
Jack Daniel
3
@JackDaniel pada distro berbasis debian, seperti debian sendiri dan ubuntu, Anda dapat menambahkan skrip itu ke /etc/init.d. Kemudian Anda dapat menjalankannya seperti ini: /etc/init.d/MyService mulai. Dan Anda dapat membuatnya mulai secara otomatis dengan menjalankan pembaruan-rc.d MyService defaults.
Andre
1
@ ThorbjørnRavnAndersen Itu akan tergantung pada program java Anda. Jika Anda tidak dapat mematikan program java Anda, periksa stackoverflow.com/questions/2541597/… . Saya akan menghapus MyService-pid bukan membunuh dan memiliki utas deamon di bagian Jawa yang memeriksa jika ada.
PbxMan
1
Di mana file ouput jar itu berada? bagaimana saya bisa mengkonfigurasi nama itu?
M. Schena
48

Solusi sederhana adalah membuat skrip start.sh yang menjalankan Java melalui nohup dan kemudian menyimpan PID ke file:

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

Maka skrip stop Anda stop.sh akan membaca PID dari file dan mematikan aplikasi:

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

Tentu saja saya telah meninggalkan beberapa detail, seperti memeriksa apakah prosesnya ada dan menghapus pid.txtjika Anda sudah selesai.

Wernsey
sumber
2
Pertanyaan: Bukankah perintah kill $ PID menyebabkan proses untuk dibunuh tanpa menyelesaikan? Saya sedang menulis program server yang berinteraksi dengan database, dan saya ingin semua utas yang sedang berjalan selesai sebelum program keluar, untuk memastikan bahwa program tersebut tidak mati di tengah penulisan ke DB atau sesuatu .
Scuba Steve
2
@ semacam scuba-steve. kill akan mengirim sinyal TERM, yang akan memanggil semua kait shutdown yang ada, jadi gunakan mereka untuk mengakhiri proses Anda dengan anggun. Mereka tidak akan mengeksekusi jika proses mendapat sinyal kill (yaitu, kill -9). OS dapat menginterupsi kait shutdown Anda jika terlalu lama untuk diselesaikan, jadi jaga agar tetap ringkas
rjohnston
34

Skrip init layanan Linux disimpan ke dalam /etc/init.d. Anda dapat menyalin dan menyesuaikan /etc/init.d/skeletonfile, lalu memanggil

service [yourservice] start|stop|restart

lihat http://www.ralfebert.de/blog/java/debian_daemon/ . Ini untuk Debian (jadi, Ubuntu juga) tetapi lebih cocok untuk distribusi.

Arcadien
sumber
Terlihat menjanjikan. Saya akan melihat lebih dekat ke ini. cheers
dreza
11

Mungkin bukan solusi dev-ops terbaik, tetapi bagus untuk penggunaan umum server untuk pesta lan atau sejenisnya.

Gunakan screenuntuk menjalankan server Anda dan kemudian lepaskan sebelum logout, ini akan membuat proses berjalan, Anda kemudian dapat melampirkan kembali pada titik mana pun.

Alur kerja:

Mulai layar: screen

Mulai server Anda: java -jar minecraft-server.jar

Lepaskan dengan menekan: Ctl-a,d

Pasang kembali: screen -r

Info lebih lanjut di sini: https://www.gnu.org/software/screen/manual/screen.html

Peter Peterson
sumber
7

Alternatif lain, yang juga cukup populer adalah Java Service Wrapper . Ini juga cukup populer di komunitas OSS.

carlspring
sumber
Bersulang. Saya telah melihat beberapa menyebutkan itu. Akan melihat lebih dekat.
dreza
5

Mengacu pada aplikasi Spring Boot sebagai Layanan juga, saya akan menggunakan systemdversi ini, karena ini adalah yang termudah, paling tidak bertele-tele, dan paling baik diintegrasikan ke dalam distro modern (dan bahkan yang tidak begitu modern seperti CentOS 7.x).

yglodt
sumber
4

Berikut ini contoh skrip shell (pastikan Anda mengganti nama MATH dengan nama aplikasi Anda):

#!/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
Matheus Sant Anna de Oliveira
sumber
Untuk beberapa alasan ini selalu melaporkan layanan sudah dimulai. Tampaknya pgrep mengembalikan 0 ketika dijalankan dari dalam skrip, tetapi jika saya memasukkan perintah pgrep secara manual ia mengembalikan 1.
HomeIsWhereThePcIs
Alasan mengapa pgrep berpikir layanan sedang berjalan adalah karena ia mendeteksi "/ bin / sh / sbin / service MATH start" dan "/ bin / bash /etc/init.d/MATH start" dan mengembalikan 0
HomeIsWhereThePcIs
3

Dari aplikasi Spring Boot sebagai Layanan , saya dapat merekomendasikan supervisordaplikasi berbasis Python . Lihat pertanyaan stack overflow untuk informasi lebih lanjut. Ini sangat mudah untuk diatur.

Dawngerpony
sumber
supervisordsangat bagus, bagi mereka yang tidak tahu, ini memungkinkan layanan pemantauan (yang harus foreground- tidak daemonized), maka layanan restart otomatis (dan dapat mengirim email peringatan ketika restart terjadi melalui plugin)
wired00
2

Jawaban lain melakukan pekerjaan yang baik dengan memberikan skrip dan pengaturan khusus tergantung pada platform Anda. Selain itu, berikut adalah program dewasa, tujuan khusus yang saya tahu:

  • JSW dari TanukiSoftware
  • YAJSW adalah klon open source dari atas. Itu ditulis dalam Java, dan ini adalah proses pengasuh yang mengelola proses anak (kode Anda) sesuai dengan konfigurasi. Bekerja di windows / linux.
  • JSVC adalah aplikasi asli. Ini juga proses pengasuh, tetapi meminta aplikasi anak Anda melalui JNI, bukan sebagai proses.
Mori Bellamy
sumber
1

Anda dapat menggunakan server hemat atau JMX untuk berkomunikasi dengan layanan Java Anda.

tienthanhakay
sumber
1

Dari Panduan Referensi Boot Musim Semi

Instalasi sebagai layanan init.d (Sistem V)

Cukup symlink jar untuk init.dmendukung standar start, stop, restartdan statusperintah. Dengan asumsi bahwa Anda memiliki aplikasi Spring Boot yang terinstal di / var / myapp, untuk menginstal aplikasi Spring Boot sebagai layanan init.d cukup buat symlink:

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

Setelah diinstal, Anda dapat memulai dan menghentikan layanan dengan cara biasa. Misalnya, pada sistem berbasis Debian:

$ service myapp start

TipJika aplikasi Anda gagal memulai, periksa file log yang ditulis /var/log/<appname>.loguntuk kesalahan.

Lanjutkan membaca untuk mengetahui cara mengamankan layanan yang digunakan.

Setelah melakukan seperti yang tertulis, saya menemukan bahwa layanan saya gagal memulai dengan pesan kesalahan ini dalam log: start-stop-daemon: opsi tidak dikenal --no-close . Dan saya sudah berhasil memperbaikinya dengan membuat file konfigurasi /var/myapp/myapp.confdengan konten berikut

USE_START_STOP_DAEMON=false
naXa
sumber
1

Saya memiliki aplikasi java Netty dan saya ingin menjalankannya sebagai layanan dengan systemd. Sayangnya aplikasi berhenti tidak peduli apa Jenis yang saya gunakan. Pada akhirnya saya sudah mulai membungkus java di layar. Berikut adalah file konfigurasi:

layanan

[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

Mulailah

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

dari titik itu Anda dapat menggunakan systemctl [start|stop|status] service.

gskillz
sumber
1

Untuk menjalankan kode Java sebagai daemon (layanan) Anda dapat menulis rintisan berbasis JNI.

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

untuk kode sampel yang didasarkan pada JNI. Dalam hal ini Anda daemonize kode yang dimulai sebagai Java dan loop utama dieksekusi dalam C. Tetapi juga dimungkinkan untuk menempatkan loop layanan utama, daemon, di dalam Java.

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

Bersenang-senang dengan JNI!

Oo.o
sumber
0

Namun begitu mulai, saya tidak tahu bagaimana mengaksesnya untuk menghentikannya

Anda dapat menulis skrip berhenti sederhana yang menangkap proses java Anda, mengekstrak PID dan memanggil kill di atasnya. Itu tidak mewah, tapi lurus ke depan. Sesuatu seperti itu mungkin bisa membantu sebagai permulaan:

#!/bin/bash
PID = ps ax | grep "name of your app" | cut -d ' ' -f 1
kill $PID
hovanessyan
sumber
2
Saya tidak terlalu bagus di linux tetapi tidak pkill nameofprocessmelakukan hal yang sama?
Denys Séguret
0

Dimungkinkan untuk menjalankan perang sebagai layanan Linux, dan Anda mungkin ingin memaksa dalam file pom.xml Anda sebelum pengemasan, karena beberapa distro mungkin tidak mengenali dalam mode otomatis. Untuk melakukannya, tambahkan properti berikut di dalam plugin spring-boot-maven-plugin.

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

Selanjutnya, atur init.d Anda dengan:

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

dan Anda akan dapat berlari

service myapp start|stop|restart

Ada banyak opsi lain yang dapat Anda temukan di dokumentasi Spring Boot , termasuk layanan Windows.

Eder Luis Jorge
sumber