LinuxでJavaアプリケーションをサービスとして実行する


128

標準の仮想ホストLinuxソリューションで実行されるJavaサーバーアプリケーションを作成しました。アプリケーションは、常にソケット接続をリッスンし、それらの新しいハンドラーを作成して実行されます。これは、クライアントサーバーアプリケーションへのサーバー側の実装です。

私がそれを開始する方法は、サーバーのスタートアップrc.localスクリプトに含めることです。ただし、いったん起動すると、アクセスして停止する方法がわからず、更新をインストールする必要がある場合は、アプリケーションを再起動するためにサーバーを再起動する必要があります。

Windows PCでは、このタイプのアプリケーションの場合、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これをありがとう。私はそれをやってみて、私たちがどのように乗るかを見るかもしれません。乾杯。
dreza 2014年

2
しかし、このファイルをどのように実行できますか?どこに置く必要がありますか?
ジャックダニエル

3
@JackDanielは、Debianベースのディストリビューション(debian自体やubuntuなど)で、/ etc / init.dにそのスクリプトを追加できます。次に、次のように呼び出します:/etc/init.d/MyService start。そして、update-rc.d MyService defaultsを実行することで、自動的に開始することができます。
Andre

1
@ThorbjørnRavnAndersenそれはあなたのJavaプログラムに依存するでしょう。Javaプログラムを強制終了できない場合は、stackoverflow.com / questions / 2541597 / …を確認してください。killの代わりにMyService-pidを削除し、Javaパーツにデーモンスレッドが存在するかどうかを確認します。
PbxMan 2017

1
jarの出力ファイルはどこにありますか?名前を設定するにはどうすればよいですか?
M.シェーナ2017

48

簡単な解決策は、nohupを介してJavaを実行し、PIDをファイルに保存するスクリプトstart.shを作成することです。

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コマンドでプロセスが終了せずに強制終了されないのですか?データベースとインターフェイスするサーバープログラムを作成しています。プログラムがDBへの書き込みの途中で停止しないように、プログラムが終了する前に、現在実行中のすべてのスレッドを終了する必要があります。 。
スキューバスティーブ

2
@ scuba-steveのようなものです。killはTERMシグナルを送信します。これにより、所定のシャットダウンフックが呼び出されるため、それらを使用してプロセスを正常に終了します。プロセスがkillシグナル(つまり、kill -9)を受け取った場合は実行されません。シャットダウンフックの完了に時間がかかりすぎると、OSがシャットダウンフックを中断する可能性があるため、簡潔にしてください
rjohnston

34

Linuxサービスの初期化スクリプトはに保存され/etc/init.dます。/etc/init.d/skeletonファイルをコピーしてカスタマイズしてから、

service [yourservice] start|stop|restart

http://www.ralfebert.de/blog/java/debian_daemon/を参照してください。Debian(つまり、Ubuntu)向けですが、より多くのディストリビューションに適合します。


有望に見えます。これについて詳しく調べます。歓声
dreza

11

多分、最良のdev-opsソリューションではないかもしれませんが、LANパーティーなどのサーバーの一般的な使用には適しています。

を使用screenしてサーバーを実行し、ログアウトする前にデタッチします。これにより、プロセスが実行されたままになり、いつでも再接続できます。

ワークフロー:

画面を起動します。 screen

サーバーを起動します。 java -jar minecraft-server.jar

を押して切り離す:Ctl-ad

再接続: screen -r

詳細はこちら:https : //www.gnu.org/software/screen/manual/screen.html



5

Spring Boot application as a Serviceについても言及しますが、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

サービスとして春ブートアプリケーション、私はPythonベースの推薦することができsupervisord、アプリケーションを。詳細については、スタックオーバーフローの質問を参照してください。セットアップは本当に簡単です。


supervisord知らない人のために、それは可能に、素晴らしいです監視サービス(でなければならないforeground-ではないdaemonized)、それはその後、自動再起動サービスは(再起動がプラグインを経由して発生したときに警告を電子メールで送信することができます)します
wired00

2

その他の回答は、プラットフォームに応じてカスタムスクリプトと設定を提供するのに適しています。これらに加えて、ここに私が知っている成熟した特別目的プログラムがあります:

  • TanukiSoftwareのJSW
  • YAJSWは、上記のオープンソースクローンです。これはJavaで記述されており、構成に従って子プロセス(コード)を管理する乳母プロセスです。Windows / Linuxで動作します。
  • JSVCはネイティブアプリケーションです。ナニープロセスでもありますが、サブプロセスとしてではなく、JNIを介して子アプリケーションを呼び出します。


1

春ブーツリファレンスガイド

init.dサービスとしてのインストール(System V)

単純にするためにjarファイルをシンボリックリンクinit.d標準サポートするためにstartstoprestartおよびstatusコマンドを。Spring Bootアプリケーションが/ var / myappにインストールされていると想定して、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:unrecognized option --no-close。そして、私は/var/myapp/myapp.conf次の内容の設定ファイルを作成することでそれを修正することができました

USE_START_STOP_DAEMON=false

1

私はNetty Javaアプリケーションを持っていて、それをsystemdのサービスとして実行したいと思っています。残念ながら、使用しているTypeに関係なくアプリケーションが停止します。最後に、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を抽出して、killを呼び出す単純な停止スクリプトを作成できます。派手ではありませんが、簡単です。そのような何かが最初に役立つかもしれません:

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

2
私はLinuxがあまり得意ではありませpkill nameofprocessんが、同じことをしませんか?
DenysSéguret12年

0

一部のディストリビューションは自動モードで認識されない可能性があるため、戦争をLinuxサービスとして実行することは可能です。これを行うには、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サービスなど、他にも多くのオプションがあります。

弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.