# 环境库 / Environment Repository

将配置文件存储在哪里?是通过 EnvironmentRepository 策略决定的,它服务于 Environment 对象, 该对象来自 spring 中 Environment(包含 propertySources)的一个浅拷贝;Environment 中有三个参数

  • {application}, spring.application.name 的值
  • {profile}, 激活的 profile ,多个使用逗号分隔
  • {label}, 服务端特性,标识一组配置文件的版本

加载配置文件的时候与 spring 本地加载程序类似,如下配置:

spring:
  application:
    name: config-client
  profiles:
    active: dev,mysql
  cloud:
    config:
      uri: http://localhost:11000 # 指向刚才创建的配置中心项目
      profile: dev,mysql # 默认为 default  
1
2
3
4
5
6
7
8
9

在启动的时:

  • 仓库配置:

    会去获取 http://localhost:11000/config-client/dev,mysql 两个配置文件信息;

    但是还需要看仓库中是否有对应的,如果没有则不会有信息

  • 本地配置:

    会读取 application.yml 、 application-dev.yml 、application-mysql.yml

既然加载了多个配置文件,那么优先级则是自定义的高于默认配置,在 active 中的顺序决定了谁覆盖谁,后加载的则会覆盖前面相同名称的属性

spring.cloud.config.server.accept-empty 允许返回空;默认值为 true,在服务端配置; 本来你仓库中没有 mrcode-prod.yml(http://localhost:11000/mrcode/prod) 这个配置文件, 如果为 true,则不会报错,只是返回空的 propertySources;如果为 false 则直接 404 页面

{
  "name": "mrcode",
  "profiles": [
  "prod"
  ],
  "label": null,
  "version": "c0fe8977dd5935f84c991e1ff501df339f012d16",
  "state": null,
  "propertySources": []
}
1
2
3
4
5
6
7
8
9
10

# git 后端

EnvironmentRepository 的默认实现使用 Git 后端,这对于管理升级和物理环境以及审计更改非常方便。 要更改存储库的位置,可以设置 spring.cloud.config.server.git。

uri 可以使用 file: 为前缀可以指向本地的一个 git 仓库,但是,在这种情况下,服务器直接在本地存储库上操作, 而不进行克隆(如果它不是一个纯粹的本地仓库,也没有关系,因为配置服务器从不更改“远程”存储库)。

要扩展配置服务器并使其高度可用,您需要让服务器的所有实例指向同一个存储库,这样只有共享的文件系统才能工作。 即使在这种情况下,也最好使用 ssh: 协议来共享文件系统存储库,这样服务器就可以克隆它并使用本地工作副本作为缓存。

spring:
  cloud:
    config:
      server:
        git:
          uri: http://localhost/mrcode/config.git
          # username: xx
          # password: xx
          uri: file://f:/dir/config-repo
1
2
3
4
5
6
7
8
9

这个存储库实现将 HTTP 资源的 {label} 参数映射到 git 标签(commit id、 branch name 或者 tag)。 如果这些名称中(beanch name、tag)包含斜杠「/」,那么需要使用下划线「(_)」将其转义

比如要获取 tag 为 「ta/ge」 中的 mrcode-dev.yml,被转义之后的地址是 http://localhost:11000/mrcode-dev-ta(_)ge.json

如果使用 curl 类似的命令行工具需要使用单引号将括号转义 mrcode-dev-ta'('_')'ge.json

# 跳过 SSL 证书验证

通过配置 skipSslValidation = true 来跳过 ssl 证书验证,默认值为 false

spring:
  cloud:
    config:
      server:
        git:
          uri: https://example.com/my/repo
          skipSslValidation: true
1
2
3
4
5
6
7

# 设置 HTTP 连接超时

您可以配置配置中心等待获取 HTTP 连接的时间(以秒为单位)。这里的参数对于 SSH 配置也同样适用

spring:
  cloud:
    config:
      server:
        git:
          uri: https://example.com/my/repo
          timeout: 4
1
2
3
4
5
6
7

# git uri 中的只占位符

请查看如下配置

spring:
  cloud:
    config:
      server:
        git:
          uri: file:///f:/dir/config-repos/{application}
1
2
3
4
5
6

上面的配置对应物理目录如下

|- config-repos  # 普通文件夹
  |- mrcode  # git 本地仓库
    |- mrcode-dev.yml
1
2
3

我们要访问到 mrcode-dev.yml,需要使用地址 http://localhost:11000/mrcode-dev.json; 可以看到在访问上并没有什么不同,但是在 uri 中使用了占位符;

这意味着,你可以让一个服务一个仓库,占位符支持以下变量:

  • {application}
  • {profile}
  • {label}

# 模式匹配和多个 git 仓库

spring:
  cloud:
    config:
      server:
        git:
          uri: file:///H:/dir/config-repos/{application}
          repos:
            simple: file:///H:/dir/config-repo
            config:
              pattern: config*
              uri: file:///H:/dir/config-repo
            mrcode:
              pattern: mr*/dev*,mr*/simple*
              uri: file:///H:/dir/config-repos/{application}
1
2
3
4
5
6
7
8
9
10
11
12
13
14

上面使用通配符匹配,下图展示了匹配的结果

  • simple: http://localhost:11000/mrcode-simple.json

    匹配的是 profile 标签

  • pattern:

    http://localhost:11000/config-client-dev.json

    匹配的是整个文件名称,pattern 中的 「/」 匹配文件名中的「-」

注意

对于 simple 这样一行写完的只适合简单的,如果需要配置更多信息(凭证,pattern)则需要完整的表单方式(也就是类似 config、mrcode 那样)

每个存储库还可以选择将配置文件存储在子目录中,搜索这些目录的模式可以指定为 searchpath。

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          mrcode2:
            pattern: mrcode*
            uri: file:///H:/dir/config-repos/mrcode
            searchPaths: dir*,zirr
1
2
3
4
5
6
7
8
9
10

在这之前测试的都是在一个仓库的 「根目录」下放置配置文件,还可以分目录放置

如上图在两个目录下都有相同的配置文件,内容不太一样;这样的情况结果是什么呢?

访问 http://localhost:11000/mrcode-simple.json 输出

{
  "name": "xxx",
  "test": "config-repos/mrcode/zirr/mrcode-simple.yml"
}
1
2
3
4

可见,在遇到相同配置和相同属性的时候都是后面的同名属性会覆盖之前的,简单说就是文件可以被合并;

默认情况是在第一次请求配置文件时才会去克隆仓库,可以通过 cloneOnStart 配置,在项目启动时去克隆仓库

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
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18

上面配置 team-a 在项目启动时就去克隆仓库了,而其他配置则在首次请求时去克隆,克隆完成后才会返回结果

# Authentication 认证

如果使用 https 协议,支持用户名和密码进行认证

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          username: trolley
          password: strongpassword
1
2
3
4
5
6
7
8

如果不使用密码则会使用 shh 协议,需要在 ~/.ssh/config 中配置访问的仓库服务与要使用的公钥文件

Host github.com			   # git 服务的地址,访问该地址时,就使用下面的配置
Hostname github.com
Port 22					   # 端口,如果是私有 git 服务器,请注意这个端口号是否有更改
User git
IdentityFile ~/.ssh/xxx    # 私钥文件,不是 .pub 那个, pub 是公钥,需要在 git 服务端你的用户 ssh 中配置的
1
2
3
4
5

# 使用属性进行 Git SSH 配置

如果你在容器中部署项目的话,使用系统中的配置文件配置,可能不是很方便,这时候就可以使用属性配置

  spring:
    cloud:
      config:
        server:
          git:
            uri: git@gitserver.com:team/repo1.git
            ignoreLocalSshSettings: true   # 这个是前提,让他忽略本地的 ssh 配置
            hostKey: someHostKey
            hostKeyAlgorithm: ssh-rsa
            # 私钥文件内容,注意需要,内容是以前后的竖线包裹起来的
            privateKey: |
                         -----BEGIN RSA PRIVATE KEY-----
                         MIIEpgIBAAKCAQEAx4UbaDzY5xjW6hc9jwN0mX33XpTDVW9WqHp5AKaRbtAC3DqX
                         IXFMPgw3K45jxRb93f8tv9vL3rD9CUG1Gv4FM+o7ds7FRES5RTjv2RT/JVNJCoqF
                         ol8+ngLqRZCyBtQN7zYByWMRirPGoDUqdPYrj2yq+ObBBNhg5N+hOwKjjpzdj2Ud
                         1l7R+wxIqmJo1IYyy16xS8WsjyQuyC0lL456qkd5BDZ0Ag8j2X9H9D5220Ln7s9i
                         oezTipXipS7p7Jekf3Ywx6abJwOmB0rX79dV4qiNcGgzATnG1PkXxqt76VhcGa0W
                         DDVHEEYGbSQ6hIGSh0I7BQun0aLRZojfE3gqHQIDAQABAoIBAQCZmGrk8BK6tXCd
                         fY6yTiKxFzwb38IQP0ojIUWNrq0+9Xt+NsypviLHkXfXXCKKU4zUHeIGVRq5MN9b
                         BO56/RrcQHHOoJdUWuOV2qMqJvPUtC0CpGkD+valhfD75MxoXU7s3FK7yjxy3rsG
                         EmfA6tHV8/4a5umo5TqSd2YTm5B19AhRqiuUVI1wTB41DjULUGiMYrnYrhzQlVvj
                         5MjnKTlYu3V8PoYDfv1GmxPPh6vlpafXEeEYN8VB97e5x3DGHjZ5UrurAmTLTdO8
                         +AahyoKsIY612TkkQthJlt7FJAwnCGMgY6podzzvzICLFmmTXYiZ/28I4BX/mOSe
                         pZVnfRixAoGBAO6Uiwt40/PKs53mCEWngslSCsh9oGAaLTf/XdvMns5VmuyyAyKG
                         ti8Ol5wqBMi4GIUzjbgUvSUt+IowIrG3f5tN85wpjQ1UGVcpTnl5Qo9xaS1PFScQ
                         xrtWZ9eNj2TsIAMp/svJsyGG3OibxfnuAIpSXNQiJPwRlW3irzpGgVx/AoGBANYW
                         dnhshUcEHMJi3aXwR12OTDnaLoanVGLwLnkqLSYUZA7ZegpKq90UAuBdcEfgdpyi
                         PhKpeaeIiAaNnFo8m9aoTKr+7I6/uMTlwrVnfrsVTZv3orxjwQV20YIBCVRKD1uX
                         VhE0ozPZxwwKSPAFocpyWpGHGreGF1AIYBE9UBtjAoGBAI8bfPgJpyFyMiGBjO6z
                         FwlJc/xlFqDusrcHL7abW5qq0L4v3R+FrJw3ZYufzLTVcKfdj6GelwJJO+8wBm+R
                         gTKYJItEhT48duLIfTDyIpHGVm9+I1MGhh5zKuCqIhxIYr9jHloBB7kRm0rPvYY4
                         VAykcNgyDvtAVODP+4m6JvhjAoGBALbtTqErKN47V0+JJpapLnF0KxGrqeGIjIRV
                         cYA6V4WYGr7NeIfesecfOC356PyhgPfpcVyEztwlvwTKb3RzIT1TZN8fH4YBr6Ee
                         KTbTjefRFhVUjQqnucAvfGi29f+9oE3Ei9f7wA+H35ocF6JvTYUsHNMIO/3gZ38N
                         CPjyCMa9AoGBAMhsITNe3QcbsXAbdUR00dDsIFVROzyFJ2m40i4KCRM35bC/BIBs
                         q0TY3we+ERB40U8Z2BvU61QuwaunJ2+uGadHo58VSVdggqAo0BSkH58innKKt96J
                         69pcVH/4rmLbXdcmNYGm6iu+MlPQk4BUZknHSmVHIFdJ0EPupVaQ8RHT
                         -----END RSA PRIVATE KEY-----
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
32
33
34
35
36
37
38

属性说明:

Property Name Remarks
ignoreLocalSshSettings 如果为 true,使用基于属性的 SSH 配置,而不是基于文件的 SSH 配置。
privateKey 有效的 SSH 私钥。如果 ignoreLocalSshSettings 为 true 且 Git URI 为 SSH 格式,则必须设置。
hostKey 有效的SSH主机密钥。如果 hostKeyAlgorithm 也被设置,则必须设置。
hostKeyAlgorithm ssh-dss, ssh-rsa, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, or ecdsa-sha2-nistp521 中的一个,如果 hostKey 也被设置,则必须被设置。
strictHostKeyChecking true or false. 如果为 false,则忽略主机密钥的错误。
knownHostsFile 自定义.known_hosts 文件位置.
preferredAuthentications 覆盖服务器认证方法的顺序。如果服务器在 publickey 方法之前使用了键盘交互式认证,这将允许规避登录提示。

# 占位符在 git.searchPaths 中

# 强行 pull git 存储库

Spring Cloud Config Server 会在本地使用 clone 下来的仓库进行提供服务,有时候可能导致本地仓库变脏(例如,OS 进程更改文件夹内容), 从而导致无法从远处仓库更新本地副本

可以通过 force-pull 属性,强制更新;默认值为 false

spring:
   cloud:
     config:
       server:
         git:
           uri: https://github.com/spring-cloud-samples/config-repo
           force-pull: true
1
2
3
4
5
6
7

# Git 刷新率

spring.cloud.config.server.git.refreshRate 属性控制服务从后端刷新频率,以秒为单位; 默认值为 0 ,意味着每次请求时从 git 仓库进行更新

# 版本控制后端文件系统

使用基于 vcs 的后端(git,svn),文件将被 checkout 或 clone 到本地文件系统上。

默认情况放在系统临时目录中,前缀为 config-reop-. 例如在 linux 上它可能是 /tmp/config-repo-<randomid>, 但是某些操作系统会 定期清理 临时目录,这就可能导致意外行为发生,例如缺少文件,要避免此问题,可以通过以下配置更改目录

spring.cloud.config.server.git.basedir

或

spring.cloud.config.server.svn.basedir
1
2
3
4
5

# 文件系统后端

config server 中还有一个「本机」配置文件,它不适用 Git,但从本地类路径或文件系统(任何静态 URL)加载配置文件。

spring:
  profiles:
    active: native
  cloud:
    config:
      server:
        native:
          search-locations:
            - file:///F:/dir/config-repos/mrcode/dirr
            - file:///F:/dir/config-repos/mrcode/zirr
1
2
3
4
5
6
7
8
9
10
  • 要使用 native,必须包含 spring.profiles.active=native

  • search-locations 支持的类型:

    • 文件路径:file:// windows 需要使用 file:///

    • 类路径:cn.mrcode.config 如果没有 file: 前缀,则认为是类路径

      搜索顺序与 Spring Boot 一致(即[classpath:/, classpath:/config, file:./, file:./config])

      这不会将 config server 的 application.properties 内容暴露出去;发送给 client 前会被删除

文件系统后端非常适合快速入门和测试。要在生产中使用它,您需要确保文件系统可靠并在 Config Server 的所有实例之间共享。

searchLocations 与前面的类似可以使用占位符 {application}{profile}{label}; 但是对于 label 是怎么处理的,我没有看懂,也没有测试到有效的访问方式

# 与所有应用程序共享配置

这里讲解基于文件的存储库(git、svn、native),以 application* 开头的将被所有客户端共享

  • application.properties
  • application.yml
  • application-*.properties

和 spring boot 程序中的配置文件类似,可以覆盖同名属性

注意

使用 native 的时候,需要把 config server 自己本身的 application* 文件排除(不要搜索这些位置), 否则 application* 所有属性将被删除后发送给客户端

# JDBC 后端

Spring Cloud Config Server 支持 JDBC(关系数据库)作为配置属性的后端。您可以通过向类路径添加 spring-jdbc 并使用 jdbc 配置文件或添加 JdbcEnvironmentRepository 类型的 bean 来启用该特性。如果您在类路径上包含了正确的依赖项(有关详细信息,请参阅用户指南),Spring Boot 将配置一个数据源。

数据库中需要有一张 PROPERTIES 表,有如下列:

  • APPLICATION
  • PROFILE
  • LABEL
  • KEY
  • VALUE

前三个属性与 {application}-{profile}-{label}.properties 含义相同; 后两个与 properties 中的含义相同,也就是说在数据库中就只能一行一个配置属性这种方式

# 同时指出多种类型的仓库(混合 Composite )

如想同时在 git 和 svn 仓库中获取配置文件

spring:
  profiles:
    active: composite
  cloud:
    config:
      server:
        composite:
        -
          type: svn
          uri: file:///path/to/svn/repo
        -
          type: git
          uri: file:///path/to/rex/git/repo
        -
          type: git
          uri: file:///path/to/walter/git/repo
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16

不深入了

# 属性覆盖(Property Overrides)

在 config server 中有以下配置

spring:
  cloud:
    config:
      server:
        overrides:  # 声明要覆盖客户端的配置
          foo: bar
1
2
3
4
5
6

以上配置,会让所有客户端读取 foo 的时候获取到 bar 值;

# 关于让客户端自己覆盖 overides 的值得问题

经过测试 override-none 属性貌似没有什么效果,测试了好几个小时都没有看到客户端能覆盖这里的属性,

@Autowired
private Environment environment;

org.springframework.core.env.PropertySourcesPropertyResolver = debug

通过获取 environment 对象和日志打印,也没有获取到什么有用的信息,比较复杂感觉;
1
2
3
4
5
6

目前唯一能确定的是,只要在 overrides 中声明了属性,客户端在使用的时候,同名属性都以这里的值为准;

原文下面这一句话,我尝试了通过启动面板 Override parameters 和 System.setProperty("foo", "sysxxx"); 也没有改变 foo 的值

You can change the priority of all overrides in the client to be more like default values, letting applications supply their own values in environment variables or System properties, by setting the spring.cloud.config.overrideNone=true flag (the default is false) in the remote repository.

# 客户端覆盖远程配置文件属性

spring:
  cloud:
    config:
      # 远程文件属于外部配置,优先级高于具体的程序内部配置参数,
      allow-override: true  # false:阻止客户端覆盖远程配置文件属性
      override-none: true #  true: 让远程文件具有最低的优先级,不应该覆盖本地数据源
      override-system-properties: false # true: 外部属性应该覆盖系统属性
1
2
3
4
5
6
7

这段配置需要放到远程仓库的配置文件中。

使用场景是:当你本地有属性需要覆盖存在远程仓库配置文件中的属性时,使用它