0%

SpringCloud(九)分布式配置管理Config

根据Martin Fowler对微服务架构的阐述中的诉求可以有一个非常轻量级的集中式管理来协调这些服务。分布式配置中心Spring Cloud Config应运而生了。

概述

分布式系统面临的配置问题

微服务意味着要将单体应用中的业务拆分成一个个子服务,每个服务的粒度相对较小,因此系统中会出现大量的服务.由于每个服务都需要必要的配置信息才能运行,所以一套集中式的、动态的配置管理设施是必不可的(想想成百上千微服务的 application.yml靠手工一个一个的修改和管理会怎样).Spring Cloud提供了Config Server来解决这个问题.

Spring Cloud Config

是什么

Spring Cloud Config 为微服务架构中的微服务提供集中化的外部配置支持,配置服务器为各个不同微服务应用的所有环境提供了一个中心化的外部配置.

Spring Cloud Config分为服务端和客户端两部分.

服务端也称为分布式配置中心,它是一个独立的微服务应用,用来连接配置服务器并为客户端提供获取配置信息、加密/解密信息等访问接口

客户端则是通过指定的配置中心来管理应用资源,以及业务相关的配置内容,并在启动的时候从配置中心获取和加载配置信息配置服务器默认采用git来存储配置信息,这样就有助于对环境配置进行版本管理,并且可以通过git客户端工具来方便的管理和访问配置内容.

如上图, Spring Cloud Config的用法就是,通过一个 Git Remote Repo (如 GitHub上的仓库,也可以是其它版本控制服务器)来存放应用系统所有微服务的配置文件,运维工程师通过其本地的 git版本库关联 Git Remote Repo实现对整个应用系统中的配置文件的管理。而微服务(如 App A、B、C)在启动的时候连接 Config Server,通过它来读取 Git Remote Repo中的配置文件。

能干什么

  • 集中管理配置文件
  • 不同环境不同配置,动态化的配置更新,分环境部署比如dev/test/prod/beta/release
  • 运行期间动态调整配置,不再需要在每个服务部署的机器上编写配置文件,服务会向配置中心统一拉取配置自己的信息
  • 当配置发生变动时,服务不需要重启即可感知到配置的变化并应用新的配置
  • 将配置信息以REST接口的形式暴露

与Git整合配置

由于Spring Cloud Config默认使用Git来存储配置文件(也有其他方式,比如支持SVN和本地文件),
但最推荐的还是使用Git,而且使用的是http/https访问形式


实战

环境准备

新建github仓库

新建 github repo,如 clouddemo-config,在创建成功页面复制 SSH协议的仓库地址

如图

新建本地git库关联github

现在你的身份是运维工程师,你需要将某个微服务的配置文件上传到 github上的 clouddemo-config。于是你先在电脑某处(F:/git_exercise)利用刚才复制的ssh协议地址将该版本库克隆到本地:

1
2
3
4
zaw@DESKTOP-KUBSPE0 MINGW64 /f/git_exercise
$ git clone git@github.com:zanwen/clouddemo-config.git
Cloning into 'clouddemo-config'...
warning: You appear to have cloned an empty repository.

于是你在 F:/git_exercise/clouddemo-config下新建了 application.yml注意:一定要以 UTF-8编码保存,否则后续微服务启动远程读取该配置文件时会报错):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#default
spring:
profiles:
active: dev
---
#dev
spring:
profiles: dev
application:
name: clouddemo-config-dev
---
#test
spring:
profiles: test
application:
name: clouddemo-config-test

其中通过 ---的写法将三种环境(defaultdevtest)下的配置信息定义到了一个配置文件中,相当于本来要写在 application.ymlapplication-dev.ymlapplication-test.yml中的多环境配置通过 ---分隔写在了一个文件中。关于 Spring Boot多环境配置,不熟悉的可参考往期文章:SpringBoot2.x(十五)多环境配置

