Приложение Spring Boot в качестве службы

Как настроить красиво весеннее загрузочное приложение, упакованное как исполняемый jar в качестве службы в системе linux? Это рекомендуемый подход, или я должен преобразовать это приложение в war и установить в Tomcat?

В настоящее время я могу запустить приложение Spring boot из screen сессия, что приятно, но требует ручного запуска после перезагрузки сервера.

то, что я ищу, - это общий совет / направление или образец init.d скрипт, если мой подход с исполняемым jar это правильно.

16 ответов


следующие работы для springboot 1.3 и выше:

как init.обслуживание D

исполняемый jar имеет обычные команды запуска, остановки, перезапуска и состояния. Он также настроит PID-файл в обычном каталоге /var/run и по умолчанию войдет в обычный каталог /var/log.

вам просто нужно символически связать свою банку с /etc / init.d хотелось бы так

sudo link -s /var/myapp/myapp.jar /etc/init.d/myapp

или

sudo ln -s ~/myproject/build/libs/myapp-1.0.jar /etc/init.d/myapp_servicename

после этого вы можете сделать обычный

/etc/init.d/myapp start

затем настройте ссылку на любом уровне запуска, который вы хотите, чтобы приложение запускалось / останавливалось при загрузке, если это необходимо.


как служба systemd

для запуска приложения Spring Boot, установленного в var/myapp, вы можете добавить следующий скрипт в /etc/systemd/system/myapp.обслуживание:

[Unit]
Description=myapp
After=syslog.target

[Service]
ExecStart=/var/myapp/myapp.jar

[Install]
WantedBy=multi-user.target


ссылка

http://docs.spring.io/spring-boot/docs/current-SNAPSHOT/reference/html/deployment-install.html#deployment-service


ниже приведен самый простой способ установить приложение Java в качестве системной службы в Linux.

предположим, вы используете systemd (что в настоящее время делает любой современный дистрибутив):

во-первых, создайте файл службы в /etc/systemd/system по имени, например javaservice.service С таким содержанием:

[Unit]
Description=Java Service

[Service]
User=nobody
# The configuration file application.properties should be here:
WorkingDirectory=/data 
ExecStart=/usr/bin/java -Xmx256m -jar application.jar
SuccessExitStatus=143
TimeoutStopSec=10
Restart=on-failure
RestartSec=5

[Install]
WantedBy=multi-user.target

во-вторых, уведомить systemd нового файла сервиса:

systemctl daemon-reload

и включите его, чтобы он работал при загрузке:

systemctl enable javaservice.service

в конце концов, вы можете использовать следующие команды для запуска / остановки новой службы:

systemctl start javaservice
systemctl stop javaservice
systemctl restart javaservice
systemctl status javaservice

если вы используете systemd, это самый ненавязчивый и чистый способ настроить приложение Java как системную службу.

что мне особенно нравится в этом решении, так это то, что вам не нужно устанавливать и настраивать любое другое программное обеспечение. Погруженный systemd делает всю работу за вас, и ваша служба ведет себя как любая другая системная служба. Я использую его в производстве некоторое время, на разные дистрибутивы, и он работает так, как вы ожидаете.

еще один плюс в том, что с помощью /usr/bin/java, вы можете легко добавить jvm параметры, такие как -Xmx256m.

Читайте также systemd часть в официальной документации Spring Boot: http://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html


вы также можете использовать supervisord который является очень удобным демоном, который можно использовать для легкого управления службами. Эти службы определяются простыми конфигурационными файлами, определяющими, что выполнять с каким пользователем, в каком каталоге и так далее, есть множество опций. supervisord имеет очень простой синтаксис, поэтому он делает очень хорошую альтернативу написанию сценариев инициализации SysV.

здесь простой supervisord файл конфигурации для программа, которую вы пытаетесь запустить / control. (положите это в / etc/supervisor / conf.d / yourapp.conf)

/etc / supervisor / conf.d / yourapp.conf

