Spring Cloud(七)Spring Cloud Config(统一管理配置)

uml图:
在这里插入图片描述

1.简介

Spring Cloud Config为分布式系统外部化配置提供了服务器端和客户端支持,它包括Config Server和Config Client两部分。由于Config Service和Config Client都实现了对Spring Environment 和PropertySource抽象的映射,因此,Spring Cloud Config非常适合Spring 应用程序,当然也可与任何其他语言编写的应用程序配合使用。

Config Server 是一个可横向扩展、集中式的配置服务器,它用于集中管理应用程序各个环境下的配置,默认使用Git存储配置内容(也可以使用Subversion、本地文件系统或Vault存储配置),因此可以很方便的实现对配置的版本控制与内容审计。

2.编写ConfigServer
创建项目,添加配置文件,push到Git

如果要编写Config Server,我们首先要有一个项目,可以存储配置文件,并且推送到了Git. 比如我在我的Git仓库有以下仓库和文件。

master:

application.yml 内容是profile: default

microservice-config-client-test.yml内容是profile: test

microservice-config-client-prod.yml内容是profile: prod

release:

microservice-config-client-dev.properties内容是profile: dev

创建Maven项目:microservice-config-server

并添加依赖

<dependency>

 <groupId>org.springframework.cloud</groupId>

 <artifactId>spring-cloud-config-server</artifactId>

</dependency>
编写启动类,在其启动类上添加注解@EnableConfigServer
@SpringBootApplication

@EnableConfigServer

public classConfigServerApplication {

      public static void main(String[] args) throws Exception {

           SpringApplication.run(ConfigServerApplication.class, args);

      }
}
编写配置文件application.yml,并添加以下内容

在这里插入图片描述

我们可以使用configserver的断点获取配置内容
/{application}/{profile}[/{label}]

/{application}-{profile}.yml

/{label}/{application}-{profile}.yml

/{application}-{profile}.properties

/{label}/{application}-{profile}.properties
  • application: 表示微服务的虚拟主机名,即配置的spring.application.name
  • profile: 表示当前的环境,dev,test or production
  • label: 表示git仓库分支,master or relase or others repository name?默认是master

如果没有找到,就会找默认的

比如:

http://localhost:9000/microservice-config-client/test

http://localhost:9000/master/microservice-config-client-prod

http://localhost:9000/microservice-config-client/dev

http://localhost:9000/release/microservice-config-client-dev.yml

http://localhost:9000/microservice-config-client-prod.yml
# 以下这个是找不到的,应该会找默认的properties,如果没有properties则会找yml

http://localhost:9000/microservice-config-client/uat
3.编写ConfigClient

我们已经知道如何使用Config Server端点获取配置内容,这一节我们讨论微服务如何获取配置信息

创建ConfigClient maven项目

添加依赖:

<dependency>

 <groupId>org.springframework.cloud</groupId>

 <artifactId>spring-cloud-starter-config</artifactId>

</dependency>

<dependency>

  <groupId>org.springframework.boot</groupId>

 <artifactId>spring-boot-starter-web</artifactId>

</dependency>

<dependency>

 <groupId>org.springframework.boot</groupId>

 <artifactId>spring-boot-starter-actuator</artifactId>

</dependency>
编写启动类
@SpringBootApplication

public classConfigClientApplication {

      public static void main(String[] args) throws Exception {

           SpringApplication.run(ConfigClientApplication.class, args);

      }

}
编写配置文件application.yml和 bootstrap.yml
application.yml:

server:

  port: 9010

bootstrap.yml:

spring:

  cloud:

    config:

      # Config Server 地址

      uri: http://localhost:9000

      # 对应的Config Server的配置文件对应的profile,即环境

      profile: dev

      # 对应的Config Server的配置文件对应的Git分支

      label: release

  application:

    # 对应的Config Server的配置文件对应的application

    name: microservice-config-client
 

有人会问,为什么不都配置在application.yml里面呢,而要配置bootstrap里面呢?

因为boostrap用于应用程序上下文的引导阶段,通常用于引导上下文从外部资源获取配置属性,比如Spring Cloud Config Server,或者 解密外部配置文件的属性等。 默认的Config Server地址是localhost:8888. 所以我们只能在bootstrap.yml或者bootstrap.properties中修改。

如需禁用引导过程,你可以设置

spring.cloud.bootstrap.enabled=false
编写controller
@RestController

