Spring Cloud - Config统一配置管理

1.为什么要统一管理微服务配置

对于Spring Boot应用,我们可以将配置内容写入application.yml,设置多个profile,也可以用多个application-{profile}.properties文件配置,并在启动时指定spring.profiles.active={profile}来加载不同环境下的配置。

在Spring Cloud微服务架构中,这种方式未必适用,微服务架构对配置管理有着更高的要求,如:

  • 集中管理:成百上千(可能没这么多)个微服务需要集中管理配置,否则维护困难、容易出错;
  • 运行期动态调整:某些参数需要在应用运行时动态调整(如连接池大小、熔断阈值等),并且调整时不停止服务;
  • 自动更新配置:微服务能够在配置发生变化是自动更新配置。

以上这些要求,传统方式是无法实现的,所以有必要借助一个通用的配置管理机制,通常使用配置服务器来管理配置。

2.Sping Cloud Config简介

Spring Cloud Config分为Config Server和Config Client两部分,为分布式系统外部化配置提供了支持。 Spring Cloud Config非常适合Spring应用程序,也能与其他编程语言编写的应用组合使用。

微服务在启动时,通过Config Client请求Config Server以获取配置内容,同时会缓存这些内容。

3.Config Server

Config Server是一个集中式、可扩展的配置服务器,它可以集中管理应用程序各个环境下的配置,默认使用Git存储配置内容。

3.1 创建Config Server

3.1.1 创建用于存放配置文件的git仓库,添加配置文件

service1.properties

profile=default-1.0

service1-dev.properties

profile=dev-1.0

service1-test.properties

profile=test-1.0

service1-pro.properties

profile=pro-1.0
3.1.2 创建一个Spring Boot应用config-server,添加spring-cloud-config-server依赖
dependencies {
    compile('org.springframework.cloud:spring-cloud-config-server:1.4.1.RELEASE')
}
3.1.3 在启动类添加@EnableConfigServer注解
@EnableConfigServer
@SpringBootApplication
public class Application {

    public static void main(String[] args) {
        SpringApplication.run(Application.class,args);
    }

}
3.1.4 在application.yml中配置Git仓库地址
server:
  port: 8181
spring:
  application:
    name: config-server
  cloud:
    config:
      server:
        git:
          uri: https://github.com/yuanzicheng/spring-cloud-config-repository
          username:
          password:

3.2 Config Server文件映射

3.2.1 配置文件映射关系

Config Server启动以后,我们可以通过它暴露的端点获取配置文件内容,http请求地址与配置文件映射关系如下:

# 映射{application}-{profile}.properties文件
/{application}/{profile}/[{label}]
/{label}/{application}-{profile}.properties
/{application}-{profile}.properties
/{label}/{application}-{profile}.yml
/{application}-{profile}.yml

{application}通常使用微服务名称,对应Git仓库中文件名的前缀;
{profile}对应{application}-后面的dev、pro、test等;
{label}对应Git仓库的分支名,默认为master。

3.2.2 测试验证

访问http://localhost:8181/service1/defaulthttp://localhost:8181/service1/default/master,结果如下

{
    "name": "service1",
    "profiles": ["default"],
    "label": null,
    "version": "3b6835a7b87aa1f7c6830456ce85605a071bbdce",
    "state": null,
    "propertySources": [{
        "name": "https://github.com/yuanzicheng/spring-cloud-config-repository/service1.properties",
        "source": {
            "profile": "default-1.0"
        }
    }]
}

访问http://localhost:8181/service1/devhttp://localhost:8181/service1/dev/master,结果如下

{
  "name": "service1",
  "profiles": [
    "dev"
  ],
  "label": null,
  "version": "3b6835a7b87aa1f7c6830456ce85605a071bbdce",
  "state": null,
  "propertySources": [
    {
      "name": "https://github.com/yuanzicheng/spring-cloud-config-repository/service1-dev.properties",
      "source": {
        "profile": "dev-1.0"
      }
    },
    {
      "name": "https://github.com/yuanzicheng/spring-cloud-config-repository/service1.properties",
      "source": {
        "profile": "default-1.0"
      }
    }
  ]
}

访问http://localhost:8181/service1-dev.propertieshttp://localhost:8181/service1-dev.yml,结果如下

profile: dev-1.0

4.Config Client

Config Client是Config Server的客户端,用于操作存储在Config Server中的配置内容。

4.1 创建Config Client

4.1.1 创建一个Spring Boot项目config-client,添加依赖
dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.springframework.boot:spring-boot-starter-actuator')
    compile('org.springframework.cloud:spring-cloud-starter-config:1.4.1.RELEASE')
}
4.1.2 创建配置文件application.yml

通常情况下,Config Client作为微服务的一部分,微服务的spring.application.name属性值决定了Git仓库中配置文件的的文件名前缀,需要为哪个微服务提供配置文件,配置文件的文件名就需要以spring.application.name属性值作为前缀。

server:
  port: 8282
spring:
  application:
    name: service1 # 对应config-server获取的配置文件的{application}
4.1.3 创建配置文件bootstrap.yml

Spring Boot应用程序启动时加载application.yml/application.properties。Spring Cloud中有“引导上下文”的概念,引导上下文加载bootstrap.yml/bootstrap.properties,而且具有更高的优先级,默认情况下bootstrap.yml/bootstrap.properties中的属性不能被覆盖。

spring:
  application:
    name: service1 # 对应config-server获取的配置文件的{application}
  cloud:
    config:
      uri: http://localhost:8181 # 对应config-server地址,默认值http://localhost:8888
      profile: pro  # 对应config-server获取的配置文件的{profile}
      label: master # 对应config-server获取的配置文件的{label},即Git仓库分支
