Environment variable based runtime configuration with sbt native packager

2.6k views Asked by At

I'm using the sbt native packager plugin to create a zip file of my application for deployment to elastic beanstalk. I would like to set environment variables in my beanstalk environment and have those be used to configure my application at runtime. I've attempted to reference the env variables in my Procfile like so:

web: ./bin/bridgeservice -Dhttp.port=$PORT

This does not work as $PORT is not interpolated by the start script generated by the packager.

I've also attempted to define the variables in my build.sbt like so:

import scala.util.Properties

javaOptions in Universal ++= Seq(
  "-Dhttp.port=" + Properties.envOrElse("PORT", "9004"),
)

This also does not work as the packager expects the PORT env variable at the time of building the distributable zip and hardcodes the default value of 9004 in an application.ini file.

Is it possible to dynamically pass java options based on environment variables at application startup?

2

There are 2 answers

0
Sergiy Sokolenko On

The settings in javaOptions in Universal are compiled into conf/application.ini file, but accordingly to sbt-native-packager docs application.ini currently does not support variable substitution:

The file will be installed to ${app_home}/conf/application.ini and read from there by the startscript. You can use # for comments and new lines as you like. This file currently doesn’t has any variable substitution. We recommend using the build.sbt if you need any information from your build.

So,the env var based runtime settings can be achieved in several ways:

Solution #1. Add extra definitions to generated start script

In build.sbt:

bashScriptExtraDefines += """addJava "-Dhttp.port=${PORT:-9004}""""

Check out Application and runtime configuration documentation for more info.

Solution #2: Set JAVA_OPTS env var in the target server

Just set JAVA_OPTS environment variable on the target server and make it available for the start script. This can be the easiest solution for environments like AWS ElasticBeanstalk where env vars can be set on the app's environment configuration page.

1
NejcT On

Not sure if this will help, but I had similar issue when building docker images of my multi module project.

I ended with this:

def sysPropOrDefault(propName: String, default: String): String = Option(System.getProperty(propName)).getOrElse(default)
val somePort = sysPropOrDefault("port", "9004")

and in the project definition:

lazy val someProject = project("some-project")
  .enablePlugins(JavaServerAppPackaging)
  .settings(
    javaOptions in Universal ++= Seq(
      s"-Dhttp.port=$somePort"
    )
  )

Adding javaOptions to project settings level was crucial in my case. And s before option is not a typo.

When running command from terminal I called:

sbt clean update -Dport=9005 docker:publishLocal