背景:
Spring Cloud Config用来为分布式系统中的基础设施和微服务应用提供集中化的外部配置支持,它分为服务端与客户端两个部分。
服务端:也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置仓库并为客户端提供获取配置信息、加密/解密信息等访问接口。
客户端:是微服务加厚中的各个微服务应用或基础设施,它们通过指定的配置中心来管理应用资源与业务相关的配置内容,并在启动环境的时候从配置中心获取和加载配置信息。
Spring Cloud Config实现的配置中心默认采用Git来存储配置信息,所以使用Spring Cloud Config构建的配置服务器,天然就支持对微服务应用配置信息的版本管理。
-------------------------------------------快速入门----------------------------------------------
一、构建基于Git存储的分布式配置中心
1、创建Spring Boot工程,命名为config-server,添加依赖。
<dependency> <groupId>org.springframework.cloud</groupId> <artifactId>spring-cloud-config-server</artifactId> </dependency>
2、创建应用主类,添加@EnableConfigServer注解,开启Spring Cloud Config的服务端功能。
@EnableConfigServer
@SpringBootApplication
public class ConfigServerApplication {
public static void main(String[] args) {
SpringApplication.run(ConfigServerApplication.class, args);
}
}
3、在application.properties中添加配置服务的基本信息以及Git仓库的相关信息:
spring.application.name=config-server
server.port=7001#Git仓库的位置
spring.cloud.config.server.git.uri=https://github.com/hedanning/SpringCloudConfigLearn
#仓库路径下的相对搜索位置
spring.cloud.config.server.git.search-paths=spring_cloud_in_action/config-repo
#访问Git仓库的用户名
spring.cloud.config.server.git.username=username
#访问Git仓库的密码
spring.cloud.config.server.git.password=passward
- spring.cloud.config.server.git.uri:配置Git仓库的位置
- spring.cloud.config.server.git.search-paths:配置仓库路径下的相对搜索位置
- spring.cloud.config.server.git.username:访问Git仓库的用户名
- spring.cloud.config.server.git.password:访问Git仓库的密码
具体请参考:Spring Cloud(十六)、通过Spring Cloud Config构建配置中心
二、配置规则详解
为了验证上面完成的分布式配置中心config-server,根据Git配置信息中指定的仓库位置,在https://github.com/hedanning/SpringCloudConfigLearn 下创建一个spring_cloud_in_action/config-repo目录作为配置仓库,并根据不同环境新建下面4个配置文件:
- hdnspace.properties
- hdnspace-dev.properties
- hdnspace-test.properties
- hdnspace-prod.properties
在这4个文件中均设置一个from属性,并为每个配置文件中分别设置不同的值:
- from=git-default-1.0
- from=git-dev-1.0
- from=git-test-1.0
- from=git-prod-1.0
以上的配置文件默认咋master分支中。再创建一个config-label-test分支,并将配置文件中的值用2.0作为后缀。
完成以上的步骤之后,我们就可以通过浏览器、PSTMAN或CURL等工具直接来访问我们的配置内容了,访问配置信息的URL与配置文件的映射关系如下:
- / { 应用名 } / { 环境名 } [ / { 分支名 } ]
- / { 应用名 } - { 环境名 }.yml
- / { 应用名 } - { 环境名 }.properties
- / { 分支名 } / { 应用名 } - { 环境名 }.yml
- / { 分支名 } / { 应用名 } - { 环境名 }.properties
上面的URL会映射{application}-{profile}.properties对应的配置文件,其中的{label}对应Git上不同的分支,默认为master。
我们在访问URL的时候,配置服务器在从Git中获取配置信息后,会存储一份在config-server的文件系统,实质上config-server是通过git clone命令将配置内容复制一份在本地存储,然后读取这些内容并返回给微服务应用进行加载。这样可以有效防止当Git仓库出现故障而引起无法加载配置文件的情况。
三、客户端映射配置
请直接参考:Spring Cloud (十七)、在微服务中获取配置中心的配置——客户端配置映射
-------------------------------------------服务端详解----------------------------------------------
四、基础架构
- 远程仓库:用来存储配置文件的地方。
- Config Server:分布式配置中心,在这里指定所要连接的Git仓库位置以及账户、密码等连接信息。
- 本地Git仓库:在Config Server的文件系统中,每次客户端请求获取配置信息时,Config Server从Git仓库中获取最新配置到本地,然后在本地Git仓库中读取并返回。当远程仓库无法获取时,直接将本地内容返回。
- Service A、Service B:具体的微服务应用,它们指定了Config Server的地址,从而实现了从外部化获取应用自己要用的配置信息。这些应用在启动的时候,会向Config Server请求获取配置信息来加载。
客户端应用从配置管理中获取配置信息遵从下面的执行流程:
- 微服务应用启动时,根据bootstrap.properties中配置的应用名{application}、环境名{profile}、分支名{label},向Config Server请求获取配置信息。
- Config Server根据自己维护的Git仓库信息和客户端传递过来的配置定位信息去查找配置信息。
- 找到配置信息后,通过git clone命令将找到了配置信息下载到Config Server的文件系统中(本地Git仓库)。
- Config Server创建Spring的ApplicationContext实例,并从Git本地仓库中加载配置文件,最后将这些配置内容读取出来返回给客户端应用(Service A、Service B)。
- 客户端应用(Service A、Service B)在获得外部配置文件后加载到客户端得ApplicationContext实例,该配置内容得优先级高于客户端Jar包内部的配置内容,所以在Jar包中重复的内容将不再被加载。
Config Server巧妙地通过git clone将配置信息存于本地,起到了缓存的作用,即使当Git服务端无法访问的时候,依然可以取Config Server中的缓存内容进行使用。
五、Git配置仓库
由于Spring Cloud Config默认使用了Git,所以对Git的配置非常简单,只需要在Config Server(配置中心工程中)的application.properties中设置spring.cloud.config.server.git.uri属性,为其指定Git仓库的网络地址和账户信息即可,如:
#Git仓库的位置
spring.cloud.config.server.git.uri=https://github.com/hedanning/SpringCloudConfigLearn
#访问Git仓库的用户名
spring.cloud.config.server.git.username=username
#访问Git仓库的密码
spring.cloud.config.server.git.password=password
1、占位符配置URI
{application}、{profile}、{label}这些不仅可以用于标识配置文件的规则,还可以用于Config Server中对Git仓库地址的URI配置。比如,我们可以通过{application}占位符来实现一个应用对应一个Git仓库目录的配置效果:
#Git仓库的位置
spring.cloud.config.server.git.uri=https://github.com/hedanning/{application}
#访问Git仓库的用户名
spring.cloud.config.server.git.username=username
#访问Git仓库的密码
spring.cloud.config.server.git.password=password
{application}代表了应用名,对应客户端中的spring.application.name的值。
2、配置多个仓库
Config Server除了可以通过application和profile模式来匹配配置仓库外,还支持带有通配符的表达式来匹配;还可以用都好来分割多个{application}/{profile}配置规则。
#默认的仓库位置,如果{application}/{profile}匹配不到,就在使用默认
spring.cloud.config.server.git.uri=https://github.com/hedanning/config-repo
#dev仓库匹配dev/*,无论profile是什么,它都能匹配大application名称为dev的应用
spring.cloud.config.server.git.repo.dev.pattern=dev/*
spring.cloud.config.server.git.repo.dev.uri=file://home/git/config-repo#test仓库未配置匹配规则,所以只匹配application名为test的应用
spring.cloud.config.server.git.repo.test=https://github.com/test/config-repo
#prod仓库则需要匹配application为prod并且profile为pp开头,或者application为online并且profile为oo开头的应用和环境
spring.cloud.config.server.git.repo.prod.pattern=prod/pp*,online/oo*
spring.cloud.config.server.git.repo.prod.uri=https://github.com/prod/config-repo
3、子目录存储
Config Server还可以将配置文件定位到Git仓库的子目录。
#仓库路径下的相对搜索位置
spring.cloud.config.server.git.search-paths=spring_cloud_in_action/config-repo
4、访问权限
Config Server在访问Git仓库的时候,若采用HTTP的方式进行认证,那么我们需要增加username和password属性来配置账户,比如:
#Git仓库的位置
spring.cloud.config.server.git.uri=https://github.com/hedanning/SpringCloudConfigLearn
#仓库路径下的相对搜索位置
spring.cloud.config.server.git.search-paths=spring_cloud_in_action/config-repo
#访问Git仓库的用户名
spring.cloud.config.server.git.username=username
#访问Git仓库的密码
spring.cloud.config.server.git.password=password
若不使用HTTP的认证方式,我们也可以采用SSH的方式,通过生成Key并在Git仓库中进行匹配以实现访问。
六、SVN配置仓库
Config Server除了支持Git仓库之外,也能使用SVN仓库,只需要做如下配置:
- 在pom.xml中引入SVN的依赖配置,让Config Server拥有读取SVN内容的能力:
<dependency>
<groupId>org.tmatesoft.svnkit</groupId>
<artifactId>svnkit</artifactId>
<version>RELEASE</version>
</dependency>
- 在application.properties中使用SVN的配置属性来指定SVN服务器的位置,以及访问的账户与密码。
spring.cloud.config.server.svn.uri=svn://localhost:443/hdnsapce/config-repo
spring.cloud.config.server.svn.username=username
spring.cloud.config.server.svn.password=password
通过上面的配置修改,Config Server就可以使用SVN作为仓库来存储配置文件了,而对于客户端来说,这个过程时透明的,所以不需要做任何变动。
七、本地仓库
在使用了Git或者SVN仓库之后,文件都会在Config Server的本地文件系统中存储一份,默认存储于config-repo为前缀的临时目录中,比如C:\Users\HDN\AppData\Local\Temp\config-repo-537612133146691877,config-server-<随机数>。我们可以通过spring.cloud.config.server.git.basedir或spring.cloud.config.server.svn.basedir来配置一个我们准备好的目录,如下:
spring.cloud.config.server.git.basedir=E:/java_dev/temp/git
spring.cloud.config.server.svn.basedir=E:/java_dev/temp/svn
八、本地文件系统
Spring Cloud Config提供了一种不使用Git仓库或SVN仓库的存储方式,而是使用本地文件系统的存储方式来保存配置信息。只需要设置属性 spring.profiles.active=native,Config Server默认会从应用的src/main/resource目录下搜索配置文件。还可以i通过spring.cloud.config.server.native.search-locations属性来指定具体的配置文件的位置。
九、健康监测
Spring Cloud Config的服务端为spring-cloud-starter-netflix-actuator模块的/health端点实现了对应的健康检测器:org.springframework.cloud.config.server.config.ConfigServerHealthIndicator。该检测器会不断的检查配置的URL仓库是否可以连通。
如果我们不想使用该健康检测器,可以通过使用spring.cloud.config.server.health.enabled=false参数设置来关闭它。
十、属性覆盖
可以让开发人员为所有的应用提供配置属性,通过spring.cloud.config.server.overrides属性来设置键值对的参数,这些参数会以Map的方式加载到客户端的配置中:
spring.cloud.config.server.overrides.name=hdn
spring.cloud.config.server.overrides.from=beijing
在Config Server中通过该属性配置的参数,不会被Spring Cloud的客户端修改,并且Spring Cloud客户端从Config Server中获取配置信息时,都会取到这些配置信息。
利用该特性可以方便地为Spring Cloud应用配置一些共同属性或是默认属性。
十一、安全保护
由于配置中心存储的内容比较敏感,做一定的安全处理是必需的。这里于Spring Security结合使用。
- 在Config Server的pom.xml中添加spring-boot-starter-security依赖,不需要做任何其他的操作就能实现对配置中心访问的安全保护。
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-security</artifactId>
</dependency>
默认情况下,我们可以获得一个名为user的用户,并且在配置中心启动的时候,在日志中打印出该用户的随机密码,如:
我们也可以在配置文件中指定用户名和密码:
spring.security.user.name=user
spring.security.user.password=70c0122c-e62c-379a-be9f-b95882d7d011
这时,我们在启动连接到配置中心的客户端的时候会返回401的错误信息,如下:
这时因为哦我们在Config Server设置了安全保护,那就也要在客户端加入安全信息来通过校验。
spring.cloud.config.username=user
spring.cloud.config.password=70c0122c-e62c-379a-be9f-b95882d7d011
十二、加密解密
将敏感信息以明文的方式存储在微服务应用中是非常危险的,所以要对属性进行加密解密的功能,以保护配置文件的信息安全。
1、使用前提
需要的配置中心运行的环境中安装不线长度的JCE版本,jre中默认自带的是限制长度的JCE。
下载jce8下载, 下载之后进行解压,有如下三个文件:
我们将local_policy.jar和US_export_policy.jar两个文件复制到jre目录下的security目录中(如:E:\java_dev\Java\jdk1.8.0_121\jre\lib\security),覆盖掉默认的内容就OK了!
2、相关端点
/encrypt/status:查看加密功能状态的端点。
/key:查看密钥的端点。
/encrypt:对请求的body内容进行加密的端点。
/decrypt:对请求的body内容进行解密的端点。
3、配置密钥:必须在bootstrap.properties配置文件中。
对称性加密:
encrypt.key=hdnspace12334566
- 使用/encrypt进行加密:
- 使用/decrypt进行解密:
通过配置encrypt.key参数来指定密钥的实现方式采用了对称性加密。
也可以使用环境变量ENCRYPT_KEY来进行配置,让密钥信息外部化存储。
4、非对称性加密:具有更高的安全性。
先了解一下keytool工具:通过keytool工具来生成密钥对,keytool是JDK中的一个密钥和证书管理工具。它使用户能够管理自己的公钥/私钥对及相关的证书,用于(通过数字签名)自我认证(用户向其他用户/服务认证自己)或数据完整性以及认证服务。在%JAVA_HOME%\bin\keytool.exe。
生成密钥的具体命令如下:
这时在E:\java_dev\temp位置生成了config-server.keystore文件,我们将此文件放到Config Server项目的src\main\resources目录下,并在bootstrap.properties文件中添加如下配置:
encrypt.key=123456
encrypt.key-store.location=config-server.keystore
encrypt.key-store.alias=config-server
encrypt.key-store.password=123456
encrypt.key-store.secret=123456
我在具体命令中输入的都是123456,所以在配置文件中设置的都是123456。
- 使用/encrypt进行加密:
- 使用/decrypt进行加密:
十三、高可用配置
两种方式:
- 传统模式:不需要做任何额外的配置,有多个配置中心,将所有的配置中心都指向同一个Git仓库,客户端通过负载均衡来调用配置中心。
- 服务模式:将配置中心作为以恶微服务应用,注册到Eureka的服务治理体系中。这样既实现了高可用,也实现了自我维护。
-------------------------------------------客户端详解----------------------------------------------
十四、URI指定配置中心
Spring Cloud Config的客户端在启动的时候,默认会从工程的classpath中加载配置信息并启动应用。只有当我们配置了spring.cloud.config.uri的时候,客户端应用才会尝试连接Spring Cloud Config的服务端来获取远程配置信息并初始化Spring环境。不指定spring.cloud.config.uri的话,Spring Cloud Config的客户端会默认尝试连接http://localhost:8888。
我们必须将spring.cloud.config.uri参数配置在bootstrap.properties、环境变量或是其他优先级高于应用Jar包内的配置信息中,才能正确加载到远程配置。
十五、服务化配置中心
将Config Server以服务的方式注册到注册中心,并被其他应用所发现来实现配置信息的获取。
具体操作请参考:Spring Cloud (十八)、服务化配置中心
十六、失败快速响应与重试
失败快速响应:
Spring Cloud Config的客户端会预先加载很多其他信息,然后在开始连接Config Server进行属性的注入。我们希望很快速地知道当前应用是否能顺利地从Config Server获取到配置信息,较少等待启动时间。
要实现客户端优先判断Config Server获取是否正常,我们只需要在客户端的bootstrap.properties文件中配置spring.cloud.config.fail-fast=true即可。这样就有效避免了当Config Server配置有误时,不需要多等待前置地一些加载时间,实现了快速返回失败信息。
重试:
保证客户端地bootstrap.properties文件中配置了spring.cloud.config.fail-fast=true之后,在客户端的pom.xml中添加以下依赖即可:
<dependency> <groupId>org.springframework.retry</groupId> <artifactId>spring-retry</artifactId> </dependency> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-aop</artifactId> </dependency>
客户端在连接Config Server失败之后,会继续尝试连接,直到第6次失败后才返回错误信息。通过这样的重试机制,可以避免一些间接性问题引起的失败导致客户端应用无法启动的情况。
若对默认的最大重试次数和重试间隔时间不满意,可以通过下面的参数进行调整:
#初始重试间隔时间(单位为毫秒),默认为10000毫秒
spring.cloud.config.retry.multiplier=
#下一间隔的乘数,默认为1.1,所以当初使时间是1000毫秒,下一次失败后的间隔为1100好眠
spring.cloud.config.retry.initial-interval=
#最大间隔时间,默认为2000毫秒
spring.cloud.config.retry.max-interval=
#最大重试次数,默认为6次
spring.cloud.config.retry.max-attempts=
十七、获取远程配置
在Git仓库中一个形如{application}-{profile}.properties或{application}-{profile}.yml的配置文件,可以通过URL请求和客户端配置来访问。
- 通过向Config Server发动GET请求
(1)不带{label}分支信息,默认访问master分支,可使用:
/{application}-{profile}.yml
/{application}-{profile}.properties
(2)带{label}分支信息,可使用:
/{label] /{application}-{profile}.yml
/{label] /{application}-{profile}.properties
/{application}/{profile}[ {label]]
- 通过客户端配置方式加载配置内容
#对应配置文件规则中的{application}部分
spring.application.name=hdnspace
#对应配置文件规则中的{propfile}部分
spring.cloud.config.profile=dev
#对应配置文件规则中的{label}部分,默认为master分支
spring.cloud.config.label=master
十八、动态刷新配置
实现配置内容的实时更新。
当我们使用Git工具修改了配置内容,在不重启客户端的时候,继续访问获取的结果还是之前的结果,这时需要我们使用spring-boot-starter-actuator的/refresh端点对客户端应用配置进行重新获取和刷新(http://localhost:7002/actuator/refresh)。在客户端的pom.xml中添加spring-boot-starter-actuator依赖即可实现:
<dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-actuator</artifactId> </dependency>
后续我们将介绍Spring Cloud Bus来实现以消息总线程的方式进行配置变更的通知,并完成集群上的批量配置更新。