Distributed Config#
Configuration in a non-distributed to distributed explodes really rapidly, from a handlful of configuration files to many-many ones.
We can still live with configuration management tools like Puppet, Chef etc. But there are issues with typical configuration management:
Deployment oriented: Need to kick-off deployments even for small or temporary changes.
Push-based is usally not dynamic enough: Won’t work in cloud environment, as we need to keep track of all the newly spun up instances and push to those as well.
Pull-based adds latency with temporal polling: Usually works on polling mechanism, which adds time-interval latency.
Configuration Server can solve our problems!
Application Configuration Server#
Dedicated, dynamic and centralized key/value store (maybe distributed).
Authoritative source.
Auditing.
Versioning.
Cryptography support.
Options available for configuration management backend:
Spring Cloud Consul
Spring Cloud Zookeeper
Spring Cloud Config
Integration with Spring Applications#
Config Client:
Embedded in application
Spring
Environmentabstraction:
@Inject
Environment environment;
Config Server:
Standalone (can be embedded)
Spring
PropertySourceabstraction
classpath:file.properties
Spring Cloud Config: Config Server#
HTTP REST Access
Output formats
JSON (default)
Properties
YAML
Backend Stores
Git (default)
SVN
File system
Configuration scopes
Using Spring Cloud Config Server#
pom.xml
<dependencyManagement>
<dependencies>
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-dependencies</artifactId>
<version>Camden-SR2</version>
<type>pom</type>
<scope>import</scope>
</dependency>
</dependencies>
</dependencyManagement>
pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
application.properties
server.port=8888
spring.cloud.config.server.git.uri=<uri_to_git_repo>
OR application.yml
server:
port: 8888
spring:
cloud:
config:
server:
git:
uri: <uri_to_git_repo>
Application.java
@SpringBootApplication
@EnableConfigServer
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
TIP: Add Eureka client dependencies, service-url configuration and @EnableDiscoveryClient to make the config server discoverable.
Configuring backend store:
Create a folder to store configuration.
(optional) Add a
propertiesorymlfile with nameapplication.Add
propertiesorymlfile with name{application}-{profile}.git init.git addandgit commit.(optional) Setup remote git repository and
git push.
Additional Notes:
Git is the default mechanism/backend.
Global configs goes into
application.yml/application.propertiesand application specific config go into the named files as above.
NOTE: Don’t forget to secure your Config Server!
Easy to configure Spring Security.
REST Endpoint Parameters#
{application} - maps to
spring.application.nameon client.{profile} - maps to
spring.profiles.activeon client.{label} - server side feature to refer to set of config files by name.
GET /{application}/{profile}[/{label}]#
/myapp/dev/master/myapp/prod/v2/myapp/default
GET /{application}-{profile}.(yml | properties)#
/myapp-dev.yml/myapp-prod.properties/myapp-default.properties
GET /{label}/{application}-{profile}.{yml | properties}#
/master/myapp-dev.yml/v2/myapp-prod.properties/master/myapp-default.properties
Spring Cloud Config: Config Client#
Spring Config Client#
pom.xml
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-client</artifactId>
</dependency>
Config First#
Specify the location of the config server.
bootstrap.properties
spring.application.name=<your_application_name>
spring.cloud.config.discovery.enabled=true
OR bootstrap.yml
spring:
application:
name: <your_application_name>
cloud:
config:
discovery:
enabled: true
Discovery First#
Discover the location of the config server.
bootstrap.properties
spring.application.name=<your_application_name>
spring.cloud.config.uri=http://localhost:8888/
OR bootstrap.yml
spring:
application:
name: <your_application_name>
cloud:
config:
uri: http://localhost:8888/
NOTE: Don’t forget to add eureka client dependencies, service-url configuration and @EnableDiscoveryClient
Refreshing configuration properties#
#1: Configuration changes#
Edit and save configuration file(s).
Commit and/or push changes to a VCS.
#2: Notify Application(s) to refresh configuration#
/refreshwithspring-boot-actuator.Explicit refresh.
/bus/refreshwithspring-cloud-bus.Dynamic push refresh.
Automatic via Spring Cloud Bus broadcasting.
From RabbitMQ or Kafka?
VCS +
/monitorwithspring-cloud-config-monitorandspring-cloud-bus.Automatic and Smart refresh.
Via post commit hooks, Spring Cloud Config Monitor and Spring Cloud Config Bus broadcasting.
Refreshing Config: What’s covered and what’s not#
@ConfigurationPropertiesAll logging levels defined by
logging.level.*are updated.Any
@Beanor@Valuethat only gets its configuration upon initialization.
@RefreshScope#
To refresh a @Bean or a @Value that only gets its configuration upon initialization.
@Configuration
public class SomeConfiguration {
@Bean
@RefreshScope
public FooService fooService(FooProperties properties) {
return new FooService(properties.getConfigValue());
}
}
Additional Features Supported#
Encrypted configuration at rest and/or in-flight.
An
/encryptendpoint to encrypt configuration.A
/decryptendpoint to decrypt configuration.Encrypting and decrypting with symmetric or asymmetric keys.
What does encrypted configuration look like?#
application.properties
my.datasource.username=foobar
my.datasource.password={cypher}AASFDSFJSRFAFESECCSE
OR application.yml
my:
datasource:
usernmae: foobar
password: '{cipher}AASFDSFJSRFAFESECCSE'
At what point the configuration is decrypted?#
Upon request at the server (default).
Locally at the client on response.
Configure the Config Server with: spring.cloud.config.server.encrypt.enabled=false
TODO: encryption and decryption setup with examples.