public classConfigClientController {

      @Value("${profile}") // 绑定git仓库配置文件属性profile

      private String profile;

      @RequestMapping("/profile")

      public StringgetProfile() {

           return this.profile;

      }

}
启动和测试

http://localhost:9010/profile

如果我们在application.yml添加以下代码:

profile: prod

spring:

  cloud:

    config:

      profile: test

第一个peofile并不会改变我们访问http://localhost:9010/profile的值;但是第二个spring.cloud.config.profile却会影响到。它覆盖了bootstrap里面的该值。

4.Config Server 的Git仓库配置
占位符的支持

Config Server占位符支持{application},{profile},{label}

比如:

https://gitee.com/nickyzhang/{application}

测试:

#创建2个项目simple 和 special

simple项目添加文件

application.yml 内容为profile: simple

simple-prod.yml 内容为profile: simple-prod

special项目添加文件

application.yml 内容为profile: special

simple-prod.yml 内容为profile: special-prod

# Config Server的配置

server:

  port: 9000

spring:

  cloud:

    config:

      server:

        git:

          # git 仓库地址

          uri:https://gitee.com/nickyzhang/{application}

          # git 仓库账号

          username:

          # git 仓库密码

          password:

# 然后启动config server,测试

http://localhost:9000/master/simple-prod.yml

http://localhost:9000/special-prod.yml

模式匹配

模式匹配指的是带有通配符的{application}/{profile}名称的列表

如果{application}/{profile}不匹配任何模式,将使用这个配置项spring.cloud.config.server.git.url定义的URL

spring:

  cloud:

    config:

      server:

        git:

          # git 仓库地址

          uri:https://gitee.com/nickyzhang/spring-cloud-config-repo

          repos:

            simple: https://gitee.com/nickyzhang/simple

            special:

              pattern: special*/prod/*,*special*/prod*

              uri:https://gitee.com/nickyzhang/special

            local:

              pattern: local*

              uri:file:/home/configsvc/config-repo

          # git 仓库账号

          username:

          # git 仓库密码

          password:

 

spring:

  cloud:

    config:

      server:

        git:

         uri: https://github.com/spring-cloud-samples/config-repo

         repos:

           development:

             pattern:

               - '*/development'

               - '*/staging'

             uri: https://github.com/development/config-repo

           staging:

             pattern:

               - '*/qa'

               - '*/production'

             uri: https://github.com/staging/config-repo
搜索目录

有些时候,可能把配置文件放在Git仓库子目录中,此时可以使用search-path指定,而且同样支持占位符

spring:

  cloud:

    config:

      server:

        git:

          uri:https://github.com/spring-cloud-samples/config-repo

          searchPaths: foo,bar*

这样,Config Server就会在Git仓库根目录、foo子目录,以及所有以bar开始的子目录中查找配置文件

启动时加载配置文件

默认情况下,在配置被首次请求时,ConfigServer才会clone git仓库。也可以让Config Server在启动时就clone git仓库,例如:

spring:

  cloud:

    config:

      server:

        git:

          uri: https://git/common/config-repo.git

          repos:

            team-a:

                pattern: team-a-*

                cloneOnStart: true

                uri:http://git/team-a/config-repo.git

            team-b:

                pattern: team-b-*

                cloneOnStart: false

                uri:http://git/team-b/config-repo.git

            team-c:

                pattern: team-c-*

                uri: http://git/team-a/config-repo.git

我们也可以设置全局的:

spring.cloud.config.git.clone-on-start: true

设置clone-on-start=true可以让我们快速识别错误的资源

5. 配置内容的加密和解密
安装JCE

Config Server加解密的功能依赖Java Cryptography Extension(JCE)

从ORACLE根据你使用的JDK版本下载:

http://www.oracle.com/technetwork/java/javase/downloads/jce8-download-2133166.html

解压然后替换掉\jre1.8.0_92\lib\security下面的jar包

Config Server的加密和解密端

Config Server提供了加密与解密的端点,分别是/encrypt 与 /decrypt,

诸如:

curl -X POST http://localhost:9000/encrypt -d 想要加密的明文
curl -X POST http://localhost:9000/decrypt -d 想要解密的密文

对称加密

很简单,在application.yml里面设置对称密钥,即

encrypt.key: foo

启动Config Server,然后测试。

curl-X POST http://localhost:9000/encrypt -d foo

返回密文:FKSAJDFGYOS8F7GLHAKERGFHLSAJ

输入

curl-X POST http://localhost:9000/decrypt -dFKSAJDFGYOS8F7GLHAKERGFHLSAJ

