Derek Mahar Derek Mahar - 9 days ago 4
Java Question

How do I build a Spring Boot jarfile that systemd can execute directly as a service?

How do I build a Spring Boot jarfile that systemd can directly execute as a service?

Following the example in Installation as a systemd service, I created the following systemd service that directly executes a Spring Boot jarfile:

[Unit]
Description=CRS Self-certification Service
Documentation=
Requires=postgresql.service
After=postgresql.service

[Service]
Environment=LOADER_PATH='lib/,config/,/etc/opes/crs/selfcertification'
ExecStart=/opt/opes/crs/selfcertification/crs-selfcertification-1.0.0-SNAPSHOT.jar
Restart=always
RestartSec=10
User=crs

[Install]
WantedBy=multi-user.target


However, when starting this service, systemd complains that the jarfile is not executable:

Nov 29 10:57:59 ubuntu systemd[24109]: selfcertification.service: Failed at step EXEC spawning /opt/opes/crs/selfcertification/crs-selfcertification-1.0.0-SNAPSHOT.jar: Exec format error
Nov 29 10:57:59 ubuntu systemd[1]: selfcertification.service: Main process exited, code=exited, status=203/EXEC
Nov 29 10:57:59 ubuntu systemd[1]: selfcertification.service: Unit entered failed state.
Nov 29 10:57:59 ubuntu systemd[1]: selfcertification.service: Failed with result 'exit-code'.


The permissions of the jarfile are
755
(executable by all):

administrator@ubuntu:~$ ls -la /opt/opes/crs/selfcertification/crs-selfcertification-1.0.0-SNAPSHOT.jar
-rwxr-xr-x 1 crs selfcertification 35978778 Nov 22 17:16 /opt/opes/crs/selfcertification/crs-selfcertification-1.0.0-SNAPSHOT.jar


What changes must I make to the following Gradle build script in order to build an executable jarfile for the systemd service?

buildscript {
ext {
springBootVersion = '1.4.2.RELEASE'
}
repositories {
mavenCentral()
}
dependencies {
classpath("org.springframework.boot:spring-boot-gradle-plugin:${springBootVersion}")
}
}

apply plugin: 'java'
apply plugin: 'eclipse'
apply plugin: 'org.springframework.boot'

jar {
baseName = 'crs-selfcertification'
version = '1.0.0-SNAPSHOT'
}

sourceCompatibility = 1.8
targetCompatibility = 1.8

repositories {
mavenCentral()
}

springBoot {
mainClass = "com.opessoftware.crs.selfcertification.Application"
layout = "ZIP"
}

dependencies {
compile("org.springframework.boot:spring-boot-starter-web")
compile("org.springframework.boot:spring-boot-starter-thymeleaf")
compile("org.springframework.boot:spring-boot-starter-data-jpa")
compile("org.springframework.boot:spring-boot-starter-mail")
testCompile("org.springframework.boot:spring-boot-starter-test")
compile group: 'org.postgresql', name: 'postgresql', version: '9.4.1208.jre7'
compile group: 'org.apache.commons', name: 'commons-dbcp2', version: '2.1.1'
compile group: 'junit', name: 'junit', version: '4.12'

}


Note that this service runs successfully if instead of trying to run the jarfile directly, systemd instead launches it using the Java Virtual Machine (JVM) from a shell script:

[Unit]
Description=CRS Self-certification Service
Documentation=
Requires=postgresql.service
After=postgresql.service

[Service]
Environment=LOADER_PATH='lib/,config/,/etc/opes/crs/selfcertification'
#ExecStart=/opt/opes/crs/selfcertification/crs-selfcertification-1.0.0-SNAPSHOT.jar
ExecStart=/opt/opes/crs/selfcertification/startCrsSelfCertification
Restart=always
RestartSec=10
User=crs

[Install]
WantedBy=multi-user.target


Shell script
/opt/opes/crs/selfcertification/startCrsSelfCertification
invokes the jarfile using the JVM:

#!/bin/sh

java -Dloader.path='lib/,config/,/etc/opes/crs/selfcertification' -jar /opt/opes/crs/selfcertification/crs-selfcertification-1.0.0-SNAPSHOT.jar


What might be missing from the Spring Boot jarfile that prevents systemd from executing the jarfile directly?

Answer

You should instruct Spring Boot to repackage your project into the fully executable form:

springBoot {
    executable = true
}

and this feature is only available for Spring Boot 1.4.0+.

Refer to http://docs.spring.io/spring-boot/docs/current/reference/html/build-tool-plugins-gradle-plugin.html#build-tool-plugins-gradle-repackage-configuration for more information.