Scaling your microservices: How to externalize the configuration for flexibility and easier deployment
As explained in IBM Cloud Method’s microservices architecture, the notable benefits of this approach include simplified deployment and more efficient development teams, thanks to the separation of a traditional “monolith” application into discrete, network-connected services that can be updated independently. This independence also simplifies application scalability because resources like CPU and memory can be allocated to individual services independently, consistent with their criticality to the overall app and anticipated throughput demands.
In the next three entries of this blog series, we’ll cover how to handle the factors below when handling scalability for Liberty’s MicroProfile-based microservices:
Thankfully, these considerations are part of the base MicroProfile, so the developer burden is minimal.
NB: For those who may have joined late, this blog series is based on my team’s experience migrating our simple storefront application from a Spring Boot-based microservices to MicroProfile, an optimized microservices programming model for enterprise Java. It was originally coded using Spring Boot (source code) and migrated to MicroProfile (source code). Both the projects are hosted on GitHub with source code and full documentation.
Why externalization of your microservices app’s configuration is important
Cloud-native designs often depend on several microservices apps to deliver their results. These microservices apps may run on multiple environments. Of course, when they run on different environments, they need different configurations. For example, they may need deployment-specific external URLs or credentials that change regularly. If the developer hardcodes these configuration values within the service, it would have to be redeployed for every configuration change.
To avoid the hassle of redeploying microservices app code for different environments, the solution is clear—externalize the configurations! This is cited in the twelve-factor app methodology. The good news is that the MicroProfile Config Feature defines an API for Java Enterprise, including IBM WebSphere Liberty (see IBM Doubles Down on Enterprise Java with WebSphere Liberty on ADTmag.com for more details).
In our last blog post, we showed you how MicroProfile Rest Client and JSON-B makes our work easier while building microservices using REST. In today’s blog post, I’ll explain how to externalize the configurations in order to run them on different execution environments without any source code changes.
Externalized configuration for Spring Boot apps
Spring Boot Config allows the externalization of the configurations in various environments without changing any application code. To enable this, properties can be defined as environment variables, command line arguments, properties files, and YAML files. Configurations in our reference application are defined using YAML files and the properties are bound using the
@ConfigurationProperties annotation. The properties can also be configured using the
Externalized configuration for MicroProfile apps
MicroProfile Config allows one to externalize configuration properties and retrieve their values from the target environment without changing any application code. You can easily obtain configuration from different sources like system properties, system environment variables, and properties files. These configuration values can be overridden in properties files and overridden programmatically at runtime. Using this feature enables the application to pick up configured values immediately after they are updated.
The config values are sorted according to their ordinal value. We can override the lower importance values by passing them externally during application installation, assembly, or at runtime. Below is the order of importance for the config sources:
META-INF/microprofile-config.propertiesfiles on the classpath.
Contrasting MicroProfile and Spring Boot support of externalized configuration
Externalizing the configuration from the code is important. Without this separation, you would need to recompile the application whenever the configuration values change. If you have many instances of the same service running, updating the configurations for all of them will be difficult and time-consuming.
In both the MicroProfile and Spring Boot implementations, we externalized the properties to a config file. In the Spring Boot implementation of our sample application, we used
application.yml as our config file and those were retrieved using the
@ConfigurationProperties annotation. Whereas in MicroProfile implementation, we obtained the configuration programatically. This can be done by obtaining the
config object. The
config object contains all the required properties and each property can be obtained via the
getValue() method. Below are sample snippets of each approach from our sample application:
The above are examples for one approach—you can do it in multiple ways. For more, check out BlueCompute – MicroProfile implementation on GitHub.
Hurray! That’s it, and all the configuration values for our sample application are externalized. Personally, I felt like the MicroProfile Config approach is easy to use and more straightforward than the Spring Boot Config. To run the whole application together, see the project README.
Modern development shops run their microservices apps in different environments, like dev, test, and production. Each requires specific values that must be changed based on the deployment environment. Updating them individually would be a pain! Externalizing the configuration values as described earlier supports a reliable, predictable DevOps-driven process. The MicroProfile Config Feature allows you to conveniently change these values without modifying your application code. It is as simple as defining a properties file and choosing the underlying methods (annotations, programmatically, or a combination of both) to use the configurations in your application.
When I worked on externalizing the configurations for our simple storefront application, the Open Liberty guides are extremely helpful and made my work easier. I used Configuring microservices as my reference.
MicroProfile Config is just one among the several awesome specifications that come with Eclipse MicroProfile. The next blog post will cover Security and MicroProfile JWT Propagation. In the meantime, take a look at our microservices reference implementation available on GitHub. Each microservice in our simple storefront application can be run individually using Maven as well, so you can import them and run as-is locally, or can run them on IBM Cloud and IBM Cloud Private.