接着提交到远程版本库(当然前提是你配置了 SSH秘钥,拥有操作该远程库的权限):

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
zaw@DESKTOP-KUBSPE0 MINGW64 /f/git_exercise/clouddemo-config (master)
$ git add .
warning: LF will be replaced by CRLF in application.yml.
The file will have its original line endings in your working directory.
zaw@DESKTOP-KUBSPE0 MINGW64 /f/git_exercise/clouddemo-config (master)
$ git commit -m "init yml"
[master (root-commit) 8d4a0c6] init yml
1 file changed, 14 insertions(+)
create mode 100644 application.yml
zaw@DESKTOP-KUBSPE0 MINGW64 /f/git_exercise/clouddemo-config (master)
$ git push origin master
Counting objects: 3, done.
Delta compression using up to 4 threads.
Compressing objects: 100% (2/2), done.
Writing objects: 100% (3/3), 356 bytes | 356.00 KiB/s, done.
Total 3 (delta 0), reused 0 (delta 0)
To github.com:zanwen/clouddemo-config.git
* [new branch] master -> master

搭建 Config Server

  1. 在原来 clouddemo父工程的基础之上新建子模块 clouddemo-config-server,添加 config-server依赖

    1
    2
    3
    4
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
    </dependency>
  2. 添加 config-server配置项(指定存放配置文件的远程版本库):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    server:
    port: 3344
    spring:
    application:
    name: clouddemo-config-server
    cloud:
    config:
    server:
    git:
    uri: git@github.com:zanwen/clouddemo-config.git
  3. 在启动类上添加 @EnableConfigServer

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    package top.zhenganwen.clouddemo.config;

    import org.springframework.boot.SpringApplication;
    import org.springframework.boot.autoconfigure.SpringBootApplication;
    import org.springframework.cloud.config.server.EnableConfigServer;

    @SpringBootApplication
    @EnableConfigServer
    public class ConfigServerApplication{

    public static void main(String[] args) {
    SpringApplication.run(ConfigServerApplication.class, args);
    }
    }
  4. 测试动态化配置更新

    1. 访问 localhost:3344/application-dev.yml(将会输出 dev部分的配置):

      1
      2
      3
      4
      5
      spring: 
      application:
      name: clouddemo-config-dev
      profiles:
      active: dev
    2. 访问 localhost:3344/application-test.yml(将会输出 test部分的配置):

      1
      2
      3
      4
      5
      spring: 
      application:
      name: clouddemo-config-test
      profiles:
      active: dev
    3. 访问 localhost:3344/application-abc.yml(访问不存在的 profile将会输出 default部分的配置)

      1
      2
      3
      spring: 
      profiles:
      active: dev

      其中 spring.profiles.active=devdefault中的部分,无论如何都会输出

    4. 你甚至能通过 localhost:3344/application/dev/masterlocalhost:3344/application/test/master访问到对应的配置部分

配置的读取规则

  • /{fileName}-{profile}.yml
  • /{fileName}/{profile}[/{label}],如 localhost:3344/application/dev/master,不指定 lable则默认从 master分支中读
  • /{label}/{fileName}-{profile}.yml

至此我们成功地通过 Config Server获取 Git Remote Repo中的配置信息,下面我们就要搭建客户端连接 Config Server获取配置信息


搭建 Config Client

工程搭建

这个 Config Client就可以是一个个的微服务,如我们之间搭建的eurekaproviderconsumer等。

