Spring Cloud - Config统一配置管理
1.为什么要统一管理微服务配置
对于Spring Boot应用,我们可以将配置内容写入application.yml
,设置多个profile,也可以用多个application-{profile}.properties
文件配置,并在启动时指定spring.profiles.active={profile}
来加载不同环境下的配置。
在Spring Cloud微服务架构中,这种方式未必适用,微服务架构对配置管理有着更高的要求,如:
- 集中管理:成百上千(可能没这么多)个微服务需要集中管理配置,否则维护困难、容易出错;
- 运行期动态调整:某些参数需要在应用运行时动态调整(如连接池大小、熔断阈值等),并且调整时不停止服务;
- 自动更新配置:微服务能够在配置发生变化是自动更新配置。
以上这些要求,传统方式是无法实现的,所以有必要借助一个通用的配置管理机制,通常使用配置服务器来管理配置。
2.Sping Cloud Config简介
Spring Cloud Config分为Config Server和Config Client两部分,为分布式系统外部化配置提供了支持。 Spring Cloud Config非常适合Spring应用程序,也能与其他编程语言编写的应用组合使用。
微服务在启动时,通过Config Client请求Config Server以获取配置内容,同时会缓存这些内容。
3.Config Server
Config Server是一个集中式、可扩展的配置服务器,它可以集中管理应用程序各个环境下的配置,默认使用Git存储配置内容。
3.1 创建Config Server
3.1.1 创建用于存放配置文件的git仓库,添加配置文件
service1.properties
profile=default-1.0
service1-dev.properties
profile=dev-1.0
service1-test.properties
profile=test-1.0
service1-pro.properties
profile=pro-1.0
3.1.2 创建一个Spring Boot应用config-server,添加spring-cloud-config-server
依赖
dependencies {
compile('org.springframework.cloud:spring-cloud-config-server:1.4.1.RELEASE')
}
3.1.3 在启动类添加@EnableConfigServer注解
@EnableConfigServer
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class,args);
}
}
3.1.4 在application.yml中配置Git仓库地址
server:
port: 8181
spring:
application:
name: config-server
cloud:
config:
server:
git:
uri: https://github.com/yuanzicheng/spring-cloud-config-repository
username:
password:
3.2 Config Server文件映射
3.2.1 配置文件映射关系
Config Server启动以后,我们可以通过它暴露的端点获取配置文件内容,http请求地址与配置文件映射关系如下:
# 映射{application}-{profile}.properties文件
/{application}/{profile}/[{label}]
/{label}/{application}-{profile}.properties
/{application}-{profile}.properties
/{label}/{application}-{profile}.yml
/{application}-{profile}.yml
{application}通常使用微服务名称,对应Git仓库中文件名的前缀;
{profile}对应{application}-
后面的dev、pro、test等;
{label}对应Git仓库的分支名,默认为master。
3.2.2 测试验证
访问http://localhost:8181/service1/default或http://localhost:8181/service1/default/master,结果如下
{
"name": "service1",
"profiles": ["default"],
"label": null,
"version": "3b6835a7b87aa1f7c6830456ce85605a071bbdce",
"state": null,
"propertySources": [{
"name": "https://github.com/yuanzicheng/spring-cloud-config-repository/service1.properties",
"source": {
"profile": "default-1.0"
}
}]
}
访问http://localhost:8181/service1/dev或http://localhost:8181/service1/dev/master,结果如下
{
"name": "service1",
"profiles": [
"dev"
],
"label": null,
"version": "3b6835a7b87aa1f7c6830456ce85605a071bbdce",
"state": null,
"propertySources": [
{
"name": "https://github.com/yuanzicheng/spring-cloud-config-repository/service1-dev.properties",
"source": {
"profile": "dev-1.0"
}
},
{
"name": "https://github.com/yuanzicheng/spring-cloud-config-repository/service1.properties",
"source": {
"profile": "default-1.0"
}
}
]
}
访问http://localhost:8181/service1-dev.properties或http://localhost:8181/service1-dev.yml,结果如下
profile: dev-1.0
4.Config Client
Config Client是Config Server的客户端,用于操作存储在Config Server中的配置内容。
4.1 创建Config Client
4.1.1 创建一个Spring Boot项目config-client,添加依赖
dependencies {
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter-actuator')
compile('org.springframework.cloud:spring-cloud-starter-config:1.4.1.RELEASE')
}
4.1.2 创建配置文件application.yml
通常情况下,Config Client作为微服务的一部分,微服务的spring.application.name
属性值决定了Git仓库中配置文件的的文件名前缀,需要为哪个微服务提供配置文件,配置文件的文件名就需要以spring.application.name
属性值作为前缀。
server:
port: 8282
spring:
application:
name: service1 # 对应config-server获取的配置文件的{application}
4.1.3 创建配置文件bootstrap.yml
Spring Boot应用程序启动时加载application.yml/application.properties。Spring Cloud中有“引导上下文”的概念,引导上下文加载bootstrap.yml/bootstrap.properties,而且具有更高的优先级,默认情况下bootstrap.yml/bootstrap.properties中的属性不能被覆盖。
spring:
application:
name: service1 # 对应config-server获取的配置文件的{application}
cloud:
config:
uri: http://localhost:8181 # 对应config-server地址,默认值http://localhost:8888
profile: pro # 对应config-server获取的配置文件的{profile}
label: master # 对应config-server获取的配置文件的{label},即Git仓库分支
4.1.4 编写测试用的Controller
@RestController
public class ConfigController {
@Value("${profile}")
private String profile;
@GetMapping("/profile")
public String profile(){
return this.profile;
}
}
4.2 测试验证
依次启动config-server:8181和config-client:8282,访问http://localhost:8282/profile,返回如下结果
pro-1.0
Config Client能够正常通过Config Server获取Git仓库中指定环境的配置内容。
5.Git仓库配置
Config Server的application.yml配置文件中,通过spring.cloud.config.server.git.uri
指定Git仓库地址,实际上该属性的配置方式非常灵活,支持多种方式。
5.1 占位符
{application}
、{profile}
、{label}
等占位符可以用于映射配置文件,还可以用于Config Server中配置Git仓库地址。
5.1.1 使用{application}指定Git仓库地址
Step 1:在Config Server中用{application}占位符的形式指定Git仓库地址
spring:
cloud:
config:
server:
git:
uri: https://github.com/yuanzicheng/{application}
Step 2:在Config Client中修改spring.application.name=spring-cloud-config-repository
,因为建了一个Git仓库,这里简单起见,就不再创建新的Git仓库了。
spring:
application:
name: spring-cloud-config-repository
Step 3:在Git仓库中创建一个application-dev.yml的文件
profile: application-test
特别注意:用占位符的形式定义Git仓库地址时,配置文件的文件名必须为application*.yml
或application*.properties
。
Step 4:依次启动Config Server和Config Client,访问http://localhost:8282/profile,结果如下
application-test
5.1.2 习惯用法{application}-xxx
假设创建了一个微服务service1,配置文件的Git仓库就可以指定为service1-xxx,
spring:
cloud:
config:
server:
git:
uri: https://github.com/yuanzicheng/{application}-xxx
这样Config Server就可以支持多个Config Clienet。
5.2 模式匹配
可以通过应用程序和配置文件名称的模式匹配来支持更复杂的需求,但通常情况下不建议使用这种方式。
特殊场景如有需要可用参考Pattern Matching and Multiple Repositories。
5.3 搜索目录
spring.cloud.config.server.git.search-paths
属性可以指定除了根目录,额外需要加载配置文件的子目录。
如:加载根目录、dir目录、dir开头的目录下的配置文件。
spring:
cloud:
config:
server:
git:
uri: https://github.com/yuanzicheng/spring-cloud-config-repository
search-paths: dir,dir*
5.4 clone-on-start
默认情况下,首次请求配置时,Config Server克隆Git仓库,也可以通过clone-on-start
设置Config Server启动时是否克隆git仓库。
全局配置:
spring:
application:
name: config-server
cloud:
config:
server:
git:
clone-on-start: true
指定仓库:
spring:
cloud:
config:
server:
git:
repos:
指定仓库:
clone-on-start: true
5.5 日志输出
如果需要输出Config Server请求Git仓库的细节,可以设置以下包的日志级别为debug,这样通过日志跟踪可以理解Config Server的Git仓库配置,也方便定位问题。
logging:
level:
org.springframework.boot: debug
org.springframework.cloud: debug
5.6 本地Git仓库
Config Server还支持从本地Git仓库读取配置,但建议仅在开发、测试环境下采用这种方式。
初始化本地Git仓库
$ cd ~ && mkdir local-repository
$ cd local-repository
$ git init .
$ echo "dev: local config" > service1.yml
$ git add .
$ git commit -m "first commit"
从本地文件系统的Git仓库读取配置文件(注意:windows环境下,使用file:///作为Git仓库路径前缀)
spring:
cloud:
config:
server:
git:
uri: file://${user.home}/local-repository
6.Config Server健康状况
Config Server自带了健康状况指示器,暴露的endpoint为/health,用于检查配置的仓库是否可用。
对于文中的Config Server,请求http://localhost:8181/health返回如下结果
{
"status": "UP"
}
7.配置加密
一些场景下,对于敏感信息(如:数据库账号、密码,某些服务分配的key等),需要加密处理。
Config Server支持配置内容的加密、解密,依赖于Java Cryptography Extension(JCE)。
8.刷新配置
Spring Clould Config支持不停止应用刷新配置。
8.1 手动刷新
修改Config Client项目来验证配置内容的手动刷新。
Step 1:添加依赖
其中spring-boot-starter-actuator依赖包含了/refresh端点,用于刷新配置
dependencies {
compile('org.springframework.boot:spring-boot-starter-web')
compile('org.springframework.boot:spring-boot-starter-actuator')
compile('org.springframework.cloud:spring-cloud-starter-config:1.4.1.RELEASE')
}
Step 2:在使用配置内容的类上添加注解
@RefreshScope
@RestController
public class ConfigController {
@Value("${profile}")
private String profile;
@GetMapping("/profile")
public String profile(){
return this.profile;
}
}
Step 3:禁用spring security
management:
security:
enabled: false
Step 4:修改application-dev.yml的内容为profile: application-dev
,post方式请求http://localhost:8282/refresh,返回如下结果,表示配置刷新成功。
[
"config.client.version",
"profile"
]
Step 5:再次请求http://localhost:8282/profile,返回内容已经变成了application-dev
。