Micronaut External Config
In one of the previous posts, I described how to have configurations per environment and why it a bad idea to build your jar for every environment. Also we saw how to read configuration values from property sources.
Many times you might not be in a position to enumerate your environments. For example, in one of the products I had developed, we were using the same war file across all our customers. If we had to include the configuration inside the war file, it demands to build our war file, and this approach is not flexible as that would make configuration changes costly and slow. So we took the approach of keeping the configuration file outside the war file.
Following are the controller and property source files to start with.
HelloController.java
package com.nareshak;
import io.micronaut.context.annotation.Value;
import io.micronaut.http.MediaType;
import io.micronaut.http.annotation.Controller;
import io.micronaut.http.annotation.Get;
import io.micronaut.http.annotation.Produces;
@Controller("/hello")
public class HelloController {
@Value("${greeting.message}")
private String message;
@Get("/")
@Produces(MediaType.TEXT_PLAIN)
public String index() {
return message;
}
}
appliction.yml
micronaut:
application:
name: hello-service
greeting:
message: Hello from Micronaut
Let' create a fat jar file of my project using ./gradlew build
. Once you start your service and invoke the endpoint 'http://localhost:8080/hello', you get a plain text output of "Hello from Micronaut". However, I can override this by supplying a value at runtime as follows.
➜ libs java -Dgreeting.message="Hello from External Config" -jar hello-service-0.1.jar
10:42:56.164 [main] INFO io.micronaut.runtime.Micronaut - Startup completed in 986ms. Server Running: http://localhost:8080
Let's invoke the endpoint.
➜ ~ curl -i http://localhost:8080/hello
HTTP/1.1 200 OK
Date: Thu, 25 Apr 2019 05:13:04 GMT
content-type: text/plain
content-length: 14
connection: keep-alive
Hello from External Config
We have managed to change the configuration values without rebuilding the jar. However, this approach is right only if you have to change a few items. This approach doesn't scale when there are many configuration items to be supplied. Let's take a step ahead to arrive at a better solution.
Let's modify the code to involve multiple values from the property source.
@Value("${greeting.message} ${greeting.to}")
private String message;
application.yml
micronaut:
application:
name: hello-service
greeting:
message: Hello from Micronaut
to: Dear!
Let's create a yml file and specify the configuration we would like to use.
➜ /tmp cat external-config.yml
greeting:
message: Hello
to: Friend
All we have to do is to specify this configuration file during the application launch.
➜ libs java -Dmicronaut.config.files="/tmp/external-config.yml" -jar hello-service-0.1.jar
11:29:16.089 [main] INFO io.micronaut.runtime.Micronaut - Startup completed in 1128ms. Server Running: http://localhost:8080
Let's invoke the endpoint to verify that everything is working as expected.
➜ ~ curl -i http://localhost:8080/hello
HTTP/1.1 200 OK
Date: Thu, 25 Apr 2019 05:59:24 GMT
content-type: text/plain
content-length: 12
connection: keep-alive
Hello Friend
Now that we have a working solution let us pause for a while and think if the solution can be improved. To start with, let's ask a question to ourselves - "Are there any potential pain points with the solution?". If your launch command varies across environments, there is a potential surprise waiting for you since the same command did not get executed in the lower environments. Hence let's strive to keep the command same across environments. We can achieve this by storing the config values in OS environment variables and referring to them in the launch command.
Fortunately, Micronaut supports this out of the box. Let's see it in action.
➜ libs export MICRONAUT_CONFIG_FILES="/tmp/external-config.yml"
➜ libs java -jar hello-service-0.1.jar
11:45:26.796 [main] INFO io.micronaut.runtime.Micronaut - Startup completed in 971ms. Server Running: http://localhost:8080
Note how Micronaut read from the OS environment variables without mentioning them explicitly in the launch command.