4.1.4 编写测试用的Controller
@RestController
public class ConfigController {

    @Value("${profile}")
    private String profile;

    @GetMapping("/profile")
    public String profile(){
        return this.profile;
    }

}

4.2 测试验证

依次启动config-server:8181和config-client:8282,访问http://localhost:8282/profile,返回如下结果

pro-1.0

Config Client能够正常通过Config Server获取Git仓库中指定环境的配置内容。

5.Git仓库配置

Config Server的application.yml配置文件中,通过spring.cloud.config.server.git.uri指定Git仓库地址,实际上该属性的配置方式非常灵活,支持多种方式。

5.1 占位符

{application}{profile}{label}等占位符可以用于映射配置文件,还可以用于Config Server中配置Git仓库地址。

5.1.1 使用{application}指定Git仓库地址

Step 1:在Config Server中用{application}占位符的形式指定Git仓库地址

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/yuanzicheng/{application}

Step 2:在Config Client中修改spring.application.name=spring-cloud-config-repository,因为建了一个Git仓库,这里简单起见,就不再创建新的Git仓库了。

spring:
  application:
    name: spring-cloud-config-repository

Step 3:在Git仓库中创建一个application-dev.yml的文件

profile: application-test

特别注意:用占位符的形式定义Git仓库地址时,配置文件的文件名必须为application*.ymlapplication*.properties

Step 4:依次启动Config Server和Config Client,访问http://localhost:8282/profile,结果如下

application-test
5.1.2 习惯用法{application}-xxx

假设创建了一个微服务service1,配置文件的Git仓库就可以指定为service1-xxx,

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/yuanzicheng/{application}-xxx

这样Config Server就可以支持多个Config Clienet。

5.2 模式匹配

可以通过应用程序和配置文件名称的模式匹配来支持更复杂的需求,但通常情况下不建议使用这种方式。
特殊场景如有需要可用参考Pattern Matching and Multiple Repositories

5.3 搜索目录

spring.cloud.config.server.git.search-paths属性可以指定除了根目录,额外需要加载配置文件的子目录。
如:加载根目录、dir目录、dir开头的目录下的配置文件。

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/yuanzicheng/spring-cloud-config-repository
          search-paths: dir,dir*  

5.4 clone-on-start

默认情况下,首次请求配置时,Config Server克隆Git仓库,也可以通过clone-on-start设置Config Server启动时是否克隆git仓库。

全局配置:

spring:
  application:
    name: config-server
  cloud:
    config:
      server:
        git:
          clone-on-start: true

指定仓库:

spring:
  cloud:
    config:
      server:
        git:
          repos:
            指定仓库:
              clone-on-start: true

5.5 日志输出

如果需要输出Config Server请求Git仓库的细节,可以设置以下包的日志级别为debug,这样通过日志跟踪可以理解Config Server的Git仓库配置,也方便定位问题。

logging:
  level:
    org.springframework.boot: debug
    org.springframework.cloud: debug

5.6 本地Git仓库

Config Server还支持从本地Git仓库读取配置,但建议仅在开发、测试环境下采用这种方式。

初始化本地Git仓库

$ cd ~ && mkdir local-repository
$ cd local-repository
$ git init .
$ echo "dev: local config" > service1.yml
$ git add .
$ git commit -m "first commit"

从本地文件系统的Git仓库读取配置文件(注意:windows环境下,使用file:///作为Git仓库路径前缀)

spring:
  cloud:
    config:
      server:
        git:
          uri: file://${user.home}/local-repository

6.Config Server健康状况

Config Server自带了健康状况指示器,暴露的endpoint为/health,用于检查配置的仓库是否可用。

对于文中的Config Server,请求http://localhost:8181/health返回如下结果

{
    "status": "UP"
}

7.配置加密

一些场景下,对于敏感信息(如:数据库账号、密码,某些服务分配的key等),需要加密处理。
Config Server支持配置内容的加密、解密,依赖于Java Cryptography Extension(JCE)。

8.刷新配置

Spring Clould Config支持不停止应用刷新配置。

8.1 手动刷新

修改Config Client项目来验证配置内容的手动刷新。
Step 1:添加依赖
其中spring-boot-starter-actuator依赖包含了/refresh端点,用于刷新配置

dependencies {
    compile('org.springframework.boot:spring-boot-starter-web')
    compile('org.springframework.boot:spring-boot-starter-actuator')
    compile('org.springframework.cloud:spring-cloud-starter-config:1.4.1.RELEASE')
}

Step 2:在使用配置内容的类上添加注解

@RefreshScope
@RestController
public class ConfigController {

    @Value("${profile}")
    private String profile;

    @GetMapping("/profile")
    public String profile(){
        return this.profile;
    }

}

Step 3:禁用spring security

management:
  security:
    enabled: false 

Step 4:修改application-dev.yml的内容为profile: application-dev,post方式请求http://localhost:8282/refresh,返回如下结果,表示配置刷新成功。

[
    "config.client.version",
    "profile"
]

Step 5:再次请求http://localhost:8282/profile,返回内容已经变成了application-dev

8.2 自动刷新

8.2.1 Spring Cloud Bus
8.2.2 Spring Cloud Bus自动刷新
8.2.3 局部刷新

9.Spring Cloud Config与Eureka整合

10.Spring Cloud Config用户认证

11.Config Server高可用

11.1 Git仓库高可用

11.2 RabbitMQ高可用

11.3 Config Server自身高可用

推荐阅读更多精彩内容