[program:yourapp]
command=/usr/bin/java -jar /path/to/application.jar
user=usertorun
autostart=true
autorestart=true
startsecs=10
startretries=3
stdout_logfile=/var/log/yourapp-stdout.log
stderr_logfile=/var/log/yourapp-stderr.log

для управления приложением, вам нужно выполнить supervisorctl, который представит вам подсказку, где вы можете начать, остановить, статус yourapp.

командной строки

# sudo supervisorctl
yourapp             RUNNING   pid 123123, uptime 1 day, 15:00:00
supervisor> stop yourapp
supervisor> start yourapp

если supervisord демон уже запущен и вы добавили конфигурации для обслуживания без перезапуска демона вы можете просто сделать reread и на supervisorctl shell.

это действительно дает вам все flexibilites вы бы с помощью сценариев SysV Init, но простой в использовании и управлении. Взгляните на документация.


Я только что собрался сделать это сам, так что следующее, Где я до сих пор с точки зрения CentOS init.D сценарий контроллера службы. До сих пор он работал довольно хорошо, но я не хакер leet Bash, поэтому я уверен, что есть место для улучшения, поэтому мысли об улучшении приветствуются.

прежде всего, у меня есть короткий скрипт конфигурации /data/svcmgmt/conf/my-spring-boot-api.sh для каждой службы, которая устанавливает переменные окружения.

#!/bin/bash
export JAVA_HOME=/opt/jdk1.8.0_05/jre
export APP_HOME=/data/apps/my-spring-boot-api
export APP_NAME=my-spring-boot-api
export APP_PORT=40001

Я использую CentOS, чтобы убедиться, что мои услуги запущенный после перезагрузки сервера, у меня есть сценарий управления службой в /etc/init.d/my-spring-boot-api:

#!/bin/bash
# description: my-spring-boot-api start stop restart
# processname: my-spring-boot-api
# chkconfig: 234 20 80

. /data/svcmgmt/conf/my-spring-boot-api.sh

/data/svcmgmt/bin/spring-boot-service.sh 

exit 0

как вы можете видеть, это вызывает сценарий начальной конфигурации для настройки переменных среды, а затем вызывает общий скрипт, который я использую для перезапуска всех моих служб загрузки Spring. Этот общий скрипт - это то, где мясо всего этого можно найти:

#!/bin/bash

echo "Service [$APP_NAME] - []"

echo "    JAVA_HOME=$JAVA_HOME"
echo "    APP_HOME=$APP_HOME"
echo "    APP_NAME=$APP_NAME"
echo "    APP_PORT=$APP_PORT"

function start {
    if pkill -0 -f $APP_NAME.jar > /dev/null 2>&1
    then
        echo "Service [$APP_NAME] is already running. Ignoring startup request."
        exit 1
    fi
    echo "Starting application..."
    nohup $JAVA_HOME/bin/java -jar $APP_HOME/$APP_NAME.jar \
        --spring.config.location=file:$APP_HOME/config/   \
        < /dev/null > $APP_HOME/logs/app.log 2>&1 &
}

function stop {
    if ! pkill -0 -f $APP_NAME.jar > /dev/null 2>&1
    then
        echo "Service [$APP_NAME] is not running. Ignoring shutdown request."
        exit 1
    fi

    # First, we will try to trigger a controlled shutdown using 
    # spring-boot-actuator
    curl -X POST http://localhost:$APP_PORT/shutdown < /dev/null > /dev/null 2>&1

    # Wait until the server process has shut down
    attempts=0
    while pkill -0 -f $APP_NAME.jar > /dev/null 2>&1
    do
        attempts=$[$attempts + 1]
        if [ $attempts -gt 5 ]
        then
            # We have waited too long. Kill it.
            pkill -f $APP_NAME.jar > /dev/null 2>&1
        fi
        sleep 1s
    done
}

case  in
start)
    start
;;
stop)
    stop
;;
restart)
    stop
    start
;;
esac
exit 0

