对于Spring Boot应用,我们可以将配置内容写入application.yml,设置多个profile,也可以用多个application-{profile}.properties文件配置,并在启动时指定spring.profiles.active={profile}来加载不同环境下的配置。
在Spring Cloud微服务架构中,这种方式未必适用,微服务架构对配置管理有着更高的要求,如:
- 集中管理:成百上千(可能没这么多)个微服务需要集中管理配置,否则维护困难、容易出错;
- 运行期动态调整:某些参数需要在应用运行时动态调整(如连接池大小、熔断阈值等),并且调整时不停止服务;
- 自动更新配置:微服务能够在配置发生变化是自动更新配置。
Spring Cloud Config是Spring Cloud团队创建的一个全新项目,用来为分布式系统中的基础设施和微服务应用提供集中化的外部配置支持,它分为服务端与客户端两个部分。
其中服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置仓库并为客户端提供获取配置信息、加密/解密信息等访问接口;而客户端则是微服务架构中的各个微服务应用或基础设施,它们通过指定的配置中心来管理应用资源与业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息。
Spring Cloud Config实现的配置中心默认采用Git来存储配置信息,所以使用Spring Cloud Config构建的配置服务器,天然就支持对微服务应用配置信息的版本管理,并且可以通过Git客户端工具来方便的管理和访问配置内容。当然它也提供了对其他存储方式的支持,比如:SVN仓库、本地化文件系统。
1、准备配置仓库
https://github.com/huingsn/config-repo-demo.git
假设我们读取配置中心的应用名为config-client
那么我们可以在git仓库中该项目的默认配置文件config-client.yml:
1 | info: |
2、创建配置中心
核心依赖:
1 | <dependencies> |
配置信息:
1 | spring: |
启动类:
1 | //开启Spring Cloud Config的服务端功能。 |
创建bootstrap.yml配置,来指定获取配置文件的config-server-git位置:
1 | spring: |
启动类:
1 |
|
启动后访问结果:
一个简单的demo完成。
整体流程:
4、加密解密
Spring Cloud Config提供了对属性进行加密解密的功能,以保护配置文件中的信息安全。比如下面的例子:
1 | didi = |
在Spring Cloud Config中通过在属性值前使用{cipher}前缀来标注该内容是一个加密值,当微服务客户端来加载配置时,配置中心会自动的为带有{cipher}前缀的值进行解密。
加密准备:
使用Spring Cloud Config的加密解密功能时,为了启用该功能,需要在配置中心的运行环境中安装不限长度的JCE版本(Unlimited Strength Java Cryptography Extension)。
虽然JCE功能在JRE中就有,但是默认使用的是有长度限制的版本。我们可以从Oracle的官方网站中下载到它,它是一个压缩包,解压后可以看到下面三个文件:
README.txt
local_policy.jar
US_export_policy.jar
将local_policy.jar和US_export_policy.jar两个文件复制到$JAVA_HOME/jre/lib/security目录下,覆盖原来的默认内容。
完成了JCE的安装后,启动配置中心。在控制台中,将会输出了一些配置中心特有的端点,主要包括:
- /encrypt/status:查看加密功能状态的端点
- /key:查看密钥的端点
- /encrypt:对请求的body内容进行加密的端点
- /decrypt:对请求的body内容进行解密的端点
可以通过GET请求访问/encrypt/status端点,我们将得到如下内容:返回说明当前配置中心的加密功能还不能使用,因为没有为加密服务配置对应的密钥。1
2
3
4{
"description": "No key was installed for encryption service",
"status": "NO_KEY"
}
配置密钥:
通过encrypt.key属性在配置文件中直接指定密钥信息(对称性密钥),比如:
1 | encrypt: |
再访问http://localhost:1200/encrypt/status得到:
1 | { |
此时,我们配置中心的加密解密功能就已经可以使用了。
还有可以通过/encrypt和/decrypt端点来进行加密和解密的功能。
这两个端点都是POST请求,加密和解密信息需要通过请求体来发送。比如,以curl命令为例,我们可以通过下面的方式调用加密与解密端点:
1 | $ curl localhost:7001/encrypt -d didispace |
这里,我们通过配置encrypt.key参数来指定密钥的实现方式采用了对称性加密。这种方式实现比较简单,只需要配置一个参数即可。另外,我们也可以使用环境变量ENCRYPT_KEY来进行配置,让密钥信息外部化存储。
非对称加密
Spring Cloud Config的配置中心不仅可以使用对称性加密,也可以使用非对称性加密(比如:RSA密钥对)。虽然非对称性加密的密钥生成与配置相对复杂一些,但是它具有更高的安全性。
首先,我们需要通过keytool工具来生成密钥对。
keytool是JDK中的一个密钥和证书管理工具。它使用户能够管理自己的公钥/私钥对及相关证书,用于(通过数字签名)自我认证(用户向别的用户/服务认证自己)或数据完整性以及认证服务。
在JDK 1.4以后的版本中都包含了这一工具,它的位置在:%JAVA_HOME%\bin\keytool.exe。
生成密钥的具体命令如下:
1 | C:\Users\hu>keytool -genkeypair -alias config-server -keyalg RSA -keystore config-server.keystore |
1 | 如果我们不想逐步的输入那些提示信息,可以使用-dname来直接指定,而密钥库口令与密钥口令可使用-storepass和-keypass来直接指定。所以,我们可以通过下面的命令直接创建出与上述命令一样的密钥库: |
配置中心高可用
在生产环境,Config Server与服务注册中心一样,我们也需要将其扩展为高可用的集群。
spring cloud config 实现高可用非常简单,不需要为这些服务端做额外的配置,只需要遵守一个配置规则:将所有的Config Server都指向同一个Git仓库
这样所有的配置内容就通过统一的共享文件系统来维护,而客户端在指定Config Server位置时,只要配置Config Server外的均衡负载即可,就像如下图所示的结构:
虽然通过服务端负载均衡已经能够实现,但是作为架构内的配置管理,本身其实也是可以看作架构中的一个微服务。所以,另外一种方式更为简单的方法就是把config-server也注册为服务,这样所有客户端就能以服务的方式进行访问。
通过这种方法,只需要启动多个指向同一Git仓库位置的config-server就能实现高可用了。
在config-server-git的基础上复制一个名为:config-server-git-eureka
依赖中增加:
1
2
3
4<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-eureka</artifactId>
</dependency>
作为服务放到注册中心
1 | spring: |
启动类增加@EnableDiscoveryClient //用来将config-server注册到上面配置的服务注册中心上去。
启动后可以访问注册中心,看到服务已经注册到注册中心。
config-client配置和config-server-git-eureka一样,复制config-client修改名字为config-client-eureka,需要增加
1 | <dependency> |
修改配置
1 | spring: |
启动项目:
浏览http://localhost:1201/user即可得到key对应的值
demo 见:spring-cloud-config