The https://docs.spring.io/spring-boot/docs/current/reference/html/deployment-install.html
chapter 64.2.2 Installation as a systemd Service
is not complete.
Several points are not clear or just missing in documentation and will lead to "bad" system usage.
Service unit file according to documentation
[Service]
ExecStart=/opt/myApplication/myApplication.jar
SuccessExitStatus=143
will print out the stdout application logging into journalctl -xe
Jun 03 15:36:24 serverhostname myApplication.jar[25061]: Application is running as root (UID 0). This is considered insecure.
Jun 03 15:36:27 serverhostname myApplication.jar[25061]: . ____ _ __ _ _
Jun 03 15:36:27 serverhostname myApplication.jar[25061]: /\\ / ___'_ __ _ _(_)_ __ __ _ \ \ \ \
Jun 03 15:36:27 serverhostname myApplication.jar[25061]: ( ( )\___ | '_ | '_| | '_ \/ _` | \ \ \ \
Jun 03 15:36:27 serverhostname myApplication.jar[25061]: \\/ ___)| |_)| | | | | || (_| | ) ) ) )
Jun 03 15:36:27 serverhostname myApplication.jar[25061]: ' |____| .__|_| |_|_| |_\__, | / / / /
Jun 03 15:36:27 serverhostname myApplication.jar[25061]: =========|_|==============|___/=/_/_/_/
Jun 03 15:36:27 serverhostname myApplication.jar[25061]: :: Spring Boot :: (v2.1.1.RELEASE)
Jun 03 15:36:27 serverhostname myApplication.jar[25061]: 2019-06-03 15:36:27.765 INFO 25080 --- [ main]
and /var/log/messages
contains the full stdout application logging too.
In my case the JAR file with embedded Spring Boot Startup Script is not linked to /etc/init.d/
thus it is not recognized to run as init_script
and default action="run"
will apply.
To start the application via systemd service unit file, I need to set MODE=service
environment.
The example service unit starts fine, but never stops via systemctl stop myApplication.service
, because of missing ExecStop
:
[Service]
#Type=forking
Type=simple
Environment="JAVA_HOME=/opt/java"
Environment="MODE=service"
#Environment="DEBUG=1"
WorkingDirectory=/opt/myApplication
ExecStart=/opt/myApplication/myApplication.jar start
SuccessExitStatus=143
A kill <java pid>
is required :(
Simply adding ExecStop
statement is not working too:
[Service]
#Type=forking
Type=simple
Environment="JAVA_HOME=/opt/java"
Environment="MODE=service"
#Environment="DEBUG=1"
WorkingDirectory=/opt/myApplication
ExecStart=/opt/myApplication/myApplication.jar start
ExecStop=/opt/myApplication/myApplication.jar stop
SuccessExitStatus=143
because it results into start & stop together:
Jun 03 15:14:12 serverhostname myApplication.jar[24595]: Started [24620]
Jun 03 15:14:13 serverhostname myApplication.jar[24622]: myApplication is running as root (UID 0). This is considered insecure.
Jun 03 15:14:14 serverhostname myApplication.jar[24622]: Stopped [24620]
My only working service unit (in MODE=service
) is with usage of RemainAfterExit=yes
:
[Service]
#Type=forking
Type=simple
Environment="JAVA_HOME=/opt/java"
Environment="MODE=service"
#Environment="DEBUG=1"
WorkingDirectory=/opt/myApplication
ExecStart=/opt/myApplication/myApplication.jar start
RemainAfterExit=yes
ExecStop=/opt/myApplication/myApplication.jar stop
SuccessExitStatus=143
Comment From: vpavic
I think there's some confusion here as you seem to mix SysV-style init and systemd concerns.
In my case the JAR file with embedded Spring Boot Startup Script is not linked to /etc/init.d/ thus it is not recognized to run as init_script and default action="run" will apply.
With systemd you shouldn't be linking the executable JAR to /etc/init.d
- the only part of Spring Boot's embedded script that's really relevant for the systemd deployment is run
as systemd itself is more advanced init system that handles concerns such as PID file and log redirection (which are handled by embedded script in SysV-style init).
In fact, you could quite easily configure systemd descriptor for Spring Boot application without using embedded script at all but rather having a jar -jar
type command in the ExecStart
.
Comment From: psytester
I'm not sure I fully understood your point, or you mean mine.
My development provides a Spring-Boot application with this embedded launch script. I do the integration test and it has to run as a service in production.
It will be a SystemD with usage of systemctl <action> myApplikation
and service myApplikation <action>
, but if someone should set an init.d symlink and then do something via direct init.d call, it must still work reliably and failsafe. So e.g. do not start another process, but allow a stop or restart or only a status query.
I also don't want to set a symlink to /etc/init.d/ at all, as this will mix up too much.
As SystemD Service Unit I have to set the MODE=service
in any case, to use the other action cases in the launch script. Otherwise, action=run
is always used internally, even for a status query.
That the application started via SystemD ExecStart
can also be stopped again, an ExecStop
must of course be added. To prevent ExecStop
from being executed immediately on ExecStart, RemainAfterExit=yes
is required.
The complete log output to /var/log/messages
or as a separate file to /var/log/myApplication
is only prevented if I set the configuration exactly as specified with correct MODE
and action
Building and running the application as a stand alone JAR file is not my decision and why else should there be the launch script?
Some or most will certainly not even be aware of this behavior and there is this gap in the documentation.
Comment From: wilkinsona
Closing in favour of https://github.com/spring-projects/spring-boot/issues/28453.