Issue
We are running a Spring Boot Java application in Pivotal Cloud Foundry. We want to run multiple instances of the app (using scaling, etc), but we want them to have slightly different configurations. We do NOT want to have to run multiple apps if we can get away with it.
Is there some way of assigning a different configuration to each instance of an app? We need to have a separate MQTT topic for each instance. The ideal solution would be if each app could tell which instance number it was. "Hey, I'm instance #1, so I'll grab the first set in this list, etc".
So we're hoping to be able to tell either a) which instance we are, or b) somehow give a different configuration value to each instance of the app.
Solution
As far as Cloud Foundry is concerned, each instance of an application is the same as every other application instance. This is more concerned with the files that make up the app and the start command though, because when you stage your application with the Java buildpack, it produces a "droplet" which is effectively the full set of files required to run your app (JVM, app files, etc...) and the command to run your app. The exact same droplet and command are provided to every application instance, so from that perspective each app instance is the same.
That said, Spring Boot is incredibly flexible and what you're describing should work. You may fetch the application instance number (0-based index) from the CF_INSTANCE_INDEX
env variable or you can fetch the application guid from CF_INSTANCE_GUID
env variable. Either one will be unique per application instance, although if you need to pre-allocate any resources the instance index is predictable.
https://docs.cloudfoundry.org/devguide/deploy-apps/environment-variable.html#CF-INSTANCE-GUID
This means you could set up your application configuration like this:
example.mqtt.topic=foo/bar-${CF_INSTANCE_INDEX}
And you'd end up with topics like foo/bar-0
, foo/bar-1
, foo-bar-2
, etc...
If you need more control, you might try something with Spring Profiles. You can probably dynamically enable a specific profile for the app based on the app instance. You might also be able to use java-cfenv
and create a custom processor. That essentially just maps information from the environment to Spring Boot properties, so you could look up whatever you need, like CF_*
env variables, and use that to generate and set properties for your services.
Answered By - Daniel Mikusa
Answer Checked By - Dawn Plyler (JavaFixing Volunteer)