Если вы видите что-то необычное, просто сообщите мне. Skip to main content

Run a Java Application as a Service on Linux

  1. Introduction

Введение

AnyЛюбое Java applicationприложение fromс theточки systemзрения point-of-viewсистемы isэто justпросто anобъект instanceJVM. ofВ theэтом Javaкоротком Virtualруководстве Machine.мы Inувидим, thisкак shortмы tutorial,можем we’llсделать seeнаше howприложение we can make our applications run as system services.сервисом.

We’llМы useбудем theистользовать facilitiesудобства ofпакета thesystem, systemd softwareэто package.сервис systemdуправления isсистемой theв initializationсовременных andдистрибутивах service management system in most modern Linux distributions.Linux.

ThroughoutЗдесь theвы tutorial,найдёте we’llдве considerреализации: twoодна implementations:для oneпростого forслучая, aдругая simple- case and one for a more advanced case. 2. Simple Serviceрасширенная.

Простой сервис

InВ theмире systemdsystemd, world,для toсоздания createсистемного aсервиса, systemнам service,нужно weподготовить needфайл toи prepareзарегистрировать aего unitопределённым fileспособом. andНачнём registerс itсодержания the proper way. We’ll discuss the file location shortly, but first, let’s start with the content:файла:

[Unit]
Description=My Java driven simple service
After=syslog.target network.target

[Service]
SuccessExitStatus=143

User=appuser
Group=appgroup

Type=simple

Environment="JAVA_HOME=/path/to/jvmdir"
WorkingDirectory=/path/to/app/workdir
ExecStart=${JAVA_HOME}/bin/java -jar javaapp.jar
ExecStop=/bin/kill -15 $MAINPID

[Install]
WantedBy=multi-user.target

WeМы setузнали theтип Typeсервиса ofпростым serviceпотому toчто simpleсистема because the system starts theначинает JVM processпроцесс directly,напрямую withoutбез spawningсоздания aдочернего child process.процесса.

ExecStop specifiesуказывает theкоманду serviceзавершения, termination command, andи systemd isдостаточно smartумен enoughчтобы to figure out theвыяснить PID ofначального theпроцесса. startedон process.автоматически It automatically creates aсоздаёт MAINPID environmentпеременные variable.окружения.

Then,После, weмы instructуказываем systemd to send aпосылать 15 (SIGTERM) systemсистемный signalсигнал, toчтобы terminateзавершить the process gracefully.процесс.

The JVM designers made Java returnсоздатели aспроектировали non-zeroего exitтаким codeобразом, inчтобы caseон itвозвращал isне terminatedнулевой byкод aв systemслучае signal.если Asон aзавершён non-zeroсистемным base,сигналом. theyТак tookкак 128,сигнал andне theнулевой, resultingто exitответ codeбудет is a sum of 128 and+ theчисловое signalзначение numeric value.сигнала.

ByУ settingказывая SuccessExitStatus toкак 143, weмы tellговорим systemd toотловить handleэто that value значение(128+15) asкак aнормальное normalзавершение

exit.

Форкаем 3.сервис

Forking

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

TheЭто simpleможет service unit file above might be quite sufficient for trivial applications. However, more practical cases will probably include additional settings.

These can beбыть JVM parametersпараметры asтак wellже asкак anyлюбой otherдругой application-specificпараметр parameters,приложения, forдля example,примера, configфайл orконфигурации dataили fileданных. locations.Это Thatмодно mayсвести resultк inнаписанию writingобёртки a wrapperдля shell scriptскрипта, whereгде weмы canможем setнастроить upвсе allтребуемые theпараметры requiredпрежде parametersчем before starting theзапустить JVM.

Let’sПредоставим, imagineмы weуже alreadyимеем haveобертку aдля wrapperскрипта, scriptи andтеперь nowпросто justхотим wantвключить toэто turnв itсервис into a system service:систем:

#!/bin/bash