返回foo,说明可以正常解密

存储加密的内容

加密后的内容,可使用{cipher}密文的形式存储。准备一个配置文件:

encryption.yml:

spring:

  datasource:

    username: admin

password:'{cipher}U2FsdGVkX1+6Wfv66BRyKzYVHvN84cvAZQ=='

或者准备一个encryption.properties:

spring.datasource.username=admin

spring.datasource.password={cipher}U2FsdGVkX1+6Wfv66BRyKzYVHvN84cvAZQ==

注意密码加单引号括起来。

然后将其push到Git仓库https://gitee.com/nickyzhang/spring-cloud-config-repo

然后访问http://localhost:9000/encrption-default.yml

则可以正常读取密码123abcABC

非对称加密
  1. 执行以下命令,生成server.jks,即可创建一个Key Store

keytool -genkeypair -alias mytestkey -keyalg RSA-dname "CN=Web Server,OU=Unit,O=Organization,L=City,S=State,C=US"-keypass changeme -keystore server.jks -storepass letmein
  1. 将生成的server.jks复制到项目classpath路径下

  2. application.yml配置文件添加以下内容

encrypt:

  key-store:

    location: classpath:/server.jks # jks文件路径

    password: letmein # storepass

    alias: mytestkey # alias

secret: changeme # keypass

这样的话,使用以下命令

curl http://localhost:9000/encrypt -d mysecret去测试

对称加密和非对称加密的比较:

  • 对称式加密:解密方式是加密方式的逆运算,即加密和解密使用的是同一个密钥(初等加密算法)。
  • 非对称式加密:加密和解密需要两个密钥进行,这两个密钥是公钥和私钥(高等加密算法)。
6.使用/refresh端点手动刷新配置

有时候,我们需要在运行期间动态调整配置。如果配置发生了修改,微服务要如何实现配置的刷新呢?

  1. 添加依赖,主要是spring-boot-starter-actuator
<dependency>

 <groupId>org.springframework.cloud</groupId>

 <artifactId>spring-cloud-starter-config</artifactId>

</dependency>

<dependency>

 <groupId>org.springframework.boot</groupId>

 <artifactId>spring-boot-starter-web</artifactId>

</dependency>

<dependency>

 <groupId>org.springframework.boot</groupId>

 <artifactId>spring-boot-starter-actuator</artifactId>

</dependency>
  1. 在controller上添加注解
@RestController

@RefreshScope

public classConfigClientController {

      @Value("${profile}")

      private String profile;

 

      @RequestMapping("/profile")

      public StringgetProfile() {

           return this.profile;

      }

}

然后将配置文件更新,并且push到git远程仓库

刷新测试

请求http://localhost:9000/profile,发现并没有刷新,此时我们需要调用http://localhost:9000/refresh, 然后再次请求/profile,会发现已经刷新了。

如果遇到以下错误:

{"timestamp":1507270047254,"status":401,"error":"Unauthorized","message":"Fullauthentication is required to access this resource.","path":"/refresh"}

在配置文件中添加:

management:

  security:

    enabled: false
7.使用SpringCloud Bus自动刷新配置

使用/refresh端点手动刷新配置,但是如果所有微服务节点的配置都需要手刷新,工作量有可能很大。而且随着系统的扩张,越来难以维护。因此实现配置的自动刷新是很有必要的。

简介

Spring Cloud Bus使用轻量级的消息代理,RabbitMQ, Kafka等连接分布式系统的节点,这样就可以广播状态的改变。可以将Spring Cloud Bus想象成Spring Boot Actuator,架构图如下所示:
在这里插入图片描述
由图可知,微服务A的所有实例都通过消息总线连接到了一起,每一个实例都会订阅配置更新事件。当其中一个微服务节点的/bus/refresh端点被请求,该实例就会向消息总线发送一个配置更新事件,其他实例获得该事件后也会更新配置。

实现自动刷新
  1. 添加依赖
<dependency>

 <groupId>org.springframework.cloud</groupId>

 <artifactId>spring-cloud-starter-bus-amqp</artifactId>

</dependency>
  1. 配置application.yml
spring:

  rabbitmq:

    host:localhost

    port:5672

    username:guest

password: guest

测试
3. 启动config server 和 config client(多个实例)

  1. 先访问客户端不修改配置文件的情况

  2. 直接访问http://localhost:9000/profile

  3. 然后再将文件内容修改,再次访问http://localhost:9000/profile看是否发生改变

  4. 如果没有,将POST 请求到其中一个Config Client实例的/bus/refresh端点,如

