【SpringCloud】四、Spring Cloud Config
Spring Cloud Config
- 前言
- 一、什么是配置中心
- 1、 为什么需要分布式配置中心
- 2、常用分布式配置中心框架
- 二、什么是Spring Cloud Config?
- 1、Springcloud config 的工作原理
- 2、构建 Spring cloud config 配置中心仓库
- 3、构建 Spring cloud config 配置中心服务端
- 4、构建 Springcloud config 配置中心客户端
- **bootstrap.properties** 文件;
- 5、配置信息的加解密安全处理
- 对称加密
- 6、Spring Cloud Config配置动态刷新
- 配置信息局部刷新
- 配置信息全局刷新
前言
目前市场长主流的分布式配置中心大概NACOS占的比例多点,其次是Apollo,但本文是以学习的角度出发,进行学习记录的。
一、什么是配置中心
- 1、传统配置方式:
配置信息分散到系统各个角落方式,配置文件或者在代码中; - 2、集中式配置中心:
将应用系统中对配置信息的管理作为一个新的应用功能模块,进行集中统一管理,并且提供额外功能; - 3、分布式配置中心:
在分布式、微服务架构中,独立的配置中心服务;
1、 为什么需要分布式配置中心
在分布式微服务体系中,服务的数量以及配置信息日益增多,比如各种服务器参数配置、各种数据库访问参数配置、各种环境下配置信息的不同、配置信息修改之后实时生效等等,传统的配置文件方式或者将配置信息存放于数据库中的方式已无法满足开发人员对配置管理的要求,如:
- 安全性:配置跟随源代码保存在代码库中,容易造成配置泄漏
- 时效性:修改配置,需要重启服务才能生效;
- 局限性:无法支持动态调整:例如日志开关、功能开关;
2、常用分布式配置中心框架
Nacos:Nacos /nɑ:kəʊs/ 是 Dynamic Naming and Configuration Service的首字母简称,一个更易于构建云原生应用的动态服务发现、配置管理和服务管理平台。
Apollo(阿波罗):携程框架部门研发的分布式配置中心,能够集中化管理应用不同环境、不同集群的配置,配置修改后能够实时推送到应用端,并且具备规范的权限、流程治理等特性,适用于微服务配置管理场景;
diamond : 淘宝开源的持久配置中心,支持各种持久信息(比如各种规则,数据库配置等)的发布和订阅;(更新稍微落后一点)
XDiamond:全局配置中心,存储应用的配置项,解决配置混乱分散的问题,名字来源于淘宝的开源项目diamond,前面加上一个字母X以示区别。
Qconf: 奇虎360内部分布式配置管理工具,用来替代传统的配置文件,使得配置信息和程序代码分离,同时配置变化能够实时同步到客户端,而且保证用户高效读取配置,这使的工程师从琐碎的配置修改、代码提交、配置上线流程中解放出来,极大地简化了配置管理工作;
Disconf:百度的分布式配置管理平台,专注于各种分布式系统配置管理的通用组件和通用平台, 提供统一的配置管理服务;
Spring Cloud Config:Spring Cloud微服务开发的配置中心,提供服务端和客户端支持;
国外也有很多开源的配置中心 Apache 的 Apache Commons Configuration、owner、cfg4j 等等;
大型互联网公司自己内部都有自己独立分布式配置中心,用于解决服务配置管理问题;
二、什么是Spring Cloud Config?
Spring Cloud Config 是一个解决分布式系统的配置管理方案。它包含 Client和 Server 两个部分,Server 提供配置文件的存储、以接口的形式将配置文件的内容提供出去,Client 通过接口获取数据、并依据此数据初始化自己的应用。
Spring cloud config使用 git 或 svn 、也可以是本地存放配置文件,默认情况下使用 git。
1、Springcloud config 的工作原理
Spring cloud Config Server 的工作过程如下图所示:
1、首先需要一个远程 Git 仓库,平时测试可以使用 GitHub,在实际生产环境
中,需要自己搭建一个 Git 服务器,远程 Git 仓库的主要作用是用来保存我们的配置文件;
2、除了远程 Git 仓库之外,我们还需要一个本地 Git 仓库,每当 Config Server访问远程 Git 仓库时,都会克隆一份到本地,这样当远程仓库无法连接时,就直接使用本地存储的配置信息;
3、微服务 A、微服务 B 则是我们的具体应用,这些应用在启动的时会从 Config
Server 中获取相应的配置信息;
4.当微服务 A、微服务 B 尝试从 Config Server 中加载配置信息的时候,Config Server 会先通过 git clone 命令克隆一份配置文件保存到本地;
5、由于配置文件是存储在 Git 仓库中,所以配置文件天然具有版本管理功能;
2、构建 Spring cloud config 配置中心仓库
前面我们介绍了spring cloud config的配置中心一般是采用git存储配置,(我们在这里采用国内的码云 gitee, 也可以使用国外的GitHub,由于使用Github网络比较慢,可能连接失败) ,
接下来我们需要在 gitee 上设置好配置中心,我们通过idea 把gitee上的springcloud项目clone到本地,然后再项目下创建一个文件夹config-center,然后在 config-center中创建四个配置文件,如下:
application.properties
application-dev.properties
application-test.properties
application-online.properties
在四个文件里面分别写上要测试的内容:
比如:
url=http://www.test.com
url=http://dev.test.com
url=http://test.test.com
url=http://online.test.com
然后通过idea将本地文件同步到 Gitee 仓库中: ’
3、构建 Spring cloud config 配置中心服务端
构建一个 spring cloud config 配置中心按照如下方式进行:
1、创建一个普通的 Spring Boot 项目
2、在 pom.xml 文件中添加如下依赖:
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-config-server</artifactId>
</dependency>
3、在入口类,也就是 main 方法的类上添加注解 @EnableConfigServer
@EnableConfigServer //开启spring cloud config配置中心支持
@SpringBootApplication
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
4、在application.properties中配置一下git仓库信息,此处我们使用gitee (也可以使用码云GitHub,由于网络比较慢,可能连接失败) ,
首先我的gitee上有一个名为 springcloud的项目,我们的配置文件如下:
server.port=8888
spring.application.name=springcloud-service-config
spring.cloud.config.server.git.uri=https://gitee.com/springcloud.git
spring.cloud.config.server.git.search-paths=config-center
spring.cloud.config.server.git.username=name
spring.cloud.config.server.git.password=123456.
其中:
1.uri 表示配置中心所在仓库的位置
2.search-paths 表示仓库下的子目录
3.username 表示你的 GitHub 用户名
4.password 表示你的 GitHub 密码
至此我们的配置中心服务端就创建好了。
配置文件的映射规则:
/{application}/{profile}[/{label}]
http://localhost:8888/application/dev/master
/{application}-{profile}.properties
http://localhost:8888/application-dev.properties
/{label}/{application}-{profile}.properties
http://localhost:8888/master/application-dev.properties
/{application}-{profile}.yml
http://localhost:8888/application-dev.yml
/{label}/{application}-{profile}.yml
http://localhost:8888/master/application-dev.yml
其中:
{application} 表示配置文件的名字,对应的配置文件即 application,
{profile} 表示环境,有 dev、test、online 及默认,
{label} 表示分支,默认我们放在 master 分支上,
通过浏览器上访问 http://localhost:8888/application/dev/master
返回的 JSON 格式的数据:
name 表示配置文件名 application 部分,
profiles 表示环境部分,
label 表示分支,
version 表示 GitHub 上提交时产生的版本号,
同时当我们访问成功后,在控制台会打印了相关的日志信息;
当访问成功后配置中心会通过 git clone 命令将远程配置文件在本地也保存一
份,以确保在 git 仓库故障时我们的应用还可以继续正常使用。
4、构建 Springcloud config 配置中心客户端
前面已经搭建好了配置中心的服务端,并且通过访问接口从config服务端读取配置信息, 不过实际开发中,更多的不是我们人为去获取配置信息,而是由微服务自己从config服务端上加载配置信息, 那么怎么来加载呢?
1、我们的各个微服务都是客户端,比如服务提供者、服务消费者等各个微服务都可以从配置中心获取配置信息,但是要添加如下依赖:
<!-- spring-cloud-starter-config -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-config</artifactId>
</dependency>
2、创建 bootstrap.properties 文件,用于获取配置信息,文件内容如下:
(注意这些信息一定要放在 bootstrap.properties 文件中才有效)
spring.application.name=application
spring.cloud.config.profile=dev
spring.cloud.config.label=master
spring.cloud.config.uri=http://localhost:8888/
其中:
- name 对应配置文件中的 application 部分,
- profile 对应了 profile 部分,
- label 对应了 label 部分,
- uri 表示配置中心的地址。
bootstrap.properties 文件;
Spring Cloud有一个“引导上下文"的概念,这是主应用程序的父上下文。引导上下文负责从配置服务器加载配置属性,以及解密外部配置文件中的属性。和主应用程序加载application.(yml或 properties)中的属性不同,引导上下文加载(bootstrap.)中的属性。配置在 bootstrap.*中的属性有更高的优先级,因此默认情况下它们不能被本地配置覆盖;
3、创建一个 Controller 进行测试:
@RestController
@RefreshScope
public class ConfigController {
@Value("${url}")//读取远程配置中心配置的信息
private String url;
@Autowired
private Environment env;
@RequestMapping("/cloud/url")
public String url () {
return this.url;
}
@RequestMapping("/cloud/url2")
public String url2 () {
return env.getProperty("url");
}
}
我们可以直接使用@Value 注解注入配置的属性值,也可以通过 Environment
对象来获取配置的属性值。
5、配置信息的加解密安全处理
前面是在Git仓库中明文存储配置信息值,很多场景下,对于某些敏感的配置内容(例如数据库账号、密码等),应该加密存储,config server为我们考虑到了这一点,对配置内容提供了加密与解密支持;
安装JCE
config server的加解密功能依赖Java Cryptography Extension(JCE)
Java 8 JCE下载地址:
http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html
下载得到JCE的zip压缩包并解压,将其中的jar包覆盖到JDK/jre/lib/security目录下;
对称加密
config server提供了加密与解密的接口,分别是
加密接口:http://localhost:8888/encrypt
解密接口:http://localhost:8888/decrypt (这个接口我们不需要用)
解密是config-server自动完成的;
在原来的springcloud-service-config项目中添加bootstrap.properties配置文件,里面配置密钥:
#设置对称密钥,用这个密钥进行加密和解密
encrypt.key=testencrypt
运行项目,验证加解密:
加密:curl http://localhost:8888/encrypt -d root
得到:9455e7d7333e1cc9d1a8680244f6db3aae6de93825d4bc6f9f4258993f7a8cad
解密:curl http://localhost:8888/decrypt -d 9455e7d7333e1cc9d1a8680244f6db3aae6de93825d4bc6f9f4258993f7a8cad
在git仓库增加修改配置文件application-dev.properties,增加如下内容:
spring.datasource.username={cipher}9455e7d7333e1cc9d1a8680244f6db3aae6de93825d4bc6f9f4258993f7a8cad
spring.datasource.password={cipher}5a6e3e417d416736d638cd4db7a6380a71a8709c3ec335a28e01cff05705eeaa
访问地址:http://localhost:8888/application-dev.properties 得到密钥原文;
说明 config server能自动解密配置内容;
6、Spring Cloud Config配置动态刷新
很多场景下,需要在运行期间动态调整配置,如果配置发生了修改,微服务要如何实现配置的动态刷新呢?
配置信息局部刷新
Spring Boot 的actuator提供了一个刷新端点/refresh,添加依赖spring-boot-starter-actuator,可用于配置的刷新;
1、添加依赖:
<!--springboot的一个监控actuator-->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
2、在Controller上添加注解@RefreshScope,添加这个注解的类会在配置更新时得到特殊的处理;
3、打开web访问端点:management.endpoints.web.exposure.include=*
4、访问http://localhost:8080/actuator/refresh 进行手动刷新配置;
(Post访问)
这种方式的刷新,就是你对每个微服务分别进行刷新,也一个一个操作,如果你有80个微服务,那么就需要手动刷新这80个微服务;
配置信息全局刷新
前面使用/actuator/refresh端点手动刷新配置虽然可以实现刷新,但所有微服务节点的配置都需要手动去刷新,如果微服务非常多,其工作量非常庞大。因此,实现配置的自动刷新是志在必行,Spring Cloud Bus就可以用来实现配置的自动刷新;
Spring Cloud Bus使用轻量级的消息代理/总线(例如RabbitMQ、Kafka等)广播传播状态的更改(例如配置的更新)或者其他的管理指令,可以将Spring Cloud Bus想象成一个分布式的Spring Boot Actuator;
Config项目添加依赖:(服务端)
<!-- spring-cloud-starter-bus-amqp -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
<!-- spring-boot-starter-actuator -->
<dependency>
<groupId>org.springframework.boot</groupId>
<artifactId>spring-boot-starter-actuator</artifactId>
</dependency>
配置文件增加rabbitmq的配置:
#配置rabbitmq
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
#开启spring cloud bus,默认是开启的,也可以省略该配置
spring.cloud.bus.enabled=true
#打开所有的web访问端点
management.endpoints.web.exposure.include=*
各个微服务(客户端)
其他各个微服务用于接收消息,那么也需要有spring cloud bus的依赖和RabbitMQ的连接信息;
<!-- spring-cloud-starter-bus-amqp -->
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-bus-amqp</artifactId>
</dependency>
#配置rabbitmq
spring.rabbitmq.host=127.0.0.1
spring.rabbitmq.port=5672
spring.rabbitmq.username=guest
spring.rabbitmq.password=guest
然后post方式请求地址:http://localhost:8888/actuator/bus-refresh 如果返回成功1,则RabbitMQ将收到消息,然后微服务会消费消息,config的所有客户端的微服务配置都会动态刷新;