Friday, March 05, 2021

Spring Cloud Config - Gotchas . . .

Spring Cloud Config takes externalization of application property-resources or configuration-files (name-value pair property files: *.properties, and YML files: *.yml) one step further away from the application into an external and central location like a git repo or a file-system.

It comes with a server-side application that accesses property resources from the central location and makes them available for client applications through HTTP resource-based API end-points. This Server application can easily be embeddable in a simple Spring Boot application. Once embedded in a Spring Boot application, this will be your Cloud config server application to be integrated with all client applications. Client applications integrate with the server by setting spring.cloud.config properties like uriuser, password etc.

Environment: Java 15, Spring Boot 2.3.8.RELEASE on macOS Catalina 10.15.7

Gotchas

  • Client applications are identified by Cloud config server by their application names (spring.application.name property value of the respective client application)
  • With git repository hosting property resource files (configuration files like *.properties or *.yml), if you use application.yml or application.properties names for configuration files, these files become common configuration to all client applications that depend on Cloud config server for externalized config files.
  • One config server can serve multiple clients' (multiple applications) externalized configurations. To best leverage this feature, organize externalized config files by the application's name. For instance if there are two Spring Boot client applications (named: my-app-1, and my-app-2) and both are configured to use one Spring Cloud config server for their externalized configurations hosted in a git repo, better to have two separate config files like my-app-1.yml and my-app-2.yml for the respective application configurations in the git repo. One yml file can have configurations for all environments like local, dev, int, cert, prod etc with each environment mapping to respective spring profile and each profile configuration separated by yml directive ---
  • The HTTP service of Cloud Config Server exposes end-points in different forms with client-application-name, client-application-profile, and label as part of the end-point forms. Label is nothing but the git branch and is optional with master as implicit value.
  • With git repository set as the host for clients' externalized configuration files, if any specific changes to those files are made and committed in a branch other than master, the cloud config server does not serve that branch unless it is explicitly asked for by specifying the optional label part in the end-point URL. This is the case even if that specific branch is currently checked out.
  • When label (branch name) is not specified, it always uses the implicit label and checks out master branch and responds with the configuration taken from property resources available in the master branch.
  • If explicitly asked for a different branch by  specifying the branch-name as the label in the end-point URL, it checks out that specific branch and servers property resources available in that branch for the given application and it's profile.

    Local Testing

  • For local testing, if your git repo (.git) for clients' external configuration files is in a directory under your home e.g. ~/dev/my-cloud-config, then set spring.cloud.config.server.git.uri to file://Users/<yourMacUserId>/dev/my-cloud-config in the cloud config server spring boot application bootstrap.yml/application.properties for the profile, let's say: int
  • Assuming your cloud config server is running locally on port:8888, the URLs: 1) http://localhost:8888/my-app-1/int 2) http://localhost:8888/my-app-1-int.yml 3) http://localhost:8888/my-app-1-int.properties to check my-app-1 application's int environment/profile configuration results in checking out master branch to serve my-app-1 application's configuration. If you are on a branch other than master, you will notice that you will be switched to master once you make a request to the above URLs to verify the configuration. This is due to the implicit master branch checkout that the cloud config server does under the hood.

  • In your local git repo where client applications' config files are hosted, if your are on a branch other than master and have local changes pending (not committed), the implicit master checkout fails resulting into an exception like:
    org.springframework.cloud.config.server.environment.NoSuchRepositoryException: Cannot clone or checkout repository: file:///Users/<myMacUserId>/dev/my-cloud-config
  • If your configuration files for client applications are on a specific git branch other than master, and if you want to test the cloud config server against that specific branch, then the endpoint /{application}/{profile}[/{label}] URL (e.g. http://localhost:8888/my-app-1/int/my-branch may work.

    Encrypted Content

  • If clients' configuration files have password property like spring.datasource.password and the values are plain text, then the response shows the property with the original value. If the password uses an encrypted value starting with {cipher} followed by encrypted password (e.g. `{cipher}my3ncryp!ed^assword`) then the response doesn't contain spring.datasource.password property or it's value. Instead, you will see a special property "invalid.spring.datasource.password" with a special value "<n/a>"   "invalid.spring.datasource.password": "<n/a>". That means you gotta use a special way to see those encrypted password properties. There is a separate section in the doc explaining this with two special end-points (/encrypt, /decrypt) provided.

TIP

  • In this case, your client application's property resource file changes are on a specific branch, you are unable to get that working, you will be better off changing the Cloud Server Spring Boot application's default implicit master branch to your specific branch by setting the property spring.cloud.config.server.git.default-label to your branch name. This works even if your branch name has / in it (e.g. feature/my-branch).

References