Spring Cloud Config配置详解(一)

spring boot版本为:2.5.6
spring cloud版本为:2020.0.4


前言

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

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

Config Client是Config Server的客户端,用于操作存储在Config Server中的配置属性。引入Spring Cloud Config后的架构如下:

架构图

config server快速入门

准备配置文件

在git仓库https://gitee.com/lvyq987329931/config-server.git中新建几个配置文件,例如:

ms-foo.properties
ms-foo-dev.properties
ms-foo-test.properties
ms-foo-prod.properties

内容分别是:

profile=default
profile=dev
profile=test
profile=prod

添加依赖

<dependency>
    <groupId>org.springframework.cloud</groupId>
    <artifactId>spring-cloud-config-server</artifactId>
</dependency>

编写启动类,添加@EnableConfigServer注解

@SpringBootApplication
@EnableConfigServer
public class ConfigServerApplication {

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

}

编写配置文件application.yml

server:
  port: 8080

spring:
  application:
    name: ms-config-server
  
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/lvyq987329931/config-server.git
          username: git用户名
          password: git密码

这样一个config server就完成了

路径规则

Spring Cloud Config Server提供了RESTful API,可用来访问存放在Git仓库中的配置文件。

/{application}/{profile}[/{label}]
/{application}-{profile}.yml
/{label}/{application}-{profile}.yml
/{application}-{profile}.properties
/{label}/{application}-{profile}.properties

其中的{appliation}、{profile}、{label} 都是占位符。
{appliation}:映射客户端的spring.application.name属性
{profile}:映射客户端的spring.profiles.active属性
{label}:默认映射master分支

按照以上规则,对于本例,可以使用以下url访问到git仓库master分支的ms-foo-dev.properties文件,例如:

http://ocalhost:8080/ms-foo/dev
http://ocalhost:8080/ms-foo-dev.properties
http://ocalhost:8080/master/ms-foo-dev.properties

Spring Cloud Config Server配置详解

git作为后端配置存储

跳过SSL证书验证

禁用配置服务器对Git服务器SSL证书的验证

spring:
  cloud:
    config:
      server:
        git:
          uri: https://gitee.com/lvyq987329931/config-server.git
          username: git用户名
          password: git密码
          # 默认为false
          skip-ssl-validation: true

设置HTTP连接超时

spring:
  cloud:
    config:
      server:
        git:
          uri: https://example.com/my/repo
          # 默认5秒
          timeout: 4

占位符

Spring Cloud Config Server支持git存储库URL带有{application}和{profile}(如果需要的话还有{label})占位符,但是请记住该标签始终用作git标签。

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

使用这种方式,即可轻松支持一个应用对应一个Git仓库。同理,也可支持一个profile对应一个Git仓库。

此外,在{application}参数中使用特殊字符串“(_)”可以启用对多个组织的支持,如以下示例所示:

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

其中在请求时以以下格式提供{application}:organization(_)application。

模式匹配和多存储库

Spring Cloud Config还支持对应用名称和配置文件名称进行模式匹配,来应对更复杂的需求。模式匹配是一个以逗号分隔的带有通配符的{application}/{profile}名称列表(注意,以通配符开头的模式可能需要用引号括起来):

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          repos:
            simple: https://github.com/simple/config-repo
            special:
              pattern: special*/dev*,*special*/dev*
              uri: https://github.com/special/config-repo
            local:
              pattern: local*
              uri: file:/home/configsvc/config-repo

