概述
- Config Server
- 使用共享配置属性
- 使用应用与特定应用程序的配置属性
- 保证配置属性安全
- 动态更新配置属性
Config Server
1. 认识
1.1 引入bootstrap.yml
bootstrap.yml(bootstrap.properties)
(和application.yml
同目录下)用来在程序引导时执行,应用于更加早期配置信息读取,如可以使用来配置application.yml中使用到参数等bootstrap.yml
配置有更高优先级,默认情况下属性不会被本地配置覆盖,优先于application.yml
加载当使用
Spring Cloud Config Server
的时候,应该在bootstrap.yml
里面指定spring.application.name
和spring.cloud.config.server.git.uri
和一些加密/解密的信息
1.2 概述
Spring Cloud Config Server作为一个配置属性的集中数据源,也是一个微服务,可以为同一应用程序中的其他服务提供配置数据
通过Config Server集中管理配置数据,其他服务将不需要单独配置
配置数据存储在外部(如GitHub丶GitLab丶Microsoft’s Team Foundation Server 丶Gogs等),通过Git方式从外部加载到Config Server进行分配
如果有安全性需求,保存在外部的配置数据的value可以进行加密后存储到Git仓库或者使用
HashiCorp Vault
替代Git仓库存储配置数据
2.使用Config Server
2.1 引入
方式一: 新建project时直接通过
spring Initializr
引入(推荐)方式二: 在pom.xml中引入
<properties> <java.version>11</java.version> <spring-cloud.version>Hoxton.SR7</spring-cloud.version> </properties> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency> </dependencies> <dependencyManagement> <dependencies> <dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-dependencies</artifactId> <version>${spring-cloud.version}</version> <type>pom</type> <scope>import</scope> </dependency> </dependencies> </dependencyManagement>
2.2 启用
在启动类上添加注解
@EnableConfigServer
应用启动时才会运行Config Server
@EnableConfigServer @SpringBootApplication public class ConfigApplication { public static void main(String[] args) { SpringApplication.run(ConfigApplication.class, args); } }
2.3 配置远程仓库地址(从中获取配置数据)
在
Config Server
的resources
目录下创建bootstrap.yml
文件并配置spring: cloud: config: server: git: uri: https://github.com/BrysonBS/learning #远程仓库地址(即打开仓库后地址栏地址) search-paths: configuration #查询仓库内路径(文件夹),可以使用通配符如more* default-label: cloud # 仓库分支 username: xxx #用户名 password: xxx #密码 application: name: config-server #定义应用名称 server: port: 8888 #服务启动端口
2.4 启动Config Server进行测试
启动
Config Server
,然后通过浏览器地址栏输入http://localhost:8888/config-server/default/cloud
查看结果(默认会从该仓库相应目录中查找application.yml
或application.properties
文件){ "name": "config-server", "profiles": ["default"], "label": "cloud", "version": "399d4f1c1a80c50de32c23d60117b2f665e76fc1", "state": null, "propertySources": [{ "name": "https://github.com/BrysonBS/learning/configuration/application.yml", "source": { "spring.application.name": "eureka-registry", "server.port": 8761, "eureka.instance.hostname": "localhost", "eureka.client.service-url.defaultZone": "http://${eureka.instance.hostname}:${server.port}/eureka" } }] }
地址详解
http://localhost:8888/config-server/default/cloud http://localhost:8888 Config Server地址和端口号 config-server 应用名称(spring.application.name) default Active Spring profile(没有定义默认为default) cloud Git label/branch(可选,默认为master)
3. 使用共享配置属性
Config Server
已经通过Git方式获取到配置数据,但是其他服务启动时还没有从Config Server
中获取配置数据并应用,因此需要通过对其他服务配置,使其启动时从Config Server
获取配置属性并应用
3.1 引入spring-cloud-starter-config
Maven依赖
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-config</artifactId> </dependency>
引入此依赖之后该Spring boot应用作为配置服务器的客户端, 启动时会就会从
Config Server
获取配置属性默认情况下接收到的所有属性都会应用到应用环境中去,同时这些属性也会进行缓存,此后即使
Config Server
关闭了,配置属性仍然可用其他应用默认情况下从
http://localhost:8888
地址的配置服务器获取配置属性,可以通过配置更改Config Server
的地址#http://localhost:8888/application/default/cloud 请求地址 spring: cloud: config: uri: http://localhost:8888 #定义从那个配置服务器(Config Server)获取配置属性 # 默认值为http://localhost:8888 profile: default #默认值请求的profile name: application #默认值应用名称 #label: #git仓库branch名
3.2 Config Server
和 Service Registry
的顺序问题
模式一: 一般情况下,
Eureka Service Registry
启动时从Config Server
获取配置属性模式二: 也可以选择让
Config Server
作为微服务自己注册到Eureka Sercice Registry
中,然后其他微服务发现Config Server
,但是要通过配置设置Config Server
为Discovery client,默认注册名为configserver
spring.cloud.config.discovery.enabled = true
4. 使用应用与特定应用程序的配置属性
4.1 认识
默认情况下从远程git仓库中的
application.yml
或者application.properties
文件中获取的配置属性是应用共享的配置属性对于应用与特定应用的配置属性则根据
application name
或者profile
属性确定,重新查看2.4中测试地址http://localhost:8888/config-server/default/cloud
,其中config-server
为application name
,defalut
为激活的profile
,即测试时改变这些参数即可获取不同应用的配置属性,启动时也是根据此地址发送请求获取配置数据,可以通过spring.cloud.config.name
丶spring.cloud.config.profile
丶spring.cloud.config.label
设置路径上的应用名,profile,git仓库branch的值如果想通过
application name
获取,对于特定应用的配置属性,存储在git仓库时文件名要以application name
命名,如taco.yml
对于profile属性设置则和以前相同
对于和共享属性
application.yml
中有冲突的属性,会以特定配置属性值为准
4.2 通过application name属性使用特定配置属性
首先在需要从
Config Server
获取配置的应用中添加spring.cloud.config.name
或spring.application.name
配置属性,设置请求时的应用名称远程git仓库中存储的文件名要以
spring.application.name
的值命名作为Config Server客户端的应用(如
spring.cloud.config.name = taco
)启动时就会从Config Server获取共享配置属性(application.yml
)和对应应用名称的的配置属性(taco.yml
)对于有冲突的配置属性以特定配置(
taco.yml
)属性为准*实例: *
本地应用(需要从
Config Server
获取配置数据):bootstrap.yml
spring: cloud: config: uri: http://localhost:8888 #定义从那个配置服务器(Config Server)获取配置属性 # 默认值为http://localhost:8888 name: eureka-registry #应用名称对应远程仓库文件名
远程Git仓库下有一个
erueka-registry.yml
文件相对应
4.3 通过profile属性使用特定配置属性
首先在需要从
Config Server
获取配置的应用中添加spring.cloud.config.profile
配置属性指定要使用的profile,如果要根据应用名则需要额外配置spring.cloud.config.name
远程git仓库中存储的文件名要加上
-
加spring.cloud.config.profile
的值作为后缀,如属性为
spring.cloud.config.name = taco
和spring.cloud.config.profile = production
则对应的查找的远程git仓库文件名为taco-production.yml
*实例: *
本地应用(需要从
Config Server
获取配置数据):bootstrap.yml
spring: cloud: config: uri: http://localhost:8888 #定义从那个配置服务器(Config Server)获取配置属性 # 默认值为http://localhost:8888 profile: production name: taco
远程Git仓库下有一个
taco-production.yml
文件相对应
也可以在配置文件中使用
---
形式创建多个profiles,一下实例本地应用(需要从
Config Server
获取配置数据):bootstrap.yml
spring: cloud: config: uri: http://localhost:8888 #定义从那个配置服务器(Config Server)获取配置属性 # 默认值为http://localhost:8888 profile: registry name: profiles
远程Git仓库下有一个
profiles.yml
文件相对应,内容中需要定义profiles值spring: profiles: registry application: name: registry-profiles server: port: 8766 eureka: instance: hostname: localhost client: service-url: defaultZone: http://${eureka.instance.hostname}:${server.port}/eureka --- spring: profiles: consumer application: name: consumer server: port: 8763
5. 保证配置属性安全
5.1 概述
配置信息可能包含敏感信息,对于放入远程Git仓库需要安全保证,
Config Server
提供两种方式来保证其安全性
- 将配置属性的值加密后存入远程Git仓库
- 使用
HashiCorp's Vault
替代远程Git仓库存储配置数据
Config Server
提供了两个端点来加密或者解密数据/encrypt
与/decrypt
如
http://localhost:8888/encrypt
,可以直接使用命令使用
curl http://localhost:8888/encrypt -d 8765 #加密8765
curl http://localhost:8888/decrypt -d 0c4e97a951510731b47ab0bc81f62ceab517f28bec007e36c6a1654773c1d4a1 #解密
5.2 将配置属性的值加密后存入远程Git仓库
5.2.1 对称加密
在
resources
目录下创建bootstrap.yml
文件(与application.yml同级目录)encrypt: key: 123456 #对称加密密钥
远程Git仓库配置文件中采用加密数据,格式为
'{cipher}加密数据'
,标识为密文server: port: '{cipher}0c4e97a951510731b47ab0bc81f62ceab517f28bec007e36c6a1654773c1d4a1' #8765使用123456密钥加密后
5.2.2 非对称加密(如RSA)
生成密钥文件
tacokey.jks
: 此处密钥库口令tacokey
,密钥口令均为123456
PS C:\Users\NBL\Downloads> keytool -genkeypair -alias tacokey -keyalg RSA -keystore tacokey.jks 输入密钥库口令: 再次输入新口令: 您的名字与姓氏是什么? [Unknown]: cn 您的组织单位名称是什么? [Unknown]: cn 您的组织名称是什么? [Unknown]: cn 您所在的城市或区域名称是什么? [Unknown]: cn 您所在的省/市/自治区名称是什么? [Unknown]: cn 该单位的双字母国家/地区代码是什么? [Unknown]: cn CN=cn, OU=cn, O=cn, L=cn, ST=cn, C=cn是否正确? [否]: y 输入
的密钥口令 (如果和密钥库口令相同, 按回车): 密钥口令太短 - 至少必须为 6 个字符 输入 的密钥口令 (如果和密钥库口令相同, 按回车): 再次输入新口令: Warning: JKS 密钥库使用专用格式。建议使用 "keytool -importkeystore -srckeystore tacokey.jks -destkeystore tacokey.jks -deststoretype pkcs12" 迁移到行业标准格式 PKCS12。 将生成的密钥文件
tacokey.jks
放入Config Server
的resources
文件夹下并在bootstrap.yml
中进行配置encrypt: key-store: alias: tacokey location: classpath:/tacokey.jks password: tacokey #密钥库口令 secret: 123456 #密钥口令
远程Git仓库中使用加密后的值存储
profiles.yml
,格式为:'{chipher}加密数据'
spring: profiles: registry-RSA application: name: registry-profiles-RSA server: port: '{cipher}AQA2nYXUQe6c9TDSrAsJzFQKBEMykrp7w14KA5WZAKbFzaf+wHz3SKFwlyNHi2481bvscJ/ZOjR6IfWwOllDDeVf7WyzuvPEE+Mo4intWOqNkVXeGeB4qesgL+fJLO3VfU9mBV3pmn/yon0YfEd04NmjmgPUyFClxwIrCNeo/U41RvmPLXQ5mbZ8DYR2ao75zzlgOXCBgy0EYLBsqSb4M2/shcaCTe7rvvqq8sqEcefvQhBsgDrR3ujUyu4m+4LO1teFxZrsa0kTXrG2pl65FTN09EFtMOHJI0Ws3NN42l8Uv1Oa7r2OwqA0hOZKS6TJMObcFs8Rrpym9vuLuZpIab+kHbWrqcnsTQ2CRleu6OVMnUfXyhIbDAcEGMqaZ1wtrDs=' #8765使用RSA加密后
5.2.3 spring.cloud.config.server.encrypt.enabled
属性
在配置加密完成之后通过
http://localhost:8888/profiles/registry-RSA
可以看到其中包含以下内容,加密值会被Config Server
自动解密为8765
{ "name": "profiles", "profiles": ["registry-RSA"], "label": null, "version": "86714bd2bf15a2f64f276ce490e1a374c8a25d24", "state": null, "propertySources": [{ "name": "https://github.com/BrysonBS/learning/configuration/profiles.yml (document #1)", "source": { "spring.profiles": "registry-RSA", "spring.application.name": "registry-profiles-RSA", "eureka.instance.hostname": "localhost", "eureka.client.service-url.defaultZone": "http://${eureka.instance.hostname}:${server.port}/eureka", "server.port": "8765" ########被自动解密 } }] }
如果想要关闭
Config Server
解密的方式,而是获取加密内容,然后由客户机自己解密(即其他从Config Server
获取配置数据的的应用需要自己配置解密信息),则设置spring.cloud.config.server.encrypt.enabled = false
(默认为true,必须在bootstrap.yml
中配置),然后再通过http://localhost:8888/profiles/registry-RSA
查看{ "name": "profiles", "profiles": ["registry-RSA"], "label": null, "version": "86714bd2bf15a2f64f276ce490e1a374c8a25d24", "state": null, "propertySources": [{ "name": "https://github.com/BrysonBS/learning/configuration/profiles.yml (document #1)", "source": { "spring.profiles": "registry-RSA", "spring.application.name": "registry-profiles-RSA", "server.port": "{cipher}AQA2nYXUQe6c9TDSrAsJzFQKBEMykrp7w14KA5WZAKbFzaf+wHz3SKFwlyNHi2481bvscJ/ZOjR6IfWwOllDDeVf7WyzuvPEE+Mo4intWOqNkVXeGeB4qesgL+fJLO3VfU9mBV3pmn/yon0YfEd04NmjmgPUyFClxwIrCNeo/U41RvmPLXQ5mbZ8DYR2ao75zzlgOXCBgy0EYLBsqSb4M2/shcaCTe7rvvqq8sqEcefvQhBsgDrR3ujUyu4m+4LO1teFxZrsa0kTXrG2pl65FTN09EFtMOHJI0Ws3NN42l8Uv1Oa7r2OwqA0hOZKS6TJMObcFs8Rrpym9vuLuZpIab+kHbWrqcnsTQ2CRleu6OVMnUfXyhIbDAcEGMqaZ1wtrDs=", ######还是加密数据 "eureka.instance.hostname": "localhost", "eureka.client.service-url.defaultZone": "http://${eureka.instance.hostname}:${server.port}/eureka" } }] }
5.3 使用HashiCorp's Vault
替代Git仓库存储配置数据
Vault安装在本地,并且存储在Vault中
secret
中的配置属性k,v(v会加密),保证配置数据的安全性,通常Git
存储库和Vault
同时使用,敏感数据保存在Vault
中即可
5.3.1 安装Vault By HashiCorp(以windows为例)
- 下载并解压到指定目录如
D:/vault
仅一个文件vault.exe
- 配置
path
环境变量增加值为如D:/vault
,以便在任何路径使用shell
窗口都能不通过路径直接运行
5.3.2 启动Vault并添加配置数据
运行
power shell
启动并设置根令牌(root token
是一个管理令牌,可以创建其他令牌(权限不同))vault server -dev -dev-root-token-id=roottoken #根令牌为roottoken
可以通过浏览器
http://127.0.0.1:8200/
进入UI界面输入根令牌后进去管理界面在secret/
下添加文件
及配置
或者新打开一个
power shell
通过命令添加#准备 $env:VAULT_ADDR="http://127.0.0.1:8200" #查看vault状态 vault status #新版本的Vault需要以下设置之后才能添加数据(为了与Config Server 兼容重新创建secret后端) vault secrets disable secret vault secrets enable -path=secret kv #添加配置数据到secret(后端秘密存储库路径)中: 在profiles中添加server.port=8767,相当于profiles.yml中添加 vault write secret/application server.port=8767 #查看写入的k/v数据 vault read secret/application #注意: 每次添加会替换掉路径下的所有k/v的值,因此需要一起添加才行 vault write secret/application server.port=8767 k1=v1
对于
profile
形式的配置数据添加,profiles.yml
内部有profile: registry-Vault
#相当于profiles.yml里面有profile: registry-Vault vault write secret/profiles,registry-Vault server.port=8767
5.3.3 Config Server配置
application.yml
中配置启用Vault
作为存储库spring: profiles: active: #同时使用vault(仅存储敏感信息),git(存储其他信息)存储库 - vault - git #如果想仅使用vault,去掉此处即可
bootstrap.yml
中配置Vault
服务器信息spring: cloud: config: server: git: uri: https://github.com/BrysonBS/learning #远程仓库地址(即打开仓库后地址栏地址) search-paths: configuration #查询仓库内路径(文件夹) default-label: cloud # 仓库分支 username: XXX #用户名 password: XXX #密码 order: 2 #优先级 vault: #服务器地址:(默认)https://localhost:8200 host: localhost port: 8200 #scheme: https 启用https时(须配置ssl)使用 order: 1 #优先级: 先于git(值2)使用
5.3.4 其他应用配置(需要从Config Server获取配置数据的应用)
bootstrap.yml
中配置Vault
的令牌,令牌会在请求头header
中携带X-Config-Token:roottoken
spring: cloud: config: token: roottoken
配置请求
Config Server
地址bootstrap.yml
spring: cloud: config: uri: http://localhost:8888 #定义从那个配置服务器(Config Server)获取配置属性 # 默认值为http://localhost:8888 profile: registry-Vault name: profiles #请求: http://localhost:8888/profiles/registry-Vault #请求头中会携带令牌信息: X-Config-Token:roottoken
6. 动态更新配置属性
6.1 概述
Spring Cloud Config Server提供了两种方式可以实现在应用运行中动态更新配置
- Manual(手动): **
Config Server
客户端(需要从Config Server
获取配置属性的应用)有一个POST请求端点actuator/refresh
,该应用直接发送此请求即可获取最新的配置属性并实现动态更新,需要额外引入Spring boot Actuator**提供支持- *Automatic(自动): * 提交配置到
Git
仓库时触发,Config Server
会自动通知(通过Message
服务广播)所有使用此配置服务器的客户端(Config Server Client
),需要引入额外的Spring Cloud
项目Spring Cloud Bus for communicating
提供支持
6.2 手动更新配置
6.2.1 引入Spring Boot Actuator
Actuator
提供了运行时监察和运行时状态操作当一个应用设置从
Config Server
获取配置属性时,Spring会自动配置一个特殊的Actuator
端点,用于刷新配置属性,为了使用此端点,需要引入Actuator
依赖并配置引入
Actuator
Maven依赖<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
暴露
Actuator
的请求端点management: endpoints: web: exposure: include: refresh,health,info
6.2.2 更新配置
Config Server客户端
远程Git仓库配置数据profiles.yml
spring: profiles: taco application: name: taco datasource: platform: h2 url: jdbc:h2:mem:test;DB_CLOSE_ON_EXIT=FALSE schema: - classpath:data/schema.sql data: - classpath:data/data.sql initialization-mode: always jpa: show-sql: true hibernate: ddl-auto: update server: port: 8762 #需要额外添加的配置暴露Actuator端点 management: endpoints: web: exposure: include: refresh,health,info greeting: message: Hello World!
Config Server
客户端(需要从Config Server
获取配置属性的应用)引入Actuator
依赖之后,只需要发送POST请求actuator/refresh
即可动态更新配置改写
greeting.message
的值然后发送POST请求更新则应用就会动态更新此属性值,例如:http://localhost:8762/actuator/refresh
6.3 自动更新配置
6.3.1 概述
流程图如下
在
Git
仓库配置一个webhook
,作用是当使用git push
时触发执行Webhook
(即向Webhook
中配置的地址发送请求(Config Server
的/monitor
端点))当触发
Webhook
请求发送给Config Server
的/monitor
端点之后,由Config Server
对信息进行处理(默认情况下提供了几种对常见远程存储库(Git等)的处理实现)Config Server
使用/monitor
端点接收Webhook
的请求,若要开启此端点则需要添加monitor
依赖处理完成的信息通过
Message
广播给所有订阅的配置客户端(Config Server Client)动态更新客户端配置Config Server Client
需要添加与Message实现相对应的Spring Cloud Bus
依赖项来实现自动更新
6.3.2 实现步骤
Git仓库配置
Webhooker
- 进入Git仓库选择
Settings>Webhooks
PayLoad URL
为Config Server
地址+端口+/monitor
,如http://host.docker.internal:8888/monitor
Content Type
选择application/json
,因为Config Server
的端点/monitor
不支持application/x-www-formurlencoded
类型Secret
选项会在Webhooker
发生的请求头中添加标识X-Hub-Signature
(GitHub),Config Server
的/monitor
端点不支持,因此留空即可
- 进入Git仓库选择
Config Server配置
启用
/monitor
端点需要引入monitor
依赖<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-monitor</artifactId> </dependency>
使用
Spring Cloud Stream
: 可以在/monitor
端点实现将message发布到订阅的Config Server Client
若使用的是
RabbitMQ
则引入<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-stream-rabbit</artifactId> </dependency>
若使用的是
Kafka
则引入<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-stream-kafka</artifactId> </dependency>
同时要配置使用的
RabbitMQ
或者Kafka
#配置RabbitMQ spring: rabbitmq: host: rabbit.tacocloud.com port: 5672 username: tacocloud password: s3cr3t
#配置Kafka spring: kafka: bootstrap-servers: - kafka.tacocloud.com:9092 - kafka.tacocloud.com:9093 - kafka.tacocloud.com:9094
创建
NOTIFICATION EXTRACTOR
对于不同
Git
服务实现,Webhook
发送的POST请求有不同的格式,在/monitor
端点通过组件处理webhook
请求,可以根据不同请求格式尝试判断出请求来自那种Git
服务,并将数据解析后通过message
发布到订阅的Config Server Clients
,对于常见的Git
服务如GitHub
丶GitLab
丶Bitbucket
等可以实现自动识别和解析,无需增加其他操作对于不能识别的
Git
服务需要添加NOTIFICATION EXTRACTOR
来解析@Component @Order(Ordered.LOWEST_PRECEDENCE - 300) public class GogsPropertyPathNotificationExtractor implements PropertyPathNotificationExtractor { @Override public PropertyPathNotification extract(MultiValueMap<String, String> headers,Map<String, Object> request){ if ("push".equals(headers.getFirst("X-Gogs-Event"))) { if (request.get("commits") instanceof Collection) { Set<String> paths = new HashSet<>(); @SuppressWarnings("unchecked") Collection<Map<String, Object>> commits = (Collection<Map<String, Object>>) request.get("commits"); for (Map<String, Object> commit : commits) { addAllPaths(paths, commit, "added"); addAllPaths(paths, commit, "removed"); addAllPaths(paths, commit, "modified"); } if (!paths.isEmpty()) { return new PropertyPathNotification(paths.toArray(new String[0])); } } } return null; } private void addAllPaths(Set<String> paths,Map<String, Object> commit,String name) { @SuppressWarnings("unchecked") Collection<String> files = (Collection<String>) commit.get(name); if (files != null) { paths.addAll(files); } } }
Config Server Clients
配置引入对应的
Spring Cloud Bus
,订阅了Config Server
的客户端(Config Server Client
)接收到message
时即可以自动更新配置若使用AMQP: 如
RabbitMQ
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-amqp</artifactId> </dependency>
若使用
Kafka
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-starter-bus-kafka</artifactId> </dependency>