Запустіть програму Java як службу в Linux


128

Я написав серверну програму Java, яка працює на стандартному віртуальному рішенні Linux. Додаток працює весь час, прослуховуючи з'єднання сокетів та створюючи для них нові обробники. Це реалізація на стороні сервера до програми клієнт-сервер.

Я запускаю його, включаючи його в сценарій запуску rc.local на сервері. Однак як тільки я почав, я не знаю, як отримати доступ до нього, щоб зупинити його, і якщо я хочу встановити оновлення, тому мені доведеться перезапустити сервер, щоб перезапустити програму.

На комп'ютері з Windows для цього типу додатків я можу створити службу Windows, і тоді я можу зупинитись та запустити її так, як хочу. Чи є щось подібне у вікні Linux, так що якщо я запускаю цю програму, я можу її зупинити та перезапустити, не роблячи повного перезавантаження сервера.

Моя програма називається WebServer.exe. Він запускається при запуску сервера, включаючи його в свій rc.local як такий:

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

Я трохи ноб у Linux, тому будь-який приклад буде вдячний за будь-які повідомлення. Однак у мене є SSH та повний FTP доступ до вікна, щоб встановити будь-які оновлення, а також доступ до панелі Plesk.

Відповіді:


239

Тут я написав ще одну просту обгортку:

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

Ви можете слідувати повним посібником для init.d тут, а для systemd (ubuntu 16+) тут

Якщо вам потрібен журнал виводу, замініть 2

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

рядки для

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

@PbxMan дякую за це. Я можу дати йому піти і подивитися, як ми продовжуємо. Ура.
дреза

2
але як я можу запустити цей файл? куди я повинен це поставити?
Джек Даніель

3
@JackDaniel в дистрибутивах на основі debian, як-от Debian і ubuntu, ви можете додати цей сценарій до /etc/init.d. Тоді ви можете викликати його так: /etc/init.d/MyService start. І ви можете змусити його запускатися автоматично, запустивши параметри MyService update-rc.d за замовчуванням.
Андре

1
@ ThorbjørnRavnAndersen Це залежатиме від вашої програми java. Якщо ви не можете вбити свою програму Java, перегляньте stackoverflow.com/questions/2541597/… . Я б видалив MyService-pid замість kill і мав би нитку deamon у частині Java, яка перевіряє, чи існує.
PbxMan

1
Де буде знаходитися вихідний файл баночки? як я можу налаштувати його ім'я?
М. Шена

48

Просте рішення - створити скрипт start.sh, який запускає Java через nohup, а потім зберігає PID у файл:

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

Тоді ваш скрипт зупинки stop.sh прочитає PID з файлу та знищить додаток:

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

Звичайно, я залишив деякі деталі, як-от перевірити, чи існує процес, і видалити, pid.txtякщо ви закінчили.


2
Питання: Чи не призведе команда kill $ PID, щоб процес був убитий без закінчення? Я пишу серверну програму, яка взаємодіє з базою даних, і я хотів би, щоб усі поточні поточні потоки закінчувалися до завершення програми, щоб гарантувати, що програма не загине посеред запису в БД чи щось таке .
Scuba Steve

2
@ scuba-steve начебто. kill надішле сигнал TERM, який викличе будь-які гачки відключення, які є на своєму місці, тому використовуйте їх для витонченого завершення процесу. Вони не виконуються, якщо процес отримає сигнал вбивства (тобто, kill -9). ОС може перервати ваші гачки відключення, якщо вони
займуть

34

Скрипт init служби служби Linux зберігається в /etc/init.d. Ви можете скопіювати та налаштувати /etc/init.d/skeletonфайл, а потім зателефонувати

service [yourservice] start|stop|restart

побачити http://www.ralfebert.de/blog/java/debian_daemon/ . Це для Debian (значить, і для Ubuntu), але підходить для більшого розповсюдження.


Виглядає перспективно. Я детальніше розгляну це. ура
дреза

11

Можливо, не найкраще рішення для розробників, але добре для загального використання сервера для lan party чи подібного.

Використовуйте screenдля запуску вашого сервера, а потім від'єднайте його, перш ніж виходити з системи, це призведе до запуску процесу, потім ви зможете повторно приєднатись у будь-якій точці.

Робочий процес:

Запуск екрана: screen

Запустіть ваш сервер: java -jar minecraft-server.jar

Відокремити натисканням: Ctl-a,d

Повторно вкласти: screen -r

Більше інформації тут: https://www.gnu.org/software/screen/manual/screen.html


7

Ще одна альтернатива, яка також є досить популярною - це Java Service Wrapper . Це також досить популярно у спільноті OSS.


Ура. Я бачив деякі згадки про це. Поглянемо уважніше.
dreza

5