останавливая, оно попытается использовать привод ботинка весны для того чтобы выполнить контролируемое выключение. Однако, в случае если привод нет настроенный или не завершающий работу в течение разумного периода времени (я даю ему 5 секунд, что немного коротко), процесс будет убит.

кроме того, скрипт делает предположение, что процесс java, выполняющий appllication, будет единственным с "my-spring-boot-api.jar " в тексте описания процесса. Это безопасное предположение в моей среде и означает, что мне не нужно отслеживать PIDs.


если вы хотите использовать Spring Boot 1.2.5 с плагином Spring Boot Maven 1.3.0.M2, вот решение:

<parent>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-parent</artifactId>
    <version>1.2.5.RELEASE</version>
</parent>

<build>
    <plugins>
        <plugin>
            <groupId>org.springframework.boot</groupId>
            <artifactId>spring-boot-maven-plugin</artifactId>
            <version>1.3.0.M2</version>
            <configuration>
                <executable>true</executable>
            </configuration>
        </plugin>
    </plugins>
</build>

<pluginRepositories>
    <pluginRepository>
        <id>spring-libs-milestones</id>
        <url>http://repo.spring.io/libs-milestone</url>
    </pluginRepository> 
</pluginRepositories>

затем скомпилируйте как ususal:mvn clean package, создайте символическую ссылку ln -s /.../myapp.jar /etc/init.d/myapp, сделайте его исполняемым chmod +x /etc/init.d/myapp и запустить его service myapp start (С сервером Ubuntu)


Я знаю, это старый вопрос, но я хотел бы представить еще один способ, который является appassembler-maven-плагин. Вот соответствующая часть из моего POM, которая включает в себя много дополнительных значений опций, которые мы нашли полезными:

<plugin>
    <groupId>org.codehaus.mojo</groupId>
    <artifactId>appassembler-maven-plugin</artifactId>
    <configuration>
        <generateRepository>true</generateRepository>
        <repositoryLayout>flat</repositoryLayout>
        <useWildcardClassPath>true</useWildcardClassPath>
        <includeConfigurationDirectoryInClasspath>true</includeConfigurationDirectoryInClasspath>
        <configurationDirectory>config</configurationDirectory>
        <target>${project.build.directory}</target>
        <daemons>
            <daemon>
                <id>${installer-target}</id>
                <mainClass>${mainClass}</mainClass>
                <commandLineArguments>
                    <commandLineArgument>--spring.profiles.active=dev</commandLineArgument>
                    <commandLineArgument>--logging.config=${rpmInstallLocation}/config/${installer-target}-logback.xml</commandLineArgument>
                </commandLineArguments>
                <platforms>
                    <platform>jsw</platform>
                </platforms>
                <generatorConfigurations>
                    <generatorConfiguration>
                        <generator>jsw</generator>
                        <includes>
                            <include>linux-x86-64</include>
                        </includes>
                        <configuration>
                            <property>
                                <name>wrapper.logfile</name>
                                <value>logs/${installer-target}-wrapper.log</value>
                            </property>
                            <property>
                                <name>wrapper.logfile.maxsize</name>
                                <value>5m</value>
                            </property>
                            <property>
                                <name>run.as.user.envvar</name>
                                <value>${serviceUser}</value>
                            </property>
                            <property>
                                <name>wrapper.on_exit.default</name>
                                <value>RESTART</value>
                            </property>
                        </configuration>
                    </generatorConfiguration>
                </generatorConfigurations>
                <jvmSettings>
                    <initialMemorySize>256M</initialMemorySize>
                    <maxMemorySize>1024M</maxMemorySize>
                    <extraArguments>
                        <extraArgument>-server</extraArgument>
                    </extraArguments>
                </jvmSettings>
            </daemon>
        </daemons>
    </configuration>
    <executions>
        <execution>
            <id>generate-jsw-scripts</id>
            <phase>package</phase>
            <goals>
                <goal>generate-daemons</goal>
            </goals>
        </execution>
    </executions>
</plugin>

в этом вопросе ответ от @PbxMan должен заставить вас начать:

