Package and deploy Scala projects as Debs or RPMs

As I struggled quite a while to find a working solution, here’s how I used sbt-native-packager to deploy my Scala applications to Debian- or RPM-based linux distributions:

First, add the plugin to your /project/plugins.sbt:

addSbtPlugin("com.typesafe.sbt" % "sbt-native-packager" % "1.1.4")

Then ammend your build.stb file to include the plugin and configure it for systemd:

name := "your-project"
 
version := "1.0"
 
enablePlugins(JavaServerAppPackaging, RpmPlugin)
 
import com.typesafe.sbt.packager.archetypes.ServerLoader
 
serverLoading in Debian := ServerLoader.Systemd

Now edit you build.sbt file.
To successfully map configuration files on the target, add a mapping for all relevant files

version := "1.2.3"
name := "your-service"
packageSummary := "Project Title",
packageDescription := "Clever description",
maintainer := "Sebastian Georgi <sgeorgi@sgeorgi.de>",
 
serverLoading in Debian := ServerLoader.Systemd,
serverLoading in Rpm := ServerLoader.Systemd,
 
rpmVendor := "sgeorgi",
rpmLicense := Some("no"),
rpmGroup := Some("Software")
 
# Copies reference.conf to application.conf
mappings in Universal += {
  val conf = (resourceDirectory in Compile).value / "reference.conf"
  conf -> "conf/application.conf"
}
 
# ...
mappings in Universal += {
  val conf = (resourceDirectory in Compile).value / "application.ini"
  conf -> "conf/application.ini"
}
 
# ...
mappings in Universal += {
  val conf = (resourceDirectory in Compile).value / "logback.xml"
  conf -> "conf/logback.xml"
}

Those mapped files will be available in /usr/share/your-project/conf upon installing the .deb-file, which in fact in conventiently symlinked to /etc/your-project.

Add the application.ini in your resource directory (/src/main/resources) to instruct the compiled binary (which is a rather complicated bash script) where to find your configuration and what parameters to pass to the JVM:

# #################################
# ##### Default configuration #####
# #################################
 
# DEPRECATED, use -J-Xmx1024m instead
# -mem 1024
 
# Setting -X directly (-J is stripped)
# -J-X
# -J-Xmx1024
 
# Add additional jvm parameters
# -Dkey=val
 
# For play applications you may set
-Dpidfile.path=/var/run/kshards-core/core.pid
 
# Turn on JVM debugging, open at the given port
# -jvm-debug
 
# Don't run the java version check
# -no-version-check
 
-Dconfig.file=/usr/share/your-project/conf/application.conf
-Dlogback.configurationFile=/usr/share/your-project/conf/logback.xml

Locally, I can use versions of logback.xml (debug output) and application.conf (settings only applicable to localhost).

On the target I can maintain my own production configuration which is conveniently copied from reference.conf to application.conf. Lightbend’s Config always uses reference.conf so my local application.conf only has to include the neccessary changes (by overriding some configuration keys).

The Debian Package Installer even notifies me when a new version of the package includes a configuration that is different from the ammended version, like it does for example when you update your linux packages as well.

To build your .deb-package simply fire up a sbt session and type

debian:packageBin

To build a RPM (you’ll need to have the rpm-package installed on your local host):

rpm:packageBin

You can either inspect the packages’ content by having a look into your /target/your-project-1.2.3 directory or extract /target/your-project_1.2.3_all.deb

Transfer the .deb or .rpm-file to your target system, issue a sudo dpkg -i your-project_1.2.3_all.deb or sudo rpm -i your-project_1.2.3_all.deb and see your service being installed.

Configuration is in /etc/your-project

Log files are in /var/log/your-project

**Starting: sudo systemctl start your-project.service**

**Stopping: … stop …**
and so on.

You can set various things in the application.ini, for example some more JVM-options or other arguments using newly mapped files in buiĺd.sbt

Make sure to visit SbtNativePackager’s own extensive documentation!