Посилаючись на додаток Spring Boot як Сервіс , я б пішов на systemdверсію, оскільки це найпростіший, найменш багатослівний і найкраще інтегрований у сучасні дистрибутиви (і навіть не такі сучасні, як CentOS 7.x).



4

Ось зразок сценарію оболонки (переконайтеся, що ви замінили ім’я MATH на ім’я вашої програми):

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

Чомусь ця служба звітів завжди запущена. Здається, що pgrep повертає 0 при запуску зсередини сценарію, але якщо я введіть команду pgrep вручну, вона повертається 1.
HomeIsWhereThePcIs

Причина, чому pgrep вважає, що служба запускається, полягає в тому, що вона виявляє "/ bin / sh / sbin / service MATH start" і "/ bin / bash /etc/init.d/MATH start" і повертає 0
HomeIsWhereThePcIs

3

З програми Spring Boot як сервісу я можу порекомендувати supervisordдодаток на основі Python . Дивіться це запитання про переповнення стека для отримання додаткової інформації. Це дуже просто налаштувати.


supervisordце чудово, що для тих, хто не знає, він дозволяє моніторингові послуги (які повинні бути foreground- ні daemonized), потім вони автоматично перезавантажать послуги (і можуть надсилати сповіщення електронною поштою, коли перезавантаження відбувається через плагіни)
wired00

2

Інші відповіді добре справляються із наданням власних сценаріїв та налаштувань залежно від вашої платформи. На додаток до них, ось зрілі програми спеціального призначення, про які я знаю:

  • JSW від TanukiSoftware
  • YAJSW - це клон з відкритим кодом із зазначеного вище. Він написаний на Java, і це нянь, який керує дочірнім процесом (вашим кодом) відповідно до конфігурацій. Працює на windows / linux.
  • JSVC - це нативна програма. Це також процес няні, але він посилається на заяву вашої дитини через JNI, а не як підпроцес.


1

Із посібника з весняного завантаження

Установка як послуга init.d (система V)

Просто символічна посилання банки , щоб init.dпідтримувати стандарт start, stop, restartі statusкоманду. Якщо припустити, що у / var / myapp встановлено додаток Spring Boot, для встановлення програми Spring Boot як сервісу init.d просто створіть символьне посилання:

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

Після встановлення можна запустити та припинити послугу звичайним способом. Наприклад, на базі системи Debian:

$ service myapp start

ПорадаЯкщо ваша програма не запускається, перевірте, чи записаний файл журналу на /var/log/<appname>.logнаявність помилок.

Продовжуйте читати, щоб знати, як забезпечити розгорнуту послугу.

Зробивши так, як написано, я виявив, що моя служба не починається з цього повідомлення про помилку в журналах: start-stop-daemon: нерозпізнана опція --no-close . І мені вдалося це виправити, створивши конфігураційний файл /var/myapp/myapp.confіз наступним вмістом

USE_START_STOP_DAEMON=false

1

У мене є програма Netty java, і я хочу запустити її як сервіс з systemd. На жаль, додаток зупиняється незалежно від того, який тип я використовую. Наприкінці я загорнув на екран java start. Ось конфігураційні файли:

сервіс

[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

почати

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

з цього моменту ви можете використовувати systemctl [start|stop|status] service.


1

Щоб запустити код Java як демон (послуга), ви можете написати заглушку на базі JNI.

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

для зразкового коду, який базується на JNI. У цьому випадку ви демонструєте код, який був запущений як Java, а основний цикл виконується в C. Але також можна помістити основний, демоновий, цикл обслуговування всередині Java.

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

Веселіться з JNI!


0

Однак, як тільки почалося, я не знаю, як отримати доступ до нього, щоб зупинити його

Ви можете написати простий сценарій зупинки, який охоплює ваш Java-процес, витягує PID і вбиває виклики. Це не фантазії, але прямо вперед. Щось таке може допомогти для початку:

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

2
Я не дуже хороший в Linux, але не робить pkill nameofprocessщось те саме?
Denys Séguret

0

Можна запустити війну як службу Linux, і ви, можливо, захочете ввести файл у файл pom.xml перед упаковкою, оскільки деякі дистрибутиви не можуть розпізнати в автоматичному режимі. Для цього додайте наступне властивість у плагін spring-boot-maven-plugin.

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

Потім налаштуйте свій файл init.d за допомогою:

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

і ти зможеш бігати

service myapp start|stop|restart

Є багато інших варіантів, які ви можете знайти в документації Spring Boot , включаючи службу Windows.

Використовуючи наш веб-сайт, ви визнаєте, що прочитали та зрозуміли наші Політику щодо файлів cookie та Політику конфіденційності.
Licensed under cc by-sa 3.0 with attribution required.