1. Introduction
Spring Cloud Config is a library that makes it easy to externalize configuration for Spring applications. It allows us to expose configuration data as a service, making it easy to ingest from any other application that has an HTTP client.
In this tutorial, we will look at how to use Spring Cloud Config without git.
2. Spring Cloud Config Overview
The Spring Cloud Config library is a typical client-server model. A centralized server (or servers) reads in configuration data from some external data source. These servers expose various HTTP endpoints that allow any other application to query for configuration data.
Spring Cloud Config also makes it very easy to connect from a Spring Boot application to a config server automatically. The configuration data that is provided by the server can then be used just like any other properties source inside the client application.
3. Git Providers
The most common use case for Spring Cloud Config is to store configuration data inside a git repository. This type of setup has several advantages:
- Flexibility: A git repository can hold various file types, including binary.
- Security: Easy to control both read and write access at a granular level.
- Auditing: Robust history tracking allows easy auditing of configuration changes.
- Standardized: Git operations are standard regardless of provider, meaning we can self-host or use any number of 3rd party providers.
- Distributed: Git is designed from the ground up to be distributed, so it’s a great fit for cloud-native and microservice architectures.
Despite all the benefits listed above, however, git may not always be the best choice for storing configuration data. For example, our organization may already put configuration data in another data store like a relational database. In this case, it may not be worth the effort to migrate it to git.
In the next section, we’ll take a closer look at using Spring Cloud Config without git.
4. Using Spring Cloud Config Without Git
When we talk about using something other than git with Spring Cloud Config, we are really referring to the server component. Our choice of data store does not impact the client component. Only the server is impacted.
Inside the Spring Cloud Config Server library, there’s a single interface named EnvironmentRepository that defines a configuration source. All configuration sources, both git and otherwise, must implement this interface.
Let’s look at some of the provided implementations.
3.1. File System
Spring Cloud Config provides support for using a file system as a configuration source. To enable this feature, we have to specify the following value in the config server’s application.properties file:
spring.cloud.config.server.native.search-locations=resources/other.properties
By default, the search location assumes a classpath resource. If we want to use any arbitrary file, we simply include a file resource prefix:
spring.cloud.config.server.native.search-locations=file:///external/path/other.properties
In addition to this property, the config server needs to run with the native profile enabled:
-Dspring.profiles.active=native
It’s important to remember that when using a file system configuration source, we need to ensure the file system is available everywhere the config server will run. This likely means using a distributed file system such as NFS.
3.2. JDBC
Spring Cloud Config can also use a relational database to load configuration data using JDBC. This is accomplished via the JdbcEnvironmentRepository class. To enable this class, we have to follow a few steps.
First, the spring-jdbc library must be present on the classpath. If we’re already using Spring Data JDBC or another dependent library, it will already be present. Otherwise, we can always specify it manually:
<dependency>
<groupId>org.springframework</groupId>
<artifactId>spring-jdbc</artifactId>
</dependency>
Second, we need to specify how to connect to the database:
spring.datasource.url=jdbc:mysql://dbhost:3306/springconfig
spring.datasource.username=dbuser
spring.datasource.password=dbpassword
spring.datasource.driver-class-name=com.mysql.jdbc.Driver
In this case, we’re using MySQL, but any JDBC-compliant driver will work.
Next, the database must include a table named PROPERTIES that has the following columns:
- APPLICATION
- PROFILE
- LABEL
- KEY
- VALUE
And finally, we need to specify the JDBC profile for the config server:
-Dspring.profiles.active=jdbc
3.3. Redis
Spring Cloud Config also supports Redis as a configuration source. This is accomplished using the RedisEnvironmentRepository class. Similar to the JDBC source, we need to follow a few steps to enable it.
First, we need to add a dependency to Spring Data Redis:
<dependency>
<groupId>org.springframework.data</groupId>
<artifactId>spring-data-redis</artifactId>
</dependency>
Second, we need to set some properties for how to connect to Redis:
spring.redis.host=localhost
spring.redis.port=6379
Next, we have to ensure our properties are stored properly in Redis. We can use the HMSET command to store some sample properties:
HMSET application sample.property.name1 "somevalue" sample.property.name2 "anothervalue"
If we were to echo back these properties, we should see the following data:
HGETALL application
{
"sample.property.name1": "somevalue",
"sample.property.name2": "anothervalue"
}
Finally, we must enable the Redis profile for our Spring Cloud Config server:
-Dspring.profiles.active=redis
Using Redis as a configuration source also supports different profiles. To do this, we simply add the profile name to the end of the application:
HMSET application-dev sample.property.name1 "somevalue" sample.property.name2 "anothervalue"
In this example, we’re creating a new set of properties under a profile named dev.
3.4. Secrets
A popular feature of many cloud providers is secrets. Secrets allow us to securely store sensitive data as part of our cloud infrastructure. These are perfect for things like usernames, hostnames, and passwords, which we would want to include as part of our application configuration.
Spring Cloud Config provides support for many different cloud secret providers. Below, we’ll look at AWS, which uses the AwsSecretsManagerEnvironmentRepository class to load AWS secrets into a property source.
This class relies on the AWSSecretsManager class to do the heavy lifting of communicating with AWS. While we could manually create it ourselves, the more straightforward solution is to use a Spring starter:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-aws-secrets-manager-config</artifactId>
<version>2.2.6.RELEASE</version>
</dependency>
This module includes an auto-configuration that will create an instance of AWSSecretsManager for us. All we have to do is specify a set of properties in our bootstrap.yml file:
aws:
secretsmanager:
default-context: application
prefix: /config
profile-separator: _
fail-fast: true
name: ConfigServerApplication
enabled: true
Now, let’s suppose we want to store our database credentials in a secret and make them available to the config server. We would simply create a new secret at the path /config/application/database_credentials. Inside, we would store the necessary key/value pairs required to connect to the database.
This construct also supports different profiles. For example, if we have a development database server, we could also create a separate secret for it. We would name it /config/application/database_credentials_dev.
3.5. S3
Another convenient way to store configuration is with cloud file services. Let’s take a look at how we can use AWS S3 as a configuration source.
First, we need to add the AWS SDK to our project:
<dependency>
<groupId>com.amazonaws</groupId>
<artifactId>aws-java-sdk-s3outposts</artifactId>
<version>1.12.150</version>
</dependency>
Then, we need to provide some values to configure a connection to the S3 bucket that contains our property files:
amazon.s3.access-key=key
amazon.s3.secret-key=secret
And, we’ll need to supply specific properties for the AWS S3 configuration provider:
spring:
cloud:
config:
server:
awss3:
region: us-east-1
bucket: config-bucket
We also need to set a profile to ensure the AWS S3 configuration source is loaded:
-Dspring.profiles.active=awss3
All that’s left is to create our desired property files, including any profile-specific files, inside the bucket. Note that when an application doesn’t have a profile, the config server assumes default. Therefore, we should include a file with this suffix along with any other files that contain specific profile names.
3.6. Custom Configuration Source
If any of the provided configuration sources don’t meet our needs, we always have the option of implementing our own. In general, this involves creating a new class that implements both EnvironmentRepository and Ordered:
public class CustomConfigurationRepository implements EnvironmentRepository, Ordered {
@Override
public Environment findOne(String application, String profile, String label) {
// Return a new Environment that is populated from
// our desired source (DB, NoSQL store, etc)
}
@Override
public int getOrder() {
// Define our order relative to other configuration repositories
return 0;
}
}
Then, we simply instantiate this class as a new Spring bean:
@Bean
public CustomConfigurationRepository customConfigurationRepository() {
return new CustomConfigurationRepository();
}
4. Multiple Configuration Sources
In some cases, it may be necessary to run Spring Cloud Config with multiple configuration sources. In this case, we have to specify a couple of pieces of data.
Let’s say we want to run with both JDBC and Redis as configuration sources. The first thing we need to do is define the order of each source in our bootstrap.yml file:
spring:
cloud:
config:
server:
redis:
order: 2
jdbc:
order: 1
This allows us to specify the precedence for which configuration sources should be used before others. Because the ordering follows the normal Spring Ordered annotation processing, lower number sources will be checked first.
Additionally, we need to define both profiles for the server:
-Dspring.profiles.active=jdbc,redis
Note that we could specify the active profiles in the YAML as well. And, this same pattern could be used to define any number of configuration sources.
5. Conclusion
In this article, we’ve covered various configuration sources that can be used with Spring Cloud Config. While git is a great default source for many projects, it may not always be the best choice. We have seen that Spring Cloud Config provides multiple alternatives, as well as the ability to create custom providers.