JAVA_HOME=/path/to/jvmdir
WORKDIR=/path/to/app/workdir
JAVA_OPTIONS=" -Xms256m -Xmx512m -server "
APP_OPTIONS=" -c /path/to/app.config -d /path/to/datadir "

cd $WORKDIR
"${JAVA_HOME}/bin/java" $JAVA_OPTIONS -jar javaapp.jar $APP_OPTIONS

SinceТак weкак useмы aиспользуем shell scriptскрипт toчтобы startзапустить the service, theсервис, JVM willбудет beзапущена startedс by theпомощью shell (bash)скрипта. process.Эта Thisоперация operationизвестна isкак knownfork, asи fork,поэтому andмы it’sуказали whyтип weкак set the service Type to forking.forking.

MovingПеренесём variableопеределения definitionsпеременных intoв theтело script’s body also makes the unit file more concise:скрипта:

[Unit]
Description=My Java forking service
After=syslog.target network.target
[Service]
SuccessExitStatus=143
User=appuser
Group=appgroup

Type=forking

ExecStart=/path/to/wrapper
ExecStop=/bin/kill -15 $MAINPID

[Install]
WantedBy=multi-user.target

    Регистрируем
  1. Registeringи andзапускаем Running the Service
сервис

NoНе matterважно whatкакой serviceтип typeсервиса weвыбран, choose,для toвыполнения completeзадачи, theмы mission,должны weзнать, mustкак knowнастроить howи toзапустить setсам upsystemd and run the system service itself.сервис.

First, we need to name the unit file after the service name we want to have. In our examples, that could be javasimple.service or javaforking.service.

Then, we put the unit file under one of the locations where systemd can find it. For an arbitrary service, /etc/systemd/system is a good choice.

The full path to our system units, in that case, will be:

/etc/systemd/system/javasimple.service
/etc/systemd/system/javaforking.service

Another possible path to place system units is /usr/lib/systemd/system. This is typically the location used by the system installation packages.

However, we should consider it more appropriate when we develop our own .rpm or .deb installation packages containing system services.

In either case, we’ll control the service using the systemctl utility and pass either the start, stop, or status command.

Before that, however, we should notify systemd that it has to rebuild its internal service database. Doing this will make it aware of the new system unit we introduced. We can do this by passing the daemon-reload command to systemctl.

Now, we’re ready to run all the commands we mentioned:

sudo systemctl daemon-reload

sudo systemctl start javasimple.service
sudo systemctl status javasimple.service

● javasimple.service - My Java driven simple service
Loaded: loaded (/etc/systemd/system/javasimple.service; disabled; vendor preset: disabled)
Active: active (running) since Sun 2021-01-17 20:10:19 CET; 8s ago
Main PID: 8124 (java)
CGroup: /system.slice/javasimple.service
└─8124 /path/to/jvmdir/bin/java -jar javaapp.jar

We’ll need to run the daemon-reload command each time we modify the unit file.

Next, we notice the system reports our service running but disabled. Disabled services will not start automatically when the system boots.

Of course, we can configure it to start up automatically along with the system. This is where we use another systemctl command — enable:

sudo systemctl enable javasimple.service
Created symlink from /etc/systemd/system/multi-user.target.wants/javasimple.service to /etc/systemd/system/javasimple.service

Now, we can see that it’s enabled:

sudo systemctl status javasimple.service
● javasimple.service - My Java driven simple service
Loaded: loaded (/etc/systemd/system/javasimple.service; enabled; vendor preset: disabled)
Active: active (running) since Sun 2021-01-17 20:10:19 CET; 14min ago
Main PID: 8124 (java)
....
  1. Conclusion

In this article, we looked at two possible ways of turning Java applications into system service by means of systemd.

Java is still one of the most popular programming languages. A lot of Java applications are designed to run non-interactively for a variety of tasks, such as processing data, providing an API, monitoring events, and so on. Thus, they all are good candidates to become system services.