After playing around with Azure App Configuration Service and how to read a configuration entry with REST, and then using feature flags in a Spring Boot application, I got hooked I must admit. I wanted to know if it’s possible to replace the Spring Cloud Config Server with Azure App Configuration without changing the client services. This post will explain every step I took to build a first version of an Azure Spring Boot Config Server.
Starting point of this project was my previous post where I created a basic Spring Boot web application with feature flags. The pom.xml
stayed pretty much the same. What’s different is everything else. Here’s an illustration about what I wanted to achieve. Instead of configuring a client service with -Dspring.cloud.config.uri=<old_SPRING_CLOUD_CONFIG_SERVER>
, I wanted to replace just the address: -Dspring.cloud.config.uri=<new_AZURE_CONFIG_SERVER>
.
Motivation
The challenge with Spring Cloud Config Server is its dependency to a Git repository which tend to have either no SLA, or an SLA of three nines which would allow for 8h 45m 56s downtime in a year. We experienced lots of problems related to the Java Config Repo which prevented our Spring Cloud Config Server to start which further prevented our services to start. In case of an incident a pretty awful situation.
Replacing Spring Cloud Config Server with Azure App Configuration
Spring Cloud Config Server - Simplified
The interesting part is how Spring Cloud Config Server serves configurations, and what endpoints it has. To find out, I took a look at what requests the clients send to the config server: http://<old_SPRING_CLOUD_CONFIG_SERVER>/<CONTEXT_PATH>/<APPLICATION>/<PROFILE>/<LABEL>/FILE
.
Application
represents the folder within the Java Configuration Repo.Profile
is the the profile the service - Config Server or Client Service - was started with.Label
is a Git-Hash, tag or branch.File
is the filename with the extension that you’d like to retrieve.
All these information must somehow be captured in an Azure App Configuration instance, normally. In my case, the profile is the same as the label, so I ignored this information for now.
Configuration
The new Azure Config Server can connect to one or many Azure App Configuration instances. Each team or application can have its own instance, cross service configurations could be in a dedicated Azure App Configuration instance. I will configure just one instance as I want to import all configurations of all of our Java Spring Services and all cross service configurations at once. his project is a proof of concept after all.
spring.cloud.azure.appconfiguration.stores[0].connection-string= ${APP_CONFIGURATION_CONNECTION_STRING}
spring.cloud.azure.appconfiguration.stores[0].label=test
spring.cloud.azure.appconfiguration.cache-expiration=1s
Configurations in Azure App Configuration can be labeled with i.e. the name of the environment dev
, test
or production
, or anything else. The new Azure Config Server will first run in the test
environment. I set cache-expiration
to one second to see changes faster, default is 30 seconds. I really don’t want to wait so long while testing and playing around.
Model
The name of the one and only model is ConfigApiProperties
. It has two members:
// Configurations from Azure App Configuration
private Map<String, String> config;
// The filename that was requested
private String file;
I ignored profile
and label
for now as I would start a new instance of the new Azure Config Server for every environment anyway. This makes sense where you have dedicated clusters for each and every environment.
Controller
The controller defines the endpoint(s) the Azure Config Server needs to listen to. As I said previously, this is a first version, a proof of concept if you will. It accepts all profiles at the moment. All configurations will be labeled with test
but should ideally be set automatically from the bootstrap configuration spring.cloud.azure.appconfiguration.stores[0].label
, something for later to implement - focusing on the core first.
@GetMapping(value = { "/{application}/*/test/{file}" }, produces = MediaType.TEXT_PLAIN_VALUE)
public String getMessage(@PathVariable String application, @PathVariable String file) {
// The core of the code you would put here will
// convert the HashMap ConfigApiProperties.config
// into one String with new lines so that the
// returning String looks like a real properties file.
}
Configuration Prefix in Azure App Configuration
Azure App Configuration let us define entries with different prefixes and labels. As I will import all configurations of all applications that have each many files defined. It probably is bad practice to even consider putting it all into one instance. I do it anyway. I will use the prefix to distinguish applications and files: /application/config.<APPLICATION>.<FILE>.
. The default deliminator is a dot .
.
/application/
is the prefix thatspring-cloud-azure-appconfiguration-config-web
will prefix by default. This can’t be changed unless you patch the class.config
is the member of theConfigApiProperties
-model.<APPLICATION>
is the foldername of the requesting service within the Java Configuration Repo.<FILE>
is the filename being requested.
Next Steps
The complete code - that I can’t share for now - has some flaws and performance issues if I can say that. I mean the Spring Cloud Config Server checks out an entire repository which can take minutes. The new Azure Config Service will read all configurations and filter then what’s get returned to the requesting service. Also is profile information missing at the moment. If you would like to get some more details about the code, please drop me a message.