a Sprint boot application
so let's start developing our application service and let it be RestAPI application so no front-end.
init
first will create a spring boot application using any method and add a spring web starter
add controller class
now add new class HomeController and add new end-point to return String message when call path "/".
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.RestController;
@RestControllerpublic class HomeController {
@GetMapping
public String getHomeWelcome(){
return "Welcome Home Debian";
}
}
now either start an application now or edit the server port, for me I will set server port in application.yaml and then start.
server:
port: 8088
service test
now to test this application will use curl
curl http://localhost:8088
and will see "Welcome Home Debian" in terminal
Test maven build
*Note: this project use java 11 and you can use java 8 but need change gradle-maven-plugin version.(until now there is no gradle-maven-plugin version work with java 17) if you have multiple versions of JDK you need to test if maven see what you run so run in terminal mvn -v and check if the not same version you need to update JAVA_HOME env . (for me because I use java 17 and also use lombok "because I will need it next" I need to check maven version is at least 3.8.3 and lombok version 1.18.22 )
now run maven build
mvn clean install -DskipTests
clean to make sure all old build was clean and -DskipTests to stop run tests . not we have a new folder called target and we have ${app.name}.jar file in it we can test run it
java -jar target/${app.name}.jar
and then test curl again curl http://localhost:8088 and now if I see output everything is work
Build configuration
now we need to add build configuration that let our application build using Gradle plugin so add inside build tag
<pluginManagement>
<plugins>
<plugin>
<groupId>org.thingsboard</groupId>
<artifactId>gradle-maven-plugin</artifactId>
<version>1.0.11</version>
</plugin>
</plugins>
</pluginManagement>
after that, we can follow these steps 1- add properties to describe all pkg name and the user will be run and also log location in the system and install location to use them in build next
<properties>
<java.version>1.8</java.version>
<pkg.name>deb_home</pkg.name>
<pkg.user>debuser</pkg.user>
<pkg.unixLogFolder>/var/log/${pkg.name}</pkg.unixLogFolder>
<pkg.installFolder>/usr/share/${pkg.name}</pkg.installFolder>
</properties>
2- add output deb Name using finalName tag in build and use resources tag to import all resources
<finalName>${pkg.name}-${project.version}</finalName>
<resources>
<resource>
<directory>${project.basedir}/src/main/resources</directory>
</resource>
</resources>
3- then use gradle-maven-plugin to build as Gradle so need to add a plugin in <build> and then in <plugins> to told maven to do that
<plugin>
<groupId>org.thingsboard</groupId>
<artifactId>gradle-maven-plugin</artifactId>
<configuration>
<tasks>
<task>build</task>
<task>buildDeb</task>
</tasks>
<args>
<arg>-PprojectBuildDir=${project.build.directory}</arg>
<arg>-PprojectVersion=${project.version}</arg>
<arg>-PmainJar=${project.build.directory}/${project.build.finalName}-boot.${project.packaging}</arg>
<arg>-PpkgName=${pkg.name}</arg>
<arg>-PpkgUser=${pkg.user}</arg>
<arg>-PpkgInstallFolder=${pkg.installFolder}</arg>
<arg>-PpkgLogFolder=${pkg.unixLogFolder}</arg>
</args>
</configuration>
<executions>
<execution>
<phase>package</phase>
<goals>
<goal>invoke</goal>
</goals>
</execution>
</executions>
</plugin>
now run mvn clean install -DskipTests. after waiting until download and build finish we have this error
FAILURE: Build failed with an exception.
* What went wrong:
Task 'buildDeb' not found in root project 'deb'.
so what is happened? the answer is there are basic things we don't do here,. This is Gradle project so we need build.gradle file that gradle will use it. but if we need build.gradle too what is a function of gradle-maven-plugin? the function of gradle-maven-plugin is not to replace gradle but to run gradle tasks. so let complete gradle needs.
4- create build.gradle and add this
import org.apache.tools.ant.filters.ReplaceTokens
buildscript {
repositories {
mavenCentral()
mavenLocal()
}
dependencies {
classpath("com.netflix.nebula:gradle-ospackage-plugin:9.0.0")
}
}
apply plugin: "nebula.ospackage"
buildDir = projectBuildDir
version = projectVersion
distsDirName = "./"
// OS Package plugin configuration
ospackage {
packageName = pkgName
version = "${project.version}"
release = 1
os = LINUX
type = BINARY
into pkgInstallFolder
user pkgUser
permissionGroup pkgUser
// Copy the actual .jar file
from(mainJar) {
// Strip the version from the jar filename
rename { String fileName ->
"${pkgName}.jar"
}
fileMode 0500
into "bin"
}
// Copy the config files
from("target/conf") {
exclude "application.conf"
fileType CONFIG | NOREPLACE
fileMode 0754
into "conf"
}
}
// Same as the buildRpm task
buildDeb {
arch = "all"
archiveName = "${pkgName}.deb"
requires("openjdk-11-jre").or("java11-runtime").or("oracle-java11-installer").or("openjdk-11-jre-headless")
from("target/conf") {
include "application.conf"
filter(ReplaceTokens, tokens: ['pkg.platform': 'deb'])
fileType CONFIG | NOREPLACE
fileMode 0754
into "${pkgInstallFolder}/conf"
}
configurationFile("${pkgInstallFolder}/conf/application.conf")
configurationFile("${pkgInstallFolder}/conf/application.yaml")
// configurationFile("${pkgInstallFolder}/conf/logback.xml") // you can add logback
preInstall file("${buildDir}/control/deb/preinst")
postInstall file("${buildDir}/control/deb/postinst")
preUninstall file("${buildDir}/control/deb/prerm")
postUninstall file("${buildDir}/control/deb/postrm")
user pkgUser
permissionGroup pkgUser
directory(pkgLogFolder, 0755)
link("/etc/init.d/${pkgName}", "${pkgInstallFolder}/bin/${pkgName}.jar")
link("${pkgInstallFolder}/bin/${pkgName}.yml", "${pkgInstallFolder}/conf/${pkgName}.yml")
link("/etc/${pkgName}/conf", "${pkgInstallFolder}/conf")
}
5- as you can see we need to set some configurations and installation scripts as follows
application.conf
used to set JAVA_OPTS and some env variable
export JAVA_OPTS="$JAVA_OPTS -Dplatform=@pkg.platform@"
export LOG_FILENAME=debhome.out
export LOADER_PATH=/usr/share/debhome/conf
application.yaml service setting and we alwardy have
preinst Script will be run before install deb used to set users and group
#!/bin/sh
if ! getent group debuser >/dev/null; then
addgroup --system debuser
fi
if ! getent passwd debuser >/dev/null; then
adduser --quiet \
--system \
--ingroup debuser \
--quiet \
--disabled-login \
--disabled-password \
--home /usr/share/debhome\
--no-create-home \
debuser
fi
postinst script will be run after install deb
#!/bin/sh
chown -R debuser: /var/log/debhome
chown -R debuser: /usr/share/debhome/conf
update-rc.d debhome defaults
prerm script run when removing the application from the system before start remove operation
#!/bin/sh
if [ -e /var/run/debhome/debhome.pid ]; then
service debhome stop
fi
postrm script run when removing application after remove done
#!/bin/sh
update-rc.d -f debhome remove
unix.properties properties file set to use in prepare build in pom.xml
we will add those files in src/main folder as following
- src/main/packaging/conf/application.conf
- src/main/packaging/filter/unix.properties
- src/main/packaging/script/control/deb/preinst
- src/main/packaging/script/control/deb/postinst
- src/main/packaging/script/control/deb/prerm
- src/main/packaging/script/control/deb/postrm
6- add configuration plugin in pom.xml to copy this scripts and configuration files from resource and packaging folder in src to target
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-resources-plugin</artifactId>
<executions>
<execution>
<id>copy-service-conf</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/conf</outputDirectory>
<resources>
<resource>
<directory>src/main/resources</directory>
<filtering>false</filtering>
</resource>
<resource>
<directory>src/main/packaging/conf</directory>
<filtering>true</filtering>
</resource>
</resources>
<filters>
<filter>src/main/packaging/filters/unix.properties</filter>
</filters>
</configuration>
</execution>
<execution>
<id>copy-control</id>
<phase>process-resources</phase>
<goals>
<goal>copy-resources</goal>
</goals>
<configuration>
<outputDirectory>${project.build.directory}/control</outputDirectory>
<resources>
<resource>
<directory>src/main/packaging/scripts/control</directory>
<filtering>true</filtering>
</resource>
</resources>
<filters>
<filter>src/main/packaging/filters/unix.properties</filter>
</filters>
</configuration>
</execution>
</executions>
</plugin>
7- now run mvn clean install -DskipTests and we get output deb in the target. go to target folder and copy ${app-name}.deb file and now can do sudo dpkg -i ${app-name}.deb
you can find a project on GitHub