запустите приложение Java как службу в Linux

Edit:

есть другой, менее приятный способ начать процесс при перезагрузке, используя cron:

@reboot user-to-run-under /usr/bin/java -jar /path/to/application.jar

это работает, но не дает вам хороший интерфейс запуска/остановки для вашего приложения. Вы все еще можете просто kill это в любом случае...


мой скрипт SysVInit для Centos 6 / RHEL (еще не идеальный). Этот скрипт требует ApplicationPidListener.

источник /etc/init.d/app

#!/bin/sh
#
# app Spring Boot Application 
#
# chkconfig:   345 20 80
# description: App Service
#           

### BEGIN INIT INFO
# Provides: App
# Required-Start: $local_fs $network
# Required-Stop: $local_fs $network
# Default-Start: 3 4 5 
# Default-Stop: 0 1 2 6
# Short-Description: Application
# Description:      
### END INIT INFO

# Source function library.
. /etc/rc.d/init.d/functions

# Source networking configuration.
. /etc/sysconfig/network

exec="/usr/bin/java"
prog="app"
app_home=/home/$prog/
user=$prog

[ -e /etc/sysconfig/$prog ] && . /etc/sysconfig/$prog

lockfile=/var/lock/subsys/$prog    
pid=$app_home/$prog.pid

start() {

    [ -x $exec ] || exit 5
    [ -f $config ] || exit 6
    # Check that networking is up.
    [ "$NETWORKING" = "no" ] && exit 1
    echo -n $"Starting $prog: "
    cd $app_home
    daemon --check $prog --pidfile $pid --user $user $exec $app_args &
    retval=$?
    echo
    [ $retval -eq 0 ] && touch $lockfile
    return $retval
}

stop() {
    echo -n $"Stopping $prog: "
    killproc -p $pid $prog
    retval=$?
    [ $retval -eq 0 ] && rm -f $lockfile
    return $retval
}

restart() {
    stop
    start
}

reload() {
    restart
}

force_reload() {
    restart
}

rh_status() {
    status -p $pid $prog
}

rh_status_q() {
    rh_status >/dev/null 2>&1
}

case "" in
    start)
        rh_status_q && exit 0
        
        ;;
    stop)
        rh_status_q || exit 0
        
        ;;
    restart)
        
        ;;
    reload)
        rh_status_q || exit 7
        
        ;;
    force-reload)
        force_reload
        ;;
    status)
        rh_status
        ;;
    condrestart|try-restart)
        rh_status_q || exit 0
        restart
        ;;
    *)
        echo $"Usage:  {start|stop|status|restart|condrestart|try-restart|reload|force-reload}"
        exit 2
esac
exit $?

пример файла config /etc/sysconfig/app:

exec=/opt/jdk1.8.0_05/jre/bin/java

user=myuser
app_home=/home/mysuer/

app_args="-jar app.jar"

pid=$app_home/app.pid

вот сценарий, который развертывает исполняемый jar как службу systemd.

Он создает пользователя для обслуживания и .файл службы и поместите файл jar под /var и сделайте некоторую базовую блокировку привилегий.

#!/bin/bash

# Argument: The jar file to deploy
APPSRCPATH=

# Argument: application name, no spaces please, used as folder name under /var
APPNAME=

# Argument: the user to use when running the application, may exist, created if not exists
APPUSER=

# Help text
USAGE="
Usage: sudo  <jar-file> <app-name> <runtime-user>
If an app with the name <app-name> already exist, it is stopped and deleted.
If the <runtime-user> does not already exist, it is created.
"

# Check that we are root
if [ ! "root" = "$(whoami)" ]; then
    echo "Must be root. Please use e.g. sudo"
    echo "$USAGE"
    exit
fi