为了不破坏之前的工程结构,我们新建一个使用了 Config Client的微服务clouddemo-config-client(配置文件从 Config Server拉取)

  1. 依赖(注意不是 config-server,而是 config,是客户端):

    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config</artifactId>
    </dependency>
    <!-- 假设这是一个要注册到eureka的服务提供者 -->
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-config</artifactId>
    </dependency>
    <dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-starter-eureka</artifactId>
    </dependency>
  2. 切换为运维工程师,将 clouddemo-config-client的远程配置文件 clouddemo-config-client.yml上传至 Git Remote Repo

    1. clouddemo-config-client.yml

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      21
      22
      23
      24
      25
      26
      27
      28
      29
      30
      31
      spring:
      profiles:
      active: dev
      ---
      #dev 开发环境
      server:
      port: 8001
      spring:
      profiles: dev
      application:
      name: clouddemo-config-dev
      eureka:
      instance:
      instance-id: clouddemo-config-8001
      client:
      serviceUrl:
      defaultZone: http://eureka-dev.com:7001/eureka/
      ---
      # prod 生产环境
      server:
      port: 8002
      spring:
      profiles: prod
      application:
      name: clouddemo-config-prod
      eureka:
      instance:
      instance-id: clouddemo-config-8002
      client:
      serviceUrl:
      defaultZone: http://eureka-prod.com:7001/eureka/
    2. pushgithub

      1
      2
      3
      4
      5
      6
      7
      8
      9
      10
      11
      12
      13
      14
      15
      16
      17
      18
      19
      20
      zaw@DESKTOP-KUBSPE0 MINGW64 /f/git_exercise/clouddemo-config (master)
      $ git add .
      warning: LF will be replaced by CRLF in clouddemo-config-client.yml.
      The file will have its original line endings in your working directory.

      zaw@DESKTOP-KUBSPE0 MINGW64 /f/git_exercise/clouddemo-config (master)
      $ git commit -m "config client yml"
      [master 69587c1] config client yml
      1 file changed, 31 insertions(+)
      create mode 100644 clouddemo-config-client.yml

      zaw@DESKTOP-KUBSPE0 MINGW64 /f/git_exercise/clouddemo-config (master)
      $ git push origin master
      Counting objects: 3, done.
      Delta compression using up to 4 threads.
      Compressing objects: 100% (3/3), done.
      Writing objects: 100% (3/3), 489 bytes | 244.00 KiB/s, done.
      Total 3 (delta 0), reused 0 (delta 0)
      To github.com:zanwen/clouddemo-config.git
      321b84e..69587c1 master -> master
  3. 切换为后端工程师,新建 bootstrap.yml

    1. 要连接的Config Server地址
    2. 指定分支
    3. 指定 profile
    4. 指定远程配置文件文件名,不要带扩展名
    1
    2
    3
    4
    5
    6
    7
    spring:
    cloud:
    config:
    name: clouddemo-config-client #远程配置文件的文件名,不带后缀
    profile: dev
    label: master
    uri: http://localhost:3344 #Config Server 地址

    Spring Cloud会创建一个"Bootstrap Context",作为Spring应用的"Application Context"的父上下文.初始化的时候,"Bootstrap Context"负责从外部源加载配置属性并解析配置.这两个上下文共享一个从外部获取的"Environment"."Bootstrap"属性有高优先级,默认情况下,它们不会被本地配置覆盖."Bootstrap Context""Application Context"有着不同的约定,
    所以新增了一个"Bootstrap.yml"文件,保证"Bootstrap Context""Application Context"配置的分离

  4. 还是要添加一个 application.yml作为应用的全局配置文件(内容可不写),Config Server只是负责返回读取的配置内容

    1
    2
    3
    spring:
    application:
    name: clouddemo-config-client

测试

测试 Config Server

访问 localhost:3344/clouddemo-config-client-dev.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
eureka: 
client:
serviceUrl:
defaultZone: http://eureka-dev.com:7001/eureka/
instance:
instance-id: clouddemo-config-8001
server:
port: 8001
spring:
application:
name: clouddemo-config-dev
profiles:
active: dev

访问 localhost:3344/clouddemo-config-client-prod.yml

1
2
3
4
5
6
7
8
9
10
11
12
13
eureka: 
client:
serviceUrl:
defaultZone: http://eureka-prod.com:7001/eureka/
instance:
instance-id: clouddemo-config-8002
server:
port: 8002
spring:
application:
name: clouddemo-config-prod
profiles:
active: dev

测试 Config Client

访问 localhost:8001/config

1
applictionName:clouddemo-config-dev eurekaServershttp://eureka-dev.com:7001/eureka/ port8001

修改 bootstrap.ymlspring.cloud.profile=prod,重启后访问 localhost:8002/config(注意端口变了)

1
applictionName:clouddemo-config-prod eurekaServershttp://eureka-prod.com:7001/eureka/ port8002

客户端总结

重点在 bootstrap.yml,其中定义了:

  1. 连接哪个 Config Server(从而决定了读取哪个 git repo
  2. 读取哪个分支上(spring.cloud.config.label)的哪个文件(spring.cloud.config.name)的哪个部分(spring.cloud.config.profile)的环境配置

如果运维向变更哪个配置中连接的数据库URL,只需在其本地git库中更改并提交推送,读取该配置的微服务再重启时就会连接变更后的数据库

鼓励一下~