curl –X POST http://localhost:8081/bus/refresh
  1. 再访问其他的节点profile端点,如果都一致了说明生效了。

  2. 借助Git仓库的WebHooks,就可以轻松实现配置的自动刷新:
    在这里插入图片描述

架构改进

通过请求某个微服务/bus/refresh端点的方式来实现配置刷新,但是这种方式不太优雅,因为:

  • 破坏了微服务的职责单一原则

  • 破坏了微服务各节点对等性

  • 有一定的局限性,比如微服务在迁移的时候,网络地址常常会发生变化,此时如想自动刷新配置,就不得不修改WebHook的配置

在这里插入图片描述
将Config Server也加入总线中,并使用Config Server的/bus/refresh端点来实现配置的刷新。这样各个微服务只需要关注自身的业务,而不再承担配置刷新的职责。

跟踪总线事件

一些场景下,希望知道Spring CloudBus事件的传播细节,可以跟踪总线事件(RemoteApplicationEvent的子类都是总线事件)。

只需要我们设置

spring.cloud.bus.trace.enbaled=true

在/bus/refresh端点被请求后,访问/trace端点就可以获得结果

8.Spring Cloud Config 配合Eureka使用

前面描述可知,微服务中指定了Config Server地址,这种方式无法利用服务发现组件的优势。下面讨论Config Server注册到Eureka上时,如何使用Spring Cloud Config

  1. 将ConfigServer 和 Config Client 注册到EurekaServer上
  2. Config Client的bootstrap.yml配置如下:
spring:

  application:

    name: microservice-client-bus

  cloud:

    config:

      uri: http://localhost:8088

      profile: prod

      label: master

      discovery:

        enabled: true # 开启通过服务发现组件访问Config Server的功能

        # 指定Config Server在服务发现组件中的serviceId

        service-id: microservice-config-server-eureka

eureka:

  client:

    serviceUrl:

      defaultZone: http://localhost:8761/eureka/

简要说明一下bootstrap.yml中的配置属性:

  • spring.cloud.config.discovery.enable=true:表示开启通过服务发现组件访问 Config Service的功能;
  • spring.cloud.config.discovery.service-id:指定Config Service在服务发现组件中的serviceId。
9.用户认证

在之前的配置中Config Server是允许匿名访问的,为了防止配置内容的泄露,应该保护Config Server的安全。简单的说我们可以为Config Server添加用户认证。

  1. 先构建一个需要用户认证的Config Server,然后添加依赖
<dependency>

 <groupId>org.springframework.boot</groupId>

 <artifactId>spring-boot-starter-security</artifactId>

</dependency>
  1. 修改application.yml配置文件
server:

  port: 9000

spring:

  cloud:

    config:

      server:

        git:

          uri:https://gitee.com/nickyzhang/{application}

          username:

          password:

security:

  basic:

    enabled: true

  user:

    name: nicky

    password: 123abcABC
Config Client连接需要认证的Config Server的时候

方式一:使用curl风格的URl

spring:

  cloud:

    config:

      uri:http://nicky:123abcABC@localhost:9000

方式二:指定Config Service的账号与密码

spring:

  cloud:

    config:

      uri:http://localhost:9000

     username: nicky

     password: 123ab

方式二的优先级较高,它们会覆盖URL中包含的账号密码。

10.高可用
Git仓库的高可用

由于配置内容存储在Git仓库中,所以想要实现Config Server的高可用,必须有一个高可用的Git仓库。有两总方式可以实现Git仓库高可用。

  • 第一种:使用第三方的Git仓库,这种方式很简单,可以使用GitHub,BitBucket等提供的仓库托管服务,这些服务本身已经就是高可用的
  • 第二种:自己搭建的Git仓库管理系统:使用第三方服务虽然省事儿,但很多场景下,更倾向于自己搭建,这时也需要保证Git高可用

以GitLab为例子,可以参考https://about.gitlab.com/high-availability/

MQ高可用

即RabbitMQ 或者Kafka高可用

Config Server自身的高可用

Config Server未注册到Eureka Server上
可以借助一个负载均衡器来实现
在这里插入图片描述
Config Server注册到了Eureka Server上
这种情况就比较简单了,只需将多个ConfigServer注册到Eureka Server上,即可实现Config Server高可用

关注公众号【程序员每日一学】让我们每天一起学习进步~

在这里插入图片描述

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序猿小张丶

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值