# Check arguments
if [ "$#" -ne 3 -o ${#APPSRCPATH} = 0 -o ${#APPNAME} = 0 -o ${#APPUSER} = 0 ]; then
    echo "Incorrect number of parameters."
    echo "$USAGE"
    exit
fi

if [ ! -f $APPSRCPATH ]; then
    echo "Can't find jar file $APPSRCPATH"
    echo "$USAGE"
    exit
fi

# Infered values
APPFILENAME=$(basename $APPSRCPATH)
APPFOLDER=/var/javaapps/$APPNAME
APPDESTPATH=$APPFOLDER/$APPFILENAME

# Stop the service if it already exist and is running
systemctl stop $APPNAME >/dev/null 2>&1

# Create the app folder, deleting any previous content
rm -fr $APPFOLDER
mkdir -p $APPFOLDER

# Create the user if it does not exist
if id "$APPUSER" >/dev/null 2>&1; then
    echo "Using existing user $APPUSER"
else
    adduser --disabled-password --gecos "" $APPUSER
    echo "Created user $APPUSER"
fi

# Place app in app folder, setting owner and rights
cp $APPSRCPATH $APPDESTPATH
chown $APPUSER $APPDESTPATH
chmod 500 $APPDESTPATH
echo "Added or updated the $APPDESTPATH file"

# Create the .service file used by systemd
echo "
[Unit]
Description=$APPNAME
After=syslog.target
[Service]
User=$APPUSER
ExecStart=/usr/bin/java -jar $APPDESTPATH
SuccessExitStatus=143
[Install]
WantedBy=multi-user.target
" > /etc/systemd/system/$APPNAME.service
echo "Created the /etc/systemd/system/$APPNAME.service file"

# Reload the daemon
systemctl daemon-reload

# Start the deployed app
systemctl start $APPNAME
systemctl status $APPNAME

пример: enter image description here


Я пытаюсь сделать приложения springboot, которые представлены как " init.D " стиль оболочки скрипта со сжатым java-приложением, прикрепленным к концу

путем символической ссылки этих скриптов из /etc / init.d / spring-app to/opt / spring-app.jar и chmod'ING банку, чтобы быть исполняемым можно сделать " / etc / init.д/весны-начала приложения" "/и т. д./init.D / spring-App stop " и другие возможности, такие как status work

предположительно, как init.D стиль скриптов из springboot look что у них есть необходимые Волшебные струны (например,# Default-Start: 2 3 4 5) chkconfig сможет добавить его как "сервис"

но я хотел заставить его работать с systemd

чтобы сделать эту работу, я пробовал многие рецепты в других ответах выше, но никто из них не работал для меня на Centos 7.2 с Springboot 1.3 в основном они начнут службу, но не смогут отслеживать pid

В итоге я нашел следующие работал для меня, когда / etc / init.D Ссылка была на месте. Файл, подобный приведенному ниже, должен быть установлен как /usr/lib/systemd/system/spring-app.service

[Unit]
Description=My loverly application
After=syslog.target 

[Service]
Type=forking
PIDFile=/var/run/spring-app/spring-app.pid
ExecStart=/etc/init.d/spring-app start
SuccessExitStatus=143

[Install]
WantedBy=multi-user.target

Я не знаю "стандартного" термоусадочного способа сделать это с помощью Java-приложения, но это определенно хорошая идея (вы хотите воспользоваться возможностями keep-alive и мониторинга операционной системы, если они есть). Это на Дорожной карте, чтобы обеспечить что-то из поддержки Spring Boot tool (maven и gradle), но пока вам, вероятно, придется свернуть свой собственный. Лучшее решение я знаю сейчас старшина, который имеет декларативный подход и в одну линию команды для упаковки сценариев init для различных стандартных форматов ОС (monit, sys V, upstart и др.). Есть также доказательства того, что люди создали материал с gradle (например,здесь).


вы используете Maven? Затем вы должны попробовать плагин AppAssembler:

плагин Application Assembler-это плагин Maven для генерации скриптов для запуска приложений java. ... Все артефакты (зависимости + артефакт из проекта) добавляются в путь к классам в созданных сценариях bin.

Поддерживаемые платформы:

в Unix-вариантов

Windows NT (Windows 9x не поддерживается)

Java Service Wrapper (JSW)

см.:http://mojo.codehaus.org/appassembler/appassembler-maven-plugin/index.html


Это можно сделать с помощью службы Systemd в Ubuntu

<code>
[Unit]
Description=A Spring Boot application
After=syslog.target

[Service]
User=baeldung
ExecStart=/path/to/your-app.jar SuccessExitStatus=143

[Install] 
WantedBy=multi-user.target
</code>

вы можете перейти по этой ссылке для более подробного описания и различных способов сделать это. http://www.baeldung.com/spring-boot-app-as-a-service


КАК СЛУЖБА WINDOWS

если вы хотите, чтобы это работало в машине windows, загрузите winsw.exe из

 http://repo.jenkins-ci.org/releases/com/sun/winsw/winsw/2.1.2/

после этого переименуйте его в имя файла jar (например:your-app.jar)

winsw.exe -> your-app.exe

Теперь создайте xml-файл your-app.в XML и скопируйте следующий контент

<?xml version="1.0" encoding="UTF-8"?>
<service>
     <id>your-app</id>
     <name>your-app</name>
     <description>your-app as a Windows Service</description>
     <executable>java</executable>
     <arguments>-jar "your-app.jar"</arguments>
     <logmode>rotate</logmode>
</service>

убедитесь, что exe-файла и xml вместе с jar в одном и том же папка.

после этого открытия командная строка в Administrator previlege и установите его в службу windows.

your-app.exe install
eg -> D:\Springboot\your-app.exe install

если это не удается с

Error: Registry key 'Software\JavaSoft\Java Runtime Environment'\CurrentVersion' has value '1.8', but '1.7' is required.

затем попробуйте следующее:

Delete java.exe, javaw.exe and javaws.exe from C:\Windows\System32

вот и все :) .

для удаления службы в windows

your-app.exe uninstall

для see/run / stop service: win+r и типа администрирование выберите сервис от этого. Тогда щелкните правой кнопкой мыши выбрать опция-run / stop


следуя за отличным ответом Чада, если вы получите ошибку "ошибка: не удалось найти или загрузить главный класс" - и вы тратите пару часов, пытаясь устранить его, будь то выполнение сценария оболочки, который запускает ваше java-приложение или запуск его из самого systemd - и вы знаете, что ваш путь к классам на 100% правильный, например, ручной запуск сценария оболочки работает, а также запуск того, что у вас есть в systemd execstart. обязательно вы используете вещи как правильные пользователь! В моем случае я пробовал разных пользователей, после довольно долгого устранения неполадок - у меня, наконец, было предчувствие, поставил root как пользователь-вуаля, приложение началось правильно. После определения, что это была неправильная проблема пользователя, I chown -R user:user папка и подпапки и приложение работали правильно, как указанный пользователь и группа, поэтому больше не нужно запускать его как root (плохая безопасность).


в файлах блока systemd вы можете установить каталог переменных среды или через EnvironmentFile. Я бы предложил делать все таким образом, поскольку это кажется наименьшим количеством трений.

пример файла блока

$ cat /etc/systemd/system/hello-world.service
[Unit]
Description=Hello World Service
After=systend-user-sessions.service

[Service]
EnvironmentFile=/etc/sysconfig/hello-world
Type=simple
ExecStart=/usr/bin/java ... hello-world.jar

затем настройте файл под /etc/sysconfig/hello-world который включает в себя заглавные имена ваших переменных загрузки Spring. Например, переменная server.port будет следовать форме SERVER_PORT в качестве переменной среды:

$ cat /etc/sysconfig/hello-world
SERVER_PORT=8081

механизм здесь используется то, что приложения Spring Boot возьмут список свойств, а затем переведут их, сделав все прописными буквами и заменив точки подчеркиванием. Как только приложение Spring Boot проходит этот процесс, оно ищет соответствующие переменные среды и использует любые найденные соответственно.

это выделено более подробно в этом SO Q & A под названием:как установить свойство Spring Boot с подчеркиванием в его имени через среду Переменные?

ссылки