如果{application}/{profile}不匹配任何模式,它将使用spring.cloud.config.server.git.uri下定义的默认URI。在上面的示例中,对于“simple”存储库,模式是simple/*(它只匹配所有配置文件中名为simple的应用程序)。“local”存储库匹配所有配置文件中以local开头的应用名称
(/*后缀会自动添加到没有配置文件匹配器的任何模式中)。

例如:请求的地址为http://localhost:8080/simple/dev,将匹配simple库

上例中的pattern属性实际上是一个数组,因此您可以使用YAML数组(或属性文件中的[0],[1]等后缀)绑定到多个模式。如果要运行具有多个配置文件的应用程序,则可能需要这样做,如以下示例所示:

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-paths指定,search-path同样支持占位符。

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          search-paths:
            - foo
            - bar*

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

默认情况下,在配置被首次请求时,Config Server才会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: https://git/team-a/config-repo.git
            team-b:
                pattern: team-b-*
                cloneOnStart: false
                uri: https://git/team-b/config-repo.git
            team-c:
                pattern: team-c-*
                uri: https://git/team-a/config-repo.git

在上面的示例中,服务器在启动时并且在接受任何请求之前克隆team-a的config-repo。在请求其它配置之前,不会克隆存储库

设置在Config Server启动时克隆存储库有助于在Config Server启动时快速识别配置错误的配置源(例如无效的存储库URI)。在没有为配置源启用cloneOnStart的情况下,Config Server可能会以配置错误或无效的配置源成功启动,并且直到应用程序从该配置源请求配置时才检测到错误。

强制拉取Git Repositories

如前所述,Spring Cloud Config服务器会复制远程git存储库,以防本地副本变脏(例如,操作系统进程更改了文件夹内容),使得Spring Cloud Config服务器无法从远程更新本地副本。

要解决此问题,有一个force-pull属性,如果本地副本脏了,则可以使Spring Cloud Config服务器强制从远程存储库强制拉取配置,如以下示例所示:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          force-pull: true

如果有多个存储库配置,则可以为每个存储库配置force-pull属性,如以下示例所示:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://git/common/config-repo.git
          force-pull: true
          repos:
            team-a:
                pattern: team-a-*
                uri: https://git/team-a/config-repo.git
                force-pull: true
            team-b:
                pattern: team-b-*
                uri: https://git/team-b/config-repo.git
                force-pull: true
            team-c:
                pattern: team-c-*
                uri: https://git/team-a/config-repo.git

force-pull属性的默认值为false。

删除Git Repositories中未跟踪的分支

由于Spring Cloud Config Server在本地有一个从远程git存储库克隆的分支副本,因此它将永久保留该分支,直到下一个服务器重新启动(这将创建新的本地存储库)。因此,可能会出现这样的情况:远程分支已被删除,但它的本地副本仍可用于获取。而且,如果Spring Cloud Config Server Client服务以--spring.cloud.config.label=deletedRemoteBranch,master开头,它将从deletedRemoteBranch本地分支获取属性,而不是从master获取属性。

为了保持本地存储库分支的干净并与远程保持一致,可以设置deleteUntrackedBranches属性。它将使Spring Cloud Config Server强制从本地存储库删除未跟踪的分支。例子:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          deleteUntrackedBranches: true

deleteUntrackedBranches属性的默认值为false。

Git刷新率

您可以使用spring.cloud.config.server.git.refreshRate控制config server多久从Git获取更新的配置数据。以秒为单位指定此属性的值。默认情况下,该值为0,这意味着config server将在每次请求时从Git存储库中获取更新的配置。

以版本控制系统作为文件系统的使用

使用基于VCS的后端存储库(git,svn),文件被检出或克隆到本地文件系统。默认情况下,它们以config-repo-为前缀放在系统临时目录中。例如,在Linux上,它可能是/tmp/config-repo-<randomid>。一些操作系统通常会清除临时目录。这可能导致意外行为,例如缺少属性。为避免此问题,请通过将spring.cloud.config.server.git.basedirspring.cloud.config.server.svn.basedir设置来更改本地文件存储目录

本地文件系统作为存储库

Config Server中还有一个“native”配置文件,该配置文件不使用Git,而是从本地类路径或文件系统(您要使用spring.cloud.config.server.native.searchLocations指向的任何静态URL)加载配置文件。要使用本地配置文件,请使用spring.profiles.active=native启动Config Server。

记住对本地文件资源使用file:前缀(没有前缀的默认情况通常是类路径)。与任何Spring Boot配置一样,您可以嵌入${}风格的环境占位符,但请记住,Windows中的绝对路径需要额外的/(例如,file:///${user.home}/config-repo)。

searchLocations的默认值与Spring Boot应用程序(即[classpath:/, classpath:/config, file:./, file:./config])相同。这不会将application.properties从服务器发送到所有客户端,因为服务器中存在的任何属性源在发送到客户端之前都会被删除。

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

搜索位置可以包含{application}、{profile}和{label}的占位符。通过这种方式,您可以隔离路径中的目录,并选择对您有意义的策略(例如每个application的子目录或每个profile文件的子目录)。

如果在searchLocations不使用占位符,默认情况下会自动在搜索路径后面追加{label}。例如,file:/tmp/config与file:/tmp/config/{label}相同。可以通过设置spring.cloud.config.server.native.addLabelLocations=false来禁用此行为。

经过测试:路径名必须以/结尾,例如:file:/tmp/config/

使用jdbc作为后端存储库

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

您可以通过将spring.cloud.config.server.jdbc.enabled属性设置为false来禁用jdbcenvirmentrepository的自动配置。

数据库需要有一个名为PROPERTIES的表,该表具有名为APPLICATION,PROFILE和LABEL的列,以及KEY和VALUE。Java中所有字段的类型均为String,因此您可以根据需要将它们设置为VARCHAR。Property值的行为与来自名为{application}-{profile}.properties的Spring Boot属性文件的值的行为相同,加解密相关配置,不在数据库中存储。

redis作为后端存储库

Spring Cloud Config Server支持Redis作为配置属性的后端。你可以通过在Spring Data Redis中添加一个依赖项来启用这个特性。

<dependencies>
    <dependency>
        <groupId>org.springframework.boot</groupId>
        <artifactId>spring-boot-starter-data-redis</artifactId>
    </dependency>
</dependencies>

下面的配置使用Spring Data RedisTemplate来访问Redis。我们可以用spring.redis.*属性覆盖默认的连接设置。

spring:
  profiles:
    active: redis
  redis:
    host: redis
    port: 16379

属性应该存储为散列中的字段。hash的名称应该与spring.application.name属性或spring.application.name和spring.profiles.active[n]的组合相同。

HMSET sample-app server.port "8100" sample.topic.name "test" test.property1 "property1"

sample-app等于应用名,当没有指定profile时,将使用default值。

运行命令可以看到上面的哈希应该包含以下键值:

HGETALL sample-app
{
  "server.port": "8100",
  "sample.topic.name": "test",
  "test.property1": "property1"
}

组合多环境存储库

在某些场景中,您可能希望从多个环境存储库提取配置数据。为此,您可以在config server的application.properties或application.yml文件中启用composite 配置文件。例如,如果你想从Subversion存储库和两个Git存储库提取配置数据,你可以为你的配置服务器设置以下属性:

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

使用此配置,优先级由composite键下列出的存储库的顺序决定。在上面的示例中,Subversion存储库首先列出,因此在Subversion存储库中相同属性的值将覆盖Git存储库中的值。在rex Git存储库中相同属性的值将覆盖walter Git存储库中的值。

如果只希望从不同类型的存储库提取配置数据,可以在config server的appilication的properties或YAML文件中启用相应的配置,而不是composite配置。例如,如果您想从单个Git存储库和单个HashiCorp Vault服务器提取配置数据,您可以为您的配置服务器设置以下属性:

spring:
  profiles:
    active: git, vault
  cloud:
    config:
      server:
        git:
          uri: file:///path/to/git/repo
          order: 2
        vault:
          host: 127.0.0.1
          port: 8200
          order: 1

使用此配置,优先级可以由order属性确定。可以使用order属性指定所有存储库的优先级顺序。order属性的数值越低,其优先级越高。存储库的优先级顺序有助于解决包含相同属性的存储库之间的任何潜在冲突

如果您的组合环境包括上一个示例中的Vault服务器,则在对配置服务器的每个请求中都必须包含Vault令牌。请参阅Vault后端。

当从Environment Repositories检索值时,任何类型的失败都会导致整个组合环境的失败。如果您希望即使在存储库失败时仍然继续该组合,您可以将spring.cloud.config.server.failOnCompositeError设置为false

在使用组合环境时,重要的是所有存储库都包含相同的labels。如果您有与前面示例中类似的环境,并且请求带有master标签的配置数据时,但Subversion存储库不包含名为master的分支,那么整个请求将失败。

定制组合environment repositories

除了使用Spring Cloud中提供的一个environment repositories之外,您还可以提供自己的EnvironmentRepository bean作为composite environment的一部分。为此,您的bean必须实现EnvironmentRepository接口。如果要在composite environment中控制自定义EnvironmentRepository的优先级,则还应该实现Ordered接口并覆盖getOrdered方法。如果未实现Ordered接口,则EnvironmentRepository的优先级最低。

属性覆盖

config server有一个“overrides”特性,允许操作人员为所有应用程序提供配置属性。常规的Spring Boot应用程序不能更改被覆盖的属性。要声明覆盖,请将名称-值对的映射添加到spring.cloud.config.server.overrides,如下面的示例所示:

spring:
  cloud:
    config:
      server:
        overrides:
          foo: bar

上面的例子导致所有config客户端的应用程序读取foo=bar,独立于它们自己的配置。

配置系统不应该提供属性覆盖。但是,它们确实为Spring Cloud Config客户端提供了有用的默认行为。

通常使用${}的Spring环境占位符可以使用反斜杠(“\”)来转义(并在客户端上解析)来转义“$”或“{”,例如\${app.foo:bar}解析为“bar “除非该应用程序提供自己的”app.foo“

这句话怎么理解呢?比如上面的foo属性,可以以这种方式表达foo: ${app.foo:bar},在客户端没有提供app.foo属性时,默认为bar。如果客户端在配置文件中提供了这个属性,需要配合下面的overrideNone=true属性,并在环境变量或系统属性中提供:--foo=${app.foo}

在YAML中,不需要转义反斜杠本身。但是,在属性文件中,当您在服务器上配置覆盖时,确实需要转义反斜杠

config client想要更改这种默认行为,可以通过在远程配置文件中设置spring.cloud.config.overrideNone=true(默认为false),然后在客户端环境变量或系统属性中提供自己的值:例如:--foo=baz

健康指标

config server附带一个运行状况指标,用于检查配置的环境存储库是否正常工作。默认情况下,它向EnvironmentRepository请求application=app、profile=default和EnvironmentRepository实现提供的默认标签。

您可以配置运行状况指标以检查更多应用程序以及自定义配置文件和自定义标签,如下面的示例所示:

spring:
  cloud:
    config:
      server:
        health:
          repositories:
            myservice:
              label: mylabel
            myservice-dev:
              name: myservice
              profiles: development

可以通过设置spring.cloud.config.server.health.enabled=false禁用运行状况指标。

最新版的官方文档中指示通过management.health.config.enabled=false来禁用健康指标,但是经测试,并不好使。

默认情况下请求/actuator/health端点,只返回status字段,如需更多详细信息需配置management.endpoint.health.show-details=always

安全性

您可以以任何对您有意义的方式保护配置服务器(从物理网络安全到OAuth2承载令牌),Spring security和Spring Boot提供了许多安全方面的支持。

要使用缺省的Spring boot配置的HTTP Basic安全性,请在类路径上包括Spring security(例如,通过Spring boot-starter-security)。默认的用户名为user和随机生成的密码。随机密码在实践中并不实用,所以我们建议您配置密码(通过设置spring.security.user.password)并加密它(参见下面的说明如何做到这一点)。

<dependency>
    <groupId>org.springframework.boot</groupId>
    <artifactId>spring-boot-starter-security</artifactId>
</dependency>
spring:
  security:
    user:
      name: user
      password: 111

此时访问config server,就会看到如下的登录页面:

登录

欢迎关注我的公众号:程序员L札记

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 212,332评论 6 493
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 90,508评论 3 385
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 157,812评论 0 348
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 56,607评论 1 284
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 65,728评论 6 386
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 49,919评论 1 290
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 39,071评论 3 410
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 37,802评论 0 268
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 44,256评论 1 303
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 36,576评论 2 327
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 38,712评论 1 341
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 34,389评论 4 332
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 40,032评论 3 316
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 30,798评论 0 21
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,026评论 1 266
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 46,473评论 2 360
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 43,606评论 2 350

推荐阅读更多精彩内容