Spring Cloud Config是一个分布式配置管理系统,它提供了一个中心化的配置服务器来管理应用程序的配置信息。它允许开发人员将应用程序的配置信息存储在一个集中的位置,并将这些配置信息分发给多个应用程序实例。Spring Cloud Config支持多种后端存储,包括Git、SVN、本地文件系统等。它还提供了一组REST API,可以用于动态获取配置信息,以便应用程序能够及时更新自己的配置。通过使用Spring Cloud Config,开发人员可以轻松地管理和更新应用程序的配置信息,从而提高应用程序的可维护性和可扩展性。

4.0.4-SNAPSHOT

本站(springdoc.cn)中的内容来源于 spring.io ,原始版权归属于 spring.io。由 springdoc.cn 进行翻译,整理。可供个人学习、研究,未经许可,不得进行任何转载、商用或与之相关的行为。 商标声明:Spring 是 Pivotal Software, Inc. 在美国以及其他国家的商标。

Spring Cloud Config为分布式系统中的外部化配置提供服务器端和客户端支持。有了配置服务器,你就有了一个集中的地方来管理所有环境中的应用程序的外部属性。客户端和服务器上的概念与Spring EnvironmentPropertySource 抽象完全一致,因此它们非常适用于Spring应用程序,但也可用于以任何语言运行的任何应用程序。当应用程序通过部署流水线(deployment pipeline)从开发到测试再到生产时,你可以管理这些环境之间的配置,并确保应用程序在迁移时拥有它们需要的一切。服务器存储后端的默认实现使用git,所以它很容易支持配置环境的标记版本,并可被用于管理内容的广泛工具。很容易添加其他的实现,并将它们与Spring配置连接起来。

快速入门

本快速入门指南介绍了Spring Cloud Config Server 的服务器和客户端的使用情况。

首先,启动服务器,如下所示:

$ cd spring-cloud-config-server
$ ../mvnw spring-boot:run

该服务器是一个Spring Boot应用程序,所以如果你愿意,可以从你的IDE中运行它(main class 是 ConfigServerApplication)。

接下来尝试一个客户端,如下所示:

$ curl localhost:8888/foo/development
{
  "name": "foo",
  "profiles": [
    "development"
  ]
  ....
  "propertySources": [
    {
      "name": "https://github.com/spring-cloud-samples/config-repo/foo-development.properties",
      "source": {
        "bar": "spam",
        "foo": "from foo development"
      }
    },
    {
      "name": "https://github.com/spring-cloud-samples/config-repo/foo.properties",
      "source": {
        "foo": "from foo props",
        "democonfigclient.message": "hello spring io"
      }
    },
    ....

定位属性源的默认策略是克隆一个 git 仓库(在 spring.cloud.config.server.git.uri)并使用它来初始化一个迷你 SpringApplication。迷你应用程序的 Environment 被用来列举属性源,并在一个JSON端点发布它们。

HTTP服务有以下形式的资源:

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

例如:

curl localhost:8888/foo/development
curl localhost:8888/foo/development/master
curl localhost:8888/foo/development,db/master
curl localhost:8888/foo-development.yml
curl localhost:8888/foo-db.properties
curl localhost:8888/master/foo-db.properties

其中,application 是作为 SpringApplication 中的 spring.config.name 注入的(通常是普通 Spring Boot 应用中的 application),profile 是一个 active profile(或逗号分隔的属性列表),label 是一个可选的git标签(默认为 master。)

Spring Cloud Config Server从各种源为远程客户端拉取配置。下面的例子从一个git仓库(必须提供)获取配置,如下图所示:

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

其他源是任何JDBC兼容的数据库、Subversion、Hashicorp Vault、Credhub和本地文件系统。

客户端的使用

要在应用程序中使用这些功能,你可以将其构建为依赖 spring-cloud-config-client 的Spring Boot应用程序(有关示例,请参见 config-client 的测试案例或示例应用程序)。添加依赖关系的最便捷方式是使用 Spring Boot Starter org.springframework.cloud:spring-cloud-starter-config。对于Maven用户,还有一个父级pom和BOM(spring-cloud-starter-parent),对于Gradle和Spring CLI用户,还有一个Spring IO版本管理属性文件。下面的例子展示了一个典型的Maven配置:

pom.xml
   <parent>
       <groupId>org.springframework.boot</groupId>
       <artifactId>spring-boot-starter-parent</artifactId>
       <version>{spring-boot-docs-version}</version>
       <relativePath /> <!-- lookup parent from repository -->
   </parent>

<dependencyManagement>
	<dependencies>
		<dependency>
			<groupId>org.springframework.cloud</groupId>
			<artifactId>spring-cloud-dependencies</artifactId>
			<version>{spring-cloud-version}</version>
			<type>pom</type>
			<scope>import</scope>
		</dependency>
	</dependencies>
</dependencyManagement>

<dependencies>
	<dependency>
		<groupId>org.springframework.cloud</groupId>
		<artifactId>spring-cloud-starter-config</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.boot</groupId>
		<artifactId>spring-boot-starter-test</artifactId>
		<scope>test</scope>
	</dependency>
</dependencies>

<build>
	<plugins>
           <plugin>
               <groupId>org.springframework.boot</groupId>
               <artifactId>spring-boot-maven-plugin</artifactId>
           </plugin>
	</plugins>
</build>

   <!-- repositories also needed for snapshots and milestones -->

现在你可以创建一个标准的Spring Boot应用程序,例如下面的HTTP服务器:

@SpringBootApplication
@RestController
public class Application {

    @RequestMapping("/")
    public String home() {
        return "Hello World!";
    }

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

}

当这个HTTP服务器运行时,它从 8888 端口的默认本地配置服务器(如果它正在运行)上获取外部配置。要修改启动行为,你可以通过使用 application.properties 来改变配置服务器的位置,如下例所示:

spring.config.import=optional:configserver:http://myconfigserver.com

默认情况下,如果没有设置 application name,将使用 application。要修改这个名字,可以在 application.properties 文件中添加以下属性:

spring.application.name: myapp
当设置属性 ${spring.application.name} 时,不要在你的应用程序名称前加上保留词 application-,以防止在解析正确的属性源时出现问题。

Config Server properties 在 /env 端点中显示为高优先级的属性源,如下例所示。

$ curl localhost:8080/env
{
  "activeProfiles": [],
  {
    "name": "servletContextInitParams",
    "properties": {}
  },
  {
    "name": "configserver:https://github.com/spring-cloud-samples/config-repo/foo.properties",
    "properties": {
      "foo": {
        "value": "bar",
        "origin": "Config Server https://github.com/spring-cloud-samples/config-repo/foo.properties:2:12"
      }
    }
  },
  ...
}

一个名为 configserver:<远程资源库的URL>/<文件名> 的属性源包含 foo 属性,值为 bar

属性源名称中的URL是git仓库,而不是配置服务器的URL。
如果你使用 Spring Cloud Config Client,你需要设置 spring.config.import 属性,以便与 Config Server 绑定。你可以在 《Spring Cloud Config参考指南》 中阅读更多相关内容。

Spring Cloud Config 服务器

Spring Cloud Config Server 为外部配置(name-value 对或同等的YAML内容)提供了基于HTTP资源的API。通过使用 @EnableConfigServer 注解,该服务器可以嵌入到Spring Boot应用程序中。因此,下面的应用程序就是一个配置服务器:

ConfigServer.java
@SpringBootApplication
@EnableConfigServer
public class ConfigServer {
  public static void main(String[] args) {
    SpringApplication.run(ConfigServer.class, args);
  }
}

像所有的Spring Boot应用程序一样,它默认运行在8080端口,但你可以通过各种方式将其切换到更传统的8888端口。最简单的是用 spring.config.name=configserver(Config Server jar 中有 configserver.yml)启动它,这也是设置一个默认的配置仓库。另一种方法是使用你自己的 application.properties,如下面的例子所示:

application.properties
server.port: 8888
spring.cloud.config.server.git.uri: file://${user.home}/config-repo

其中 ${user.home}/config-repo 是一个包含 YAML 和 properties 文件的 git 仓库。

在Windows上,如果文件URL是绝对路径的,带有驱动器前缀(例如,file:///${user.home}/config-repo),你需要在文件URL中多加一个"/"。

下面的列表显示了如何创建前述例子中的 git 仓库:

$ cd $HOME
$ mkdir config-repo
$ cd config-repo
$ git init .
$ echo info.foo: bar > application.properties
$ git add -A .
$ git commit -m "Add application.properties"
为你的git仓库使用本地文件系统,只用于测试。你应该在生产中使用一个服务器来托管你的配置仓库。
如果你在配置仓库中只保留文本文件,那么配置仓库的初始克隆可以快速有效地进行。如果你存储二进制文件,特别是大的二进制文件,你可能会在第一次请求配置时遇到延迟,或者在服务器中遇到内存不足的错误。

Environment Repository

你应该把配置服务器的配置数据存储在哪里?支配这种行为的策略是 EnvironmentRepository,为 Environment 对象服务。这个 Environment 是来自Spring Environment(包括作为主要特性的 propertySources)的 domain 的浅拷贝。Environment 资源是由三个变量参数化的:

  • {application}, 它在客户端映射为 spring.application.name

  • {profile}, 它映射到客户端的 spring.profiles.active(逗号分隔的列表)。

  • {label}, 这是一个服务器端的功能,对一组 "版本" 的配置文件进行标记。

Repository 实现通常表现得像 Spring Boot 应用程序,从等于 {application} 参数的 spring.config.name 和等于 {profiles} 参数的 spring.profiles.active 加载配置文件。配置文件的优先级规则也与普通 Spring Boot 应用程序相同: active profiles 优先于默认值,如果有多个配置文件,最后一个获胜(类似于向 Map 添加 entry)。

下面的客户应用示例具有这种引导配置(bootstrap configuration):

spring:
  application:
    name: foo
  profiles:
    active: dev,mysql

(与Spring Boot应用程序一样,这些属性也可以通过环境变量或命令行参数来设置)。

如果仓库是基于文件的,服务器会从 application.yml(在所有客户端之间共享)和 foo.yml(以 foo.yml 为优先)创建一个 Environment。如果YAML文件里面有指向 Spring 配置文件的文件,这些文件将以更高的优先级被应用(按照列出的配置文件的顺序)。如果有特定于配置文件的YAML(或 properties)文件,这些文件也会以高于默认值的优先权被应用。更高的优先级转换为 Environment 中较早列出的 PropertySource。(这些规则同样适用于独立的Spring Boot应用程序)。

你可以将 spring.cloud.config.server.accept-empty 设置为 false,这样,如果没有找到应用程序,服务器将返回 HTTP 404 状态。默认情况下,这个标志被设置为 true

你不能将 spring.main.* 属性放在远程 EnvironmentRepository 中。这些属性是作为应用程序初始化的一部分来使用的。

Git 后端

EnvironmentRepository 的默认实现使用 Git 后端,这对于管理升级和物理环境以及审计更改非常方便。要改变仓库的位置,你可以在配置服务器中设置 spring.cloud.config.server.git.uri 配置属性(例如在 application.yml 中)。如果你用 file: 前缀来设置它,它应该从本地仓库工作,这样你就可以在没有服务器的情况下快速、轻松地开始工作。然而,在这种情况下,服务器直接在本地仓库上操作,而不克隆它(如果它不是裸露的,也没有关系,因为配置服务器从不对 "远程" 仓库进行修改)。为了扩大配置服务器的规模并使其高度可用,你需要让服务器的所有实例都指向同一个仓库,所以只有共享文件系统才能发挥作用。即使在这种情况下,最好使用共享文件系统仓库的 ssh: 协议,这样服务器就可以克隆它并使用本地工作拷贝作为缓存。

这个 repository 的实现将 HTTP 资源的 {label} 参数映射到一个git标签(提交ID、分支名称或标签)。如果git分支或标签名称包含一个斜线(/),那么HTTP URL中的标签应该用特殊字符串 (_) 来指定(以避免与其他URL路径产生歧义)。例如,如果标签是 foo/bar,替换掉斜线会产生以下标签:foo(_)bar。包含特殊字符串 (_) 也可以应用于 {application} 参数。如果你使用命令行客户端,如 curl,要注意URL中的括号—​你应该在shell中用单引号('')来转义它们。

跳过SSL证书验证

可以通过设置 git.skipSslValidation 属性为 true(默认为 false)来禁用配置服务器对Git服务器SSL证书的验证。

spring:
  cloud:
    config:
      server:
        git:
          uri: https://example.com/my/repo
          skipSslValidation: true
设置 HTTP 连接超时

你可以配置配置服务器等待获取 HTTP 连接的时间,单位是秒。使用 git.timeout 属性(默认为 5)。

spring:
  cloud:
    config:
      server:
        git:
          uri: https://example.com/my/repo
          timeout: 4
Git URI中的占位符

Spring Cloud Config Server 支持 git 仓库的 URL,其中包含 {application}{profile} 的占位符。(如果你需要的话,还有 {label},但记住,无论如何,标签都是作为git标签应用的)。所以你可以通过使用类似于以下的结构来支持 "每个应用程序一个仓库" 的策略:

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

你也可以通过使用类似的模式,但使用 {profile} 来支持 "每个配置文件一个仓库" 的策略。

此外,在你的 {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 开头的应用程序名称(/* 后缀会自动添加到任何没有配置文件匹配器(profile matcher)的模式中)。

在 "简单" 例子中使用的 "单行" 快捷方式,只有在唯一需要设置的属性是URI的情况下才可以使用。如果你需要设置其他东西(证书、模式等等),你需要使用完整的形式。

repo 中的 pattern 属性实际上是一个数组,所以你可以使用YAML数组(或 properties 文件中的 [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
Spring Cloud 猜测,包含一个不以 * 结尾的配置文件的模式意味着你实际上想匹配一个以这个模式开始的配置文件列表(所以 */staging["*/staging", "*/staging,*"] 等的快捷方式)。这种情况很常见,例如,你需要在本地运行 "开发" 配置文件的应用程序,但也需要远程运行 "云" 配置文件。

每个库也可以选择在子目录中存储配置文件,搜索这些目录的模式可以被指定为 search-paths。下面的例子显示了一个顶层的配置文件:

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

在前面的例子中,服务器在顶层和 foo/ 子目录以及名称以 bar 开头的任何子目录中搜索配置文件。

默认情况下,服务器会在第一次请求配置时克隆远程仓库。服务器可以被配置为在启动时克隆仓库库,如下面的顶层例子所示:

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。所有其他的仓库都不会被克隆,直到有人请求仓库的配置。

设置配置服务器启动时克隆仓库有助于在配置服务器启动时快速识别配置错误的配置源(如无效的仓库URI)。如果不为配置源启用 cloneOnStart,配置服务器可能会在配置错误或无效的配置源下成功启动,直到应用程序从该配置源请求配置时才发现错误。
认证

要在远程仓库上使用 HTTP basic 认证,需要单独添加 usernamepassword 属性(不在URL中),如下例所示:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          username: trolley
          password: strongpassword

如果你不使用 HTTPS 和用户凭证,当你在默认目录(~/.ssh)中存储密钥,并且 URI 指向 SSH 位置,如 git@github.com:configuration/cloud-configuration 时,SSH 也应该开箱即用。重要的是,在 ~/.ssh/known_hosts 文件中要有 Git 服务器的条目,并且是 ssh-rsa 格式。其他格式(如 ecdsa-sha2-nistp256)不被支持。为了避免意外,你应该确保 Git 服务器的 known_hosts 文件中只有一个条目,并且它与你提供给配置服务器的 URL 相匹配。如果你在 URL 中使用了一个主机名,你应该在 known_hosts 文件中准确地写入这个主机名(而不是 IP)。仓库是通过使用 JGit 访问的,所以你找到的任何关于这个的文档都应该是适用的。HTTPS 代理设置可以在 ~/.git/config 或(与其他 JVM 进程相同的方式)用系统属性(-Dhttps.proxyHost-Dhttps.proxyPort)设置。

如果你不知道你的 ~/.git 目录在哪里,可以使用 git config --global 来操作设置(例如,git config --global http.sslVerify false)。

JGit 需要 PEM 格式的 RSA 密钥。下面是一个ssh-keygen(来自openssh)命令的例子,它将生成一个corect格式的密钥:

ssh-keygen -m PEM -t rsa -b 4096 -f ~/config_server_deploy_key.rsa
在使用SSH密钥时,预期的 SSH 私钥必须以 -----BEGIN RSA PRIVATE KEY----- 开始。如果密钥以 -----BEGIN OPENSSH PRIVATE KEY----- 开始,那么当 spring-cloud-config 服务器启动时,RSA密钥将无法加载。该错误看起来像:
- Error in object 'spring.cloud.config.server.git': codes [PrivateKeyIsValid.spring.cloud.config.server.git,PrivateKeyIsValid]; arguments [org.springframework.context.support.DefaultMessageSourceResolvable: codes [spring.cloud.config.server.git.,]; arguments []; default message []]; default message [Property 'spring.cloud.config.server.git.privateKey' is not a valid private key]

为了纠正上述错误,RSA 密钥必须被转换为 PEM 格式。上面提供了一个使用 openssh 生成适当格式的新密钥的例子。

用 AWS CodeCommit 进行认证

Spring Cloud Config Server 还支持 AWS CodeCommit 认证。当从命令行使用Git时,AWS CodeCommit使用了一个认证 helper。这个 helper 不用于JGit库,所以如果 Git URI 符合 AWS CodeCommit 模式,就会为 AWS CodeCommit 创建一个 JGit CredentialProvider。AWS CodeCommit 的 URI 遵循这个模式:

https://git-codecommit.${AWS_REGION}.amazonaws.com/v1/repos/${repo}

如果你在AWS CodeCommit URI中提供 username 和 password,它们必须是提供存储库访问权限的 AWS accessKeyId 和 secretAccessKey。如果你不指定 username 和 password,则通过使用 默认 Credential Provider Chain 来检索 accessKeyId 和 secretAccessKey。

如果你的 Git URI 符合 CodeCommit URI 模式(如前所示),你必须在 username 和 password 中提供有效的AWS凭证,或者在默认凭证提供者链支持的某个位置提供有效的AWS凭证。AWS EC2 实例可以使用 IAM Roles for EC2 Instances

software.amazon.awssdk:auth jar 是一个可选的依赖项。如果 software.amazon.awssdk:auth jar 不在你的 classpath 上,无论 git 服务器 URI 如何,AWS Code Commit 凭证提供者都不会被创建。
用 Google Cloud Source 进行认证

Spring Cloud Config Server还支持对 Google Cloud Source 仓库进行认证。

如果你的 Git URI 使用 httphttps 协议,且域名为 source.developers.google.com,则将使用 Google Cloud Source 的凭证 provider。Google Cloud Source 仓库的 URI 格式为 https://source.developers.google.com/p/${GCP_PROJECT}/r/${REPO}。要获得你的仓库的URI,点击 Google Cloud Source 用户界面的 "Clone",并选择 "手动生成的凭证"。不要生成任何凭证,只需复制显示的URI。

Google Cloud Source 凭证 provider 将使用谷歌云平台应用程序默认凭证。关于如何为一个系统创建应用默认凭证,请参见 Google Cloud SDK 文档。这种方法将适用于开发环境中的用户账户和生产环境中的服务账户。

com.google.auth:google-auth-library-oauth2-http 是一个可选的依赖项。如果 google-auth-library-oauth2-http jar 不在你的 classpath 上,无论 git 服务器 URI 如何,都不会创建 Google Cloud Source 凭证 provider。
使用 properties 配置Git SSH

默认情况下,Spring Cloud Config Server 使用的 JGit 库在使用 SSH URI 连接到 Git 仓库时使用 SSH 配置文件,如 ~/.ssh/known_hosts/etc/ssh/ssh_config。在 Cloud Foundry 等云环境中,本地文件系统可能是短暂的或不容易访问。对于这些情况,SSH 配置可以通过使用 Java properties 来设置。为了激活基于 properties 的 SSH 配置,spring.cloud.config.server.git.ignoreLocalSshSettings 属性必须设置为 true,如以下示例所示:

  spring:
    cloud:
      config:
        server:
          git:
            uri: git@gitserver.com:team/repo1.git
            ignoreLocalSshSettings: true
            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-----

下表描述了SSH配置属性。

Table 1. SSH配置属性
属性名 说明

ignoreLocalSshSettings

如果为 true,则使用基于 property 而不是基于文件的 SSH 配置。必须在 spring.cloud.config.server.git.ignoreLocalSshSettings 中设置,而不是在仓库定义中。

privateKey

有效的SSH私钥。如果 ignoreLocalSshSettingstrue 且Git URI为SSH格式,则必须设置。

hostKey

有效的 SSH host key。如果 hostKeyAlgorithm 也被设置,则必须被设置。

hostKeyAlgorithm

ssh-dss, ssh-rsa, ssh-ed25519, ecdsa-sha2-nistp256, ecdsa-sha2-nistp384, 或 ecdsa-sha2-nistp521 之一。如果 hostKey 也被设置,则必须被设置。

strictHostKeyChecking

truefalse。如果是 false,则忽略有 host key 的错误。

knownHostsFile

自定义 .known_hosts 文件的位置。

preferredAuthentications

覆盖服务器认证方法的顺序。如果服务器在 publickey 方法之前有 keyboard 交互式认证,这应该允许规避登录提示。

Git 搜索路径中的占位符

Spring Cloud Config Server 还支持带有 {application}{profile} 占位符的搜索路径。(以及 {label} 如果你需要的话),如下面的例子所示:

spring:
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          search-paths: '{application}'

前面的列表会导致在仓库中搜索与该目录同名的文件(以及顶层的)。通配符在带有占位符的搜索路径中也是有效的(任何匹配的目录都包括在搜索中)。

强制 pull Git 仓库

如前所述,Spring Cloud Config Server 克隆了一个远程git仓库,以防本地副本变脏(例如,操作系统进程改变了文件夹内容),导致 Spring Cloud Config Server 无法从远程仓库更新本地副本。

为了解决这个问题,有一个 force-pull 属性,如果本地副本脏了,它可以让 Spring Cloud Config Server 强制从远程仓库拉取,如下面的例子所示:

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仓库中未被追踪的分支

由于 Spring Cloud Config Server 有一个远程git仓库的克隆,在将分支检出到本地repo后(例如通过标签获取属性),它将永远保留这个分支或直到下一次服务器重启(创建新的本地repo)。因此,可能会出现这样的情况:远程分支被删除,但其本地副本仍可用于获取。如果 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 来控制配置服务器从你的 Git 后台获取更新配置数据的频率。此属性的值是以秒为单位的。默认值为 0,意味着配置服务器将在每次请求时从 Git repo 中获取更新的配置。

默认标签(Label)

Git 使用的默认标签是 main。如果你没有设置 spring.cloud.config.server.git.defaultLabel,并且一个名为 main 的分支不存在,配置服务器也会默认尝试 checkout 一个名为 master 的分支。如果你想禁用后备分支行为,可以将 spring.cloud.config.server.git.tryMasterBranch 设置为 false

版本控制后端文件系统的使用

对于基于VCS的后端(git、svn),文件被签出或克隆到本地文件系统。默认情况下,它们被放在系统的临时目录中,前缀为 config-repo-。例如,在linux上,它可能是 /tmp/config-repo-<randomid>。一些操作系统会 定期清理临时目录。这可能会导致意想不到的行为,比如丢失属性。为了避免这个问题,通过将 spring.cloud.config.server.git.basedirspring.cloud.config.server.svn.basedir 设置为不在系统临时结构中的目录,改变配置服务器使用的目录。

文件系统后端

配置服务器中还有一个 “native” profile,它不使用Git,而是从本地 classpath 或文件系统(你想用 spring.cloud.config.server.native.searchLocations 指向的任何静态URL)加载配置文件。要使用 native profile,请使用 spring.profiles.active=native 启动配置服务器。

记住要为文件资源使用 file: 前缀(没有前缀的默认值通常是 classpath)。与任何 Spring Boot 配置一样,你可以嵌入 ${} 式的 environment 占位符,但要记住,Windows中的绝对路径需要额外的 /(例如,file:///${user.home}/config-repo)。
searchLocations 的默认值与本地 Spring Boot 应用程序相同(即 [classpath:/, classpath:/config,file:./, file:./config])。这不会将服务器上的 application.properties 暴露给所有客户端,因为在发送到客户端之前,服务器中存在的任何属性源都会被删除。
文件系统后端对于快速启动和测试是很好的。要在生产中使用它,你需要确保文件系统是可靠的,并在配置服务器的所有实例中共享。

搜索位置可以包含 {application}{profile}{label} 的占位符。通过这种方式,你可以将路径中的目录分开,并选择一种对你有意义的策略(如每个应用程序的子目录或每个配置文件的子目录)。

如果你不在搜索位置使用占位符,这个 repository 也会将HTTP资源的 {label} 参数附加到搜索路径的后缀,所以属性文件会从每个搜索位置和一个与标签同名的子目录中加载(在Spring Environment 中,被标记的属性优先)。因此,没有占位符的默认行为与添加一个以 /{label}/ 结尾的搜索位置相同。例如,file:/tmp/configfile:/tmp/config,file:/tmp/config/{label} 相同。这种行为可以通过设置 spring.cloud.config.server.native.addLabelLocations=false 来禁用。

Vault 后端

Spring Cloud Config Server 也支持 Vault 作为后端。

Vault是一个用于安全访问 secrets 的工具。secrets 是任何你想严格控制访问的东西,如API密钥、密码、证书和其他敏感信息。Vault为任何 secrets 提供了一个统一的接口,同时提供严格的访问控制并记录详细的审计日志。

关于 Vault 的更多信息,请参阅 Vault快速入门指南

为了使配置服务器能够使用 Vault 后端,你可以用vault配置文件运行你的配置服务器。例如,在你的配置服务器的 application.properties 中,你可以添加 spring.profiles.active=vault

默认情况下,Spring Cloud 配置服务器使用基于令牌的认证来从Vault获取配置。Vault还支持其他认证方法,如AppRole、LDAP、JWT、CloudFoundry、Kubernetes Auth。为了使用除TOKEN或X-Config-Token header 以外的任何认证方法,我们需要在classpath上设置Spring Vault Core,以便配置服务器能够将认证委托给该库。请在你的配置服务器应用程序中添加以下依赖项。

Maven (pom.xml)

<dependencies>
	<dependency>
		<groupId>org.springframework.vault</groupId>
		<artifactId>spring-vault-core</artifactId>
	</dependency>
</dependencies>

Gradle (build.gradle)

dependencies {
    implementation "org.springframework.vault:spring-vault-core"
}

默认情况下,配置服务器假设你的Vault服务器运行在 http://127.0.0.1:8200。它还假定后端 name 为 secret,key 为 application。所有这些默认值都可以在你的配置服务器的 application.properties 中进行配置。下表描述了可配置的 Vault 属性:

Name 默认值

host

127.0.0.1

port

8200

scheme

http

backend

secret

defaultKey

application

profileSeparator

,

kvVersion

1

skipSslValidation

false

timeout

5

namespace

null

前述表格中的所有属性都必须以 spring.cloud.config.server.vault 为前缀,或者放在复合配置中正确的 Vault 部分中。

所有可配置的属性都可以在 org.springframework.cloud.config.server.environment.VaultEnvironmentProperties 中找到。

Vault 0.10.0 引入了一个版本化的 key-value 后端(k/v后端版本2),它暴露了一个与早期版本不同的API,它现在需要在挂载路径和实际上下文路径之间有一个 data/,并将 secrets 包裹在一个 data 对象中。设置 spring.cloud.config.server.vault.kv-version=2 将考虑到这一点。

另外,还支持 Vault Enterprise X-Vault-Namespace header 。为了让它被发送到Vault,请设置 namespace 属性。

在你的配置服务器运行时,你可以向服务器发出 HTTP 请求,以便从 Vault 后端检索值。要做到这一点,你需要为你的 Vault 服务器提供一个令牌。

首先,在你的 Vault 中放置一些数据,如以下例子所示:

$ vault kv put secret/application foo=bar baz=bam
$ vault kv put secret/myapp foo=myappsbar

第二,向你的配置服务器发出一个HTTP请求,以检索这些值,如下例所示:

$ curl -X "GET" "http://localhost:8888/myapp/default" -H "X-Config-Token: yourtoken"

你应该看到一个类似于以下的响应:

{
   "name":"myapp",
   "profiles":[
      "default"
   ],
   "label":null,
   "version":null,
   "state":null,
   "propertySources":[
      {
         "name":"vault:myapp",
         "source":{
            "foo":"myappsbar"
         }
      },
      {
         "name":"vault:application",
         "source":{
            "baz":"bam",
            "foo":"bar"
         }
      }
   ]
}

客户端提供必要的认证以让配置服务器与Vault对话的默认方式是设置 X-Config-Token 头。但是,你可以通过设置与 Spring Cloud Vault 相同的配置属性,省略该 header 并在服务器中配置认证。要设置的属性是 spring.cloud.config.server.vault.authentication。它应该被设置为支持的认证方法之一。你可能还需要设置你所使用的认证方法的其他特定属性,方法是使用与 spring.cloud.vault 记载的相同的属性名称,但使用 spring.cloud.config.server.vault 前缀。请参阅 《Spring Cloud Vault参考指南》了解更多细节。

如果你省略了 X-Config-Token header 并使用 server property 来设置认证,Config Server 应用程序需要额外依赖 Spring Vault 来启用额外的认证选项。关于如何添加该依赖,请参见 Spring Vault参考指南
多属性源

当使用Vault时,你可以为你的应用程序提供多个属性源。例如,假设你已将数据写入Vault的以下路径:

secret/myApp,dev
secret/myApp
secret/application,dev
secret/application

写入 secret/application 的属性对 使用 Config Server 的所有应用程序 都是可用的。一个 name 为 myApp 的应用程序将有任何写入 secret/myAppsecret/application 的属性对其可用。当 myApp 启用 dev profile时,写入上述所有路径的属性对它来说都是可用的,列表中第一个路径的属性优先于其他路径。

通过代理访问后端

配置服务器可以通过 HTTP 或 HTTPS 代理访问 Git 或 Vault 的后端。对于 Git 或 Vault 来说,这种行为由 proxy.httpproxy.https 下的设置来控制。这些设置是针对每个仓库的,所以如果你使用的是 复合环境仓库,你必须为复合环境中的每个后端单独配置代理设置。如果使用的网络需要为 HTTP 和 HTTPS URLs 提供单独的代理服务器,你可以为单个后端配置 HTTP 和 HTTPS 代理设置:在这种情况下,http 访问将使用 http 代理,https 访问使用 https 代理。另外,你也可以使用应用程序和代理之间的代理定义协议,指定一个唯一的代理,用于两个协议。

下表描述了 HTTP 和 HTTPS 代理的代理配置属性。所有这些属性必须以 proxy.httpproxy.https 为前缀。

Table 2. 代理配置属性
属性 说明

host

代理的主机。

port

访问代理的端口。

nonProxyHosts

配置服务器应该在代理之外访问的任何主机。如果同时为 proxy.http.nonProxyHostsproxy.https.nonProxyHosts 提供了值,将使用 proxy.http 的值。

username

用来验证代理的用户名。如果 proxy.http.usernameproxy.https.username 都提供了值,将使用 proxy.http 的值。

password

用来验证代理的密码。如果同时提供 proxy.http.passwordproxy.https.password 的值,将使用 proxy.http 的值。

下面的配置使用 HTTPS 代理来访问 Git 仓库。

spring:
  profiles:
    active: git
  cloud:
    config:
      server:
        git:
          uri: https://github.com/spring-cloud-samples/config-repo
          proxy:
            https:
              host: my-proxy.host.io
              password: myproxypassword
              port: '3128'
              username: myproxyusername
              nonProxyHosts: example.com

与所有应用程序共享配置

在所有应用程序之间共享配置,根据你所采取的方法而有所不同,如以下主题所述:

基于文件的仓库

对于基于文件的(git、svn和本地)仓库,文件名为 application* 的资源(application.propertiesapplication.ymlapplication-*.properties 等)在所有客户端应用程序之间共享。你可以使用这些文件名的资源来配置全局默认值,并在必要时让它们被特定的应用程序文件所覆盖。

属性覆盖 功能也可用于设置全局默认值,占位符应用程序允许本地覆盖它们。

使用 "本地" 配置文件(本地文件系统后端),你应该使用一个明确的搜索位置,而不是服务器自己配置的一部分。否则,默认搜索位置中的 application* 资源会被删除,因为它们是服务器的一部分。
Vault 服务器

当使用 Vault 作为后端时,你可以通过将配置放在 secret/application 中与所有应用程序共享配置。例如,如果你运行下面的Vault命令,所有使用配置服务器的应用程序将有属性 foobaz 可供他们使用:

$ vault write secret/application foo=bar baz=bam
CredHub 服务器

当使用CredHub作为后端时,你可以通过将配置放在 /application/ 中,或将其放在应用程序的 default profile 中,与所有应用程序共享配置。例如,如果你运行下面的 CredHub 命令,所有使用配置服务器的应用程序将有 shared.color1shared.color2 的属性可供他们使用:

credhub set --name "/application/profile/master/shared" --type=json
value: {"shared.color1": "blue", "shared.color": "red"}
credhub set --name "/my-app/default/master/more-shared" --type=json
value: {"shared.word1": "hello", "shared.word2": "world"}

AWS Secrets Manager

当使用 AWS Secrets Manager 作为后端时,你可以通过将配置放在 /application/ 中或放在应用程序的 default profile 中,与所有应用程序共享配置。例如,如果你添加了带有以下 key 的secrets,所有使用配置服务器的应用程序将拥有可用于它们的 shared.fooshared.bar 属性:

secret name = /secret/application-default/
secret value =
{
 shared.foo: foo,
 shared.bar: bar
}

or

secret name = /secret/application/
secret value =
{
 shared.foo: foo,
 shared.bar: bar
}
标记的版本

AWS Secrets Manager 仓库允许保留配置环境的标记版本,与Git后端相同。

仓库实现将 HTTP 资源的 {label} 参数映射到 AWS Secrets Manager secret 的暂存标签。要创建一个有标签的secret,需要创建一个secret或更新其内容,并为其定义一个暂存标签(staging label)(有时在AWS文档中称为版本阶段)。例如:

$ aws secretsmanager create-secret \
      --name /secret/test/ \
      --secret-string '{"version":"1"}'
{
    "ARN": "arn:aws:secretsmanager:us-east-1:123456789012:secret:/secret/test/-a1b2c3",
    "Name": "/secret/test/",
    "VersionId": "cd291674-de2f-41de-8f3b-37dbf4880d69"
}

$ aws secretsmanager update-secret-version-stage \
      --secret-id /secret/test/ \
      --version-stage 1.0.0 \
      --move-to-version-id cd291674-de2f-41de-8f3b-37dbf4880d69

{
    "ARN": "arn:aws:secretsmanager:us-east-1:123456789012:secret:/secret/test/-a1b2c3",
    "Name": "/secret/test/",
}

使用 spring.cloud.config.server.aws-secretsmanager.default-label 属性来设置默认标签。如果没有定义该属性,后端会使用 AWSCURRENT 作为暂存标签。

spring:
  profiles:
    active: aws-secretsmanager
  cloud:
    config:
      server:
        aws-secretsmanager:
          region: us-east-1
          default-label: 1.0.0

注意,如果没有设置默认标签,并且请求没有定义标签,repository 将使用secrets,就像标签化版本支持被禁用一样。另外,只有当标签化支持被启用时,默认标签才会被使用。否则,定义这个属性是没有意义的。

请注意,如果暂存标签包含一个斜线(/),那么HTTP URL中的标签应该用特殊字符串 (_) 来指定(以避免与其他URL路径产生歧义),与 Git 后端的章节描述的方式相同。

AWS Parameter Store

当使用 AWS Parameter Store 作为后端时,你可以通过将属性放在 /application 层次结构内,与所有应用程序共享配置。

例如,如果你添加了具有以下名称的参数,所有使用配置服务器的应用程序将有属性 foo.barfred.baz 可供他们使用:

/config/application/foo.bar
/config/application-default/fred.baz

JDBC 后端

Spring Cloud Config Server支持将JDBC(关系型数据库)作为配置属性的后端。你可以通过在classpath中添加 spring-boot-starter-data-jdbc 并使用 jdbc profile 或添加 JdbcEnvironmentRepository 类型的bean来启用该功能。如果你在classpath上包含了正确的依赖关系(更多相关细节见用户指南),Spring Boot就会配置一个数据源。

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

数据库需要有一个名为 PROPERTIES 的表,其列名为 APPLICATIONPROFILELABEL(具有通常的 Environment 含义),另外还有 KEYVALUE,用于 Properties 风格中的键和值对。所有字段都是Java中的 String 类型,所以你可以把它们变成任何你需要的长度的 VARCHAR。属性值的行为与它们来自 Spring Boot 名为 {application}-{profile}.properties 的属性文件的行为相同,包括所有的加密和解密,这将作为后处理步骤应用(也就是说,不直接在版本库实现中应用)。

JDBC使用的默认标签是 master。你可以通过设置 spring.cloud.config.server.jdbc.defaultLabel 来改变。

Redis 后端

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

pom.xml
<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中。hash的名称应该与 spring.application.name 属性或 spring.application.namespring.profiles.active[n] 的组合相同。

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

运行上面的命令后,一个hash应该包含以下键值:

HGETALL sample-app
{
  "server.port": "8100",
  "sample.topic.name": "test",
  "test.property1": "property1"
}
当没有指定 profile 时,将使用 default

AWS S3 后端

Spring Cloud Config Server 支持AWS S3作为配置属性的后端。你可以通过为 AWS Java SDK For Amazon S3 添加一个依赖来启用这个功能。

pom.xml
<dependencies>
	<dependency>
		<groupId>software.amazon.awssdk</groupId>
		<artifactId>s3</artifactId>
	</dependency>
</dependencies>

下面的配置使用AWS S3客户端来访问配置文件。我们可以使用 spring.cloud.config.server.awss3.* 属性来选择你的配置所存储的桶。

spring:
  profiles:
    active: awss3
  cloud:
    config:
      server:
        awss3:
          region: us-east-1
          bucket: bucket1

也可以通过 spring.cloud.config.server.awss3.endpoint 指定一个 AWS URL 来 覆盖你的S3服务的标准端点。这允许支持 S3 的 beta region,以及其他S3兼容的存储API。

凭证是使用 默认的 Credential Provider Chain 找到的。支持版本化和加密的桶,无需进一步配置。

配置文件以 {application}-{profile}.properties{application}-{profile}.yml{application}-{profile}.json 的形式存储在你的桶里。可以提供一个可选的标签来指定文件的目录路径。

当没有指定 profile 时,将使用 default

AWS Parameter Store 后端

Spring Cloud Config Server支持AWS Parameter Store作为配置属性的后端。你可以通过 为SSM添加AWS Java SDK 的依赖来启用这一功能。

pom.xml
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>ssm</artifactId>
</dependency>

下面的配置使用AWS SSM客户端来访问参数。

spring:
  profiles:
    active: awsparamstore
  cloud:
    config:
      server:
        awsparamstore:
          region: eu-west-2
          endpoint: https://ssm.eu-west-2.amazonaws.com
          origin: aws:parameter:
          prefix: /config/service
          profile-separator: _
          recursive: true
          decrypt-values: true
          max-results: 5

下表描述了AWS Parameter Store 配置属性。

Table 3. AWS Parameter Store 配置属性
属性名称 必须 默认值 说明

region

no

AWS Parameter Store 客户端要使用的区域。如果没有明确设置,SDK会尝试通过使用 默认的 Region Provider Chain 来确定要使用的区域。

endpoint

no

AWS SSM客户端的入口点的URL。这可以用来为API请求指定一个替代的端点。

origin

no

aws:ssm:parameter:

添加到 property source 名称中的前缀,以显示其出处。

prefix

no

/config

表示从 AWS Parameter Store 加载的每个属性在参数层次结构中的L1级的前缀。

profile-separator

no

-

字符串,将附加的配置文件与上下文名称分开。

recursive

no

true

标志,表示检索一个层次结构内的所有AWS参数。

decrypt-values

no

true

标志,表示检索所有AWS参数,其值已解密。

max-results

no

10

AWS Parameter Store API 调用时要返回的最大项目数。

AWS Parameter Store API 凭证是使用 默认的 Credential Provider Chain 确定的。已经支持有版本的参数,默认行为是返回最新版本。

  • 当没有指定 application 时,application 是默认的,而当没有指定 profile 时,则使用 default

  • awsparamstore.prefix 的有效值必须以一个正斜杠开始,后面是一个或多个有效的路径段,或者为空。

  • awsparamstore.profile-separator 的有效值只能包含点、破折号和下划线。

  • awsparamstore.max-results 的有效值必须在 [1, 10] 范围内。

AWS Secrets Manager 后端

Spring Cloud Config Server 支持 AWS Secrets Manager 作为配置属性的后端。你可以通过添加对 AWS Java SDK for Secrets Manager 的依赖来启用这一功能。

pom.xml
<dependency>
    <groupId>software.amazon.awssdk</groupId>
    <artifactId>secretsmanager</artifactId>
</dependency>

下面的配置使用 AWS Secrets Manager 客户端来访问 secrets。

spring:
  profiles:
  	active: awssecretsmanager
  cloud:
    config:
      server:
        aws-secretsmanager:
          region: us-east-1
          endpoint: https://us-east-1.console.aws.amazon.com/
          origin: aws:secrets:
          prefix: /secret/foo
          profileSeparator: _

AWS Secrets Manager API 凭证是使用 默认的 Credential Provider Chain 确定的。

  • 当没有指定 application 时,application 是默认的,而当没有指定profile 时,则使用 default

CredHub 后端

Spring Cloud Config Server 支持 CredHub 作为配置属性的后端。你可以通过添加对 Spring CredHub 的依赖来启用这一功能。

pom.xml
<dependencies>
	<dependency>
		<groupId>org.springframework.credhub</groupId>
		<artifactId>spring-credhub-starter</artifactId>
	</dependency>
</dependencies>

下面的配置使用双向认证(mutual TLS)来访问 CredHub:

spring:
  profiles:
    active: credhub
  cloud:
    config:
      server:
        credhub:
          url: https://credhub:8844

这些属性应以JSON格式存储,如::

credhub set --name "/demo-app/default/master/toggles" --type=json
value: {"toggle.button": "blue", "toggle.link": "red"}
credhub set --name "/demo-app/default/master/abs" --type=json
value: {"marketing.enabled": true, "external.enabled": false}

所有名称为 spring.cloud.config.name=demo-app 的客户应用程序将有以下属性可供它们使用:

{
    toggle.button: "blue",
    toggle.link: "red",
    marketing.enabled: true,
    external.enabled: false
}
当没有指定profile时,将使用 default;当没有指定标签时,将使用 master 作为默认值。注意:添加到 application 的值将被所有应用程序共享。
OAuth 2.0

你可以用 OAuth 2.0 认证,使用 UAA 作为 provider。

pom.xml
<dependencies>
	<dependency>
		<groupId>org.springframework.security</groupId>
		<artifactId>spring-security-config</artifactId>
	</dependency>
	<dependency>
		<groupId>org.springframework.security</groupId>
		<artifactId>spring-security-oauth2-client</artifactId>
	</dependency>
</dependencies>

下面的配置使用OAuth 2.0和UAA来访问CredHub:

spring:
  profiles:
    active: credhub
  cloud:
    config:
      server:
        credhub:
          url: https://credhub:8844
          oauth2:
            registration-id: credhub-client
  security:
    oauth2:
      client:
        registration:
          credhub-client:
            provider: uaa
            client-id: credhub_config_server
            client-secret: asecret
            authorization-grant-type: client_credentials
        provider:
          uaa:
            token-uri: https://uaa:8443/oauth/token
使用的 UAA client-id 应该有 credhub.read 作为 scope。

复合环境仓库

在某些情况下,你可能希望从多个环境仓库库(environment repository)中提取配置数据。要做到这一点,你可以在配置服务器的应用程序 properties 或YAML文件中启用 composite profile。例如,如果你想从一个 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 key 下的仓库排列顺序决定的。在上面的例子中,Subversion 仓库被列在第一位,所以在 Subversion 仓库中发现的值会优先于在某个 Git 仓库中发现的相同属性的值。在 rex Git 仓库中找到的值会在 walter Git 仓库中找到的相同属性值之前使用。

如果你想只从不同类型的仓库中提取配置数据,你可以在配置服务器的应用程序属性或YAML文件中启用相应的配置文件,而不是 composite profile。例如,如果你想从一个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 token。参见 Vault 后端
从 environment repository 检索值时的任何类型的失败都会导致整个复合环境的失败。如果你希望在仓库失败时复合仍能继续,你可以将 spring.cloud.config.server.failOnCompositeError 设置为 false
当使用复合环境时,重要的是所有仓库都包含相同的标签。如果你有一个与前面例子中类似的环境,你请求带有 master 标签的配置数据,但 Subversion 仓库不包含一个叫做 master 的分支,整个请求就会失败。
自定义复合环境 Repository

除了使用 Spring Cloud 的一个环境 repository 外,你还可以提供你自己的 EnvironmentRepository Bean,作为复合环境的一部分。要做到这一点,你的Bean必须实现 EnvironmentRepository 接口。如果你想在复合环境中控制你的自定义 EnvironmentRepository 的优先级,你也应该实现 Ordered 接口并重写 getOrdered 方法。如果你没有实现 Ordered 接口,你的 EnvironmentRepository 将被赋予最低的优先级。

属性覆盖

配置服务器有一个 "覆盖" 功能,可以让运维为所有应用程序提供配置属性。被覆盖的属性不能被应用程序用正常的 Spring Boot hook 意外地改变。要声明覆盖,请向 spring.cloud.config.server.overrides 添加一个 name-value 对的映射,如下面的例子所示:

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

前面的例子使所有作为 config client 的应用程序读取 foo=bar,与它们自己的配置无关。

配置系统不能强迫应用程序以任何特定方式使用配置数据。因此,覆盖是不可强制执行的。然而,它们确实为 Spring Cloud Config 客户端提供了有用的默认行为。
通常情况下,带有 ${} 的Spring environment 占位符可以通过使用反斜杠(\)来转义 ${ 来实现(并在客户端进行解析)。例如,\${app.foo:bar} 会解析为 bar,除非应用程序提供了自己的 app.foo
在YAML中,你不需要转义反斜杠本身。然而,在属性文件中,当你在服务器上配置重写时,你确实需要转义反斜杠。

你可以通过在远程仓库中设置 spring.cloud.config.overrideNone=true 标志(默认为 false)来改变客户端中所有覆盖的优先级,使其更像默认值,让应用程序在环境变量或系统属性中提供自己的值。

使用Bootstrap来覆盖属性

如果你启用了 config first bootstrap,你可以通过在来自 config 服务器的应用程序配置中放置两个属性来允许客户端应用程序覆盖来自config服务器的配置。

spring.cloud.config.allowOverride=true
spring.cloud.config.overrideNone=true

启用 Bootstrap 并将这两个属性设置为 true 后,你就可以在客户端应用程序配置中覆盖来自配置服务器的配置。

使用占位符重写属性

在不启用 config first bootstrap 的情况下,覆盖属性的一个更简洁的方法是在来自config server的配置中使用属性占位符。

例如,如果来自配置服务器的配置包含以下属性

hello=${app.hello:Hello From Config Server!}

你可以通过在你的本地应用程序配置中设置 app.hello 来覆盖来自配置服务器的 hello 值。

app.hello=Hello From Application!

使用Profiles重写属性

覆盖来自配置服务器的属性的最后一种方法是在客户端应用程序的特定 profile 中指定它们。

例如,如果你有来自配置服务器的以下配置

hello="Hello From Config Server!"

你可以通过在特定 profile 中设置 hello,然后启用该 profile,来覆盖客户端应用程序中 hello 的值。

application-overrides.properties
hello="Hello From Application!"

在上面的例子中,你将不得不启用 overrides profile。

健康指标

配置服务器带有一个健康指示器(Health Indicator),用于检查配置的 EnvironmentRepository 是否在工作。默认情况下,它要求 EnvironmentRepository 提供一个名为 app 的应用程序、default profile 和 EnvironmentRepository 实现提供的默认标签。

你可以配置健康指标,以检查更多的应用程序以及自定义配置文件和自定义标签,如以下例子所示:

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

你可以通过设置 management.health.config.enabled=false 来禁用健康指标。

此外,你可以通过设置属性 spring.cloud.config.server.health.down-health-status(默认值为 "DOWN')来提供一个你自己的自定义 down status。

安全

你可以用任何对你有意义的方式来保护你的配置服务器(从物理网络安全到 OAuth2 bearer token),因为 Spring Security 和 Spring Boot 提供对许多安全方面的支持。

要使用默认的 Spring Boot 配置的 HTTP Basic security,请在 classpath 上包含 Spring Security(例如,通过 spring-boot-starter-security)。默认的用户名是 user,密码是随机生成的。随机密码在实践中没有用,所以我们建议你配置密码(通过设置 spring.security.user.password),并对其进行加密(关于如何做的说明,见下文)。

Actuator 与 Security

一些平台配置了健康检查或类似的东西,并指向 /actuator/health 或其他执行器端点。如果actuator不是config server的依赖项,对 /actuator/** 的请求将与config server的API /{application}/{label} 相匹配,可能会泄露安全信息。在这种情况下,记得添加 spring-boot-starter-actuator 依赖,并配置用户,使调用 /actuator/** 的用户不能访问 /{application}/{label} 的配置服务器API。

加密和解密

要使用加密和解密功能,你需要在你的JVM中安装全强度的JCE(默认情况下不包括)。你可以从Oracle公司下载 “Java Cryptography Extension (JCE) Unlimited Strength Jurisdiction Policy Files”,并按照安装说明操作(基本上,你需要将JRE lib/security 目录下的两个 policy 文件替换为你下载的文件)。

如果远程属性源包含加密的内容(以 {cipher} 开头的值),它们在通过HTTP发送给客户端之前会被解密。这种设置的主要优点是,当属性值处于 "静态状态" 时(例如,在git仓库中),它们不需要是纯文本。如果一个值不能被解密,它就会被从属性源中删除,并添加一个额外的属性,其密钥相同,但前缀为 invalid 和一个表示 "不适用" 的值(通常是 <n/a>)。这主要是为了防止密码文本被用作密码而意外地泄露。

如果你为配置客户端应用程序设置了一个远程配置库,它可能包含一个类似于下面的 application.yml

application.yml
spring:
  datasource:
    username: dbuser
    password: '{cipher}FKSAJDFGYOS8F7GLHAKERGFHLSAJ'

application.properties 文件中的加密值不能用引号包裹。否则,该值将不会被解密。下面的例子显示了可以工作的值:

application.properties
spring.datasource.username: dbuser
spring.datasource.password: {cipher}FKSAJDFGYOS8F7GLHAKERGFHLSAJ

你可以安全地将这个纯文本推送到共享的git仓库中,而 secret 密码仍然受到保护。

服务器还暴露了 /encrypt/decrypt 端点(假设这些端点是安全的,只有授权的代理才能访问)。如果你编辑一个远程配置文件,你可以使用配置服务器通过 POST 到 /encrypt 端点来加密值,如下例所示:

$ curl localhost:8888/encrypt -s -d mysecret
682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
如果你用curl测试,那么使用 --data-urlencode(而不是 -d),并在要加密的值前加上 =(curl需要这样做),或者设置一个明确的 Content-Type: text/plain,以确保 curl 在有特殊字符('+' 特别棘手)时能正确编码数据。
要确保在加密的值中不包括任何 curl 命令的统计信息,这就是为什么例子中使用 -s 选项来沉默它们。将值输出到文件中可以帮助避免这个问题。

反向操作也可以通过 /decrypt 进行(只要服务器配置了对称密钥或完整的密钥对),如下例所示:

$ curl localhost:8888/decrypt -s -d 682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
mysecret

在你把它放在YAML或属性文件中,以及在你提交和推送到远程(可能是不安全的)存储之前,采取加密的值并添加 {cipher} 前缀。

/encrypt/decrypt 端点也都接受 /*/{application}/{profiles} 形式的路径,当客户端调用 main environment 资源时,可用于在每个应用(名称)和每个文件的基础上控制加密。

为了以这种精细的方式控制加密,你还必须提供一个 TextEncryptorLocator 类型的 @Bean,它可以为每个名字和配置文件创建一个不同的 encryptor。默认提供的那个并不这样做(所有的加密都使用同一个密钥)。

spring 命令行客户端(安装了Spring Cloud CLI扩展)也可以用来加密和解密,如下例所示:

$ spring encrypt mysecret --key foo
682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
$ spring decrypt --key foo 682bc583f4641835fa2db009355293665d2647dade3375c0ee201de2a49f7bda
mysecret

要使用文件中的密钥(如用于加密的RSA公钥),在密钥值前加上"@",并提供文件路径,如下例所示:

$ spring encrypt mysecret --key @${HOME}/.ssh/id_rsa.pub
AQAjPgt3eFZQXwt8tsHAVv/QHiY5sI2dRcR+...
--key 参数是强制性的(尽管有一个 -- 前缀)。

Key Management

配置服务器可以使用对称(共享)密钥或非对称密钥(RSA密钥对)。非对称选择在安全性方面更胜一筹,但使用对称密钥通常更方便,因为它是在 application.properties 中配置的单一属性值。

要配置对称密钥,你需要将 encrypt.key 设置为一个 secret String(或者使用 ENCRYPT_KEY 环境变量来避免直接写入纯文本配置文件)。

如果你在 classpath 上包含 spring-cloud-starter-bootstrap 或者将 spring.cloud.bootstrap.enabled=true 作为系统属性,你需要在 bootstrap.properties 中设置 encrypt.key
你不能使用 encrypt.key 配置非对称密钥。

要配置非对称钥匙,请使用 keystore(例如,由 JDK 附带的 keytool 工具创建)。keystore 的属性是 encrypt.keyStore.*,其中 * 等于

属性 说明

encrypt.keyStore.location

包含一个 Resource 位置。

encrypt.keyStore.password

持有解锁keystore的密码。

encrypt.keyStore.alias

确定要使用store 中的哪个key。

encrypt.keyStore.type

要创建的KeyStore的类型。默认为jks。

加密是用公钥完成的,而解密则需要私钥。因此,原则上,如果你只想加密(并准备在本地用私钥解密),你可以只在服务器上配置公钥。在实践中,你可能不想在本地进行解密,因为它把密钥管理过程分散到所有的客户端,而不是集中在服务器上。另一方面,如果你的配置服务器相对不安全,而且只有少数客户需要加密的属性,这可能是一个有用的选择。

创建一个用于测试的 Key Store

要创建一个用于测试的 keystore,你可以使用类似于以下的命令:

$ 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
当使用JDK 11或以上版本时,你在使用上述命令时可能会得到以下警告。在这种情况下,你可能要确保 keypassstorepass 的值一致。
Warning:  Different store and key passwords not supported for PKCS12 KeyStores. Ignoring user-specified -keypass value.

server.jks 文件放在 classpath中(例如),然后,在你的 bootstrap.yml 中,为配置服务器创建以下设置:

encrypt:
  keyStore:
    location: classpath:/server.jks
    password: letmein
    alias: mytestkey
    secret: changeme

使用多个 key 和 key 轮换

除了加密属性值中的 {cipher} 前缀外,配置服务器在(Base64编码的)密码文本开始前寻找零个或多个 {name:value} 前缀。密钥被传递给 TextEncryptorLocator,它可以做任何需要的逻辑来为密码定位一个 TextEncryptor。如果你已经配置了一个keystore(encrypt.keystore.location),默认的 locator 会寻找具有由 key 前缀提供的别名的key,其密码文本类似于以下内容:

foo:
  bar: `{cipher}{key:testkey}...`

该 locator 寻找一个名为 "testkey" 的密钥。也可以通过在前缀中使用 {secret:…​} 值来提供一个secret。然而,如果没有提供,默认情况下是使用keystore password (当你建立一个keystore而没有指定一个secret时,你会得到这样的密码)。如果你提供了一个secret,你也应该用一个自定义的 SecretLocator 来加密这个 secret。

当key只被用来加密几个字节的配置数据时(也就是说,它们没有被用在其他地方),从密码学的角度来看,key的轮换几乎没有必要。然而,你可能偶尔需要改变key(例如,在安全漏洞的情况下)。在这种情况下,所有的客户都需要改变他们的源配置文件(例如,在git中),并在所有密码中使用新的 {key:…​} 前缀。请注意,客户需要首先检查配置服务器 keystore 中的 key 别名是否可用。

如果你想让配置服务器处理所有的加密以及解密,{name:value} 前缀也可以作为纯文本添加到 /encrypt 端点上。

提供加密属性的服务

有时你想让客户端在本地解密配置,而不是在服务器中进行解密。在这种情况下,如果你提供 encrypt.* 配置来定位一个密钥,你仍然可以有 /encrypt/decrypt 端点,但你需要通过在 bootstrap.[yml|properties] 中放置 spring.cloud.config.server.encrypt.enabled=false 来明确关闭出站属性的解密功能。如果你不关心端点,如果你不配置 key 或 enabled 的标志,它应该可以工作。

提供其他形式的服务

来自 environment 端点的默认JSON格式非常适合Spring应用程序使用,因为它直接映射到 Environment 抽象。如果你愿意,你可以通过在资源路径中添加一个后缀(".yml"、".yaml" 或 ".properties")来消费YAML或Java properties 的相同数据。这对于那些不关心JSON端点的结构或其提供的额外元数据的应用程序的消费是非常有用的(例如,不使用Spring的应用程序可能会从这种方法的简单性中受益)。

YAML 和 properties 表示法有一个额外的标志(以布尔查询参数的形式提供,称为 resolvePlaceholders),表示源文档中的占位符(以标准的 Spring ${…​} 形式)应该在渲染之前在输出中解析,如果可能。对于不了解Spring占位符约定的消费者来说,这是一个有用的功能。

使用 YAML 或 properties 格式有一些限制,主要是与元数据的损失有关。例如,JSON的结构是一个有序的 property 源列表,其名称与源相关联。YAML 和 property 形式被凝聚成一个 map,即使值的来源有多个,原始源文件的名称也会丢失。另外,YAML表示法也不一定是支持仓库中YAML源的忠实表示。它是由平面 property 源的列表构建的,必须对 key 的形式做出假设。

提供纯文本服务

你的应用程序可能需要为其环境量身定制的通用纯文本配置文件,而不是使用 Environment 抽象(或YAML或properties格式中的一种替代表示)。配置服务器通过 /{application}/{profile}/{label}/{path} 的额外端点提供这些文件,其中 applicationprofilelabel 的含义与常规环境端点相同,但 path 是一个文件名的路径(如 log.xml)。这个端点的源文件的位置与 environment 端点的相同。对于properties和YAML文件,也使用同样的搜索路径。然而,不是聚合所有匹配的资源,而是只返回第一个匹配的资源。

找到资源后,正常格式的占位符(${…​})通过使用提供的application name、profile和标label的有效 Environment 来解决。通过这种方式,资源端点与environment端点紧密结合。

与 environment 配置的源文件一样,profile 被用来解析文件名。因此,如果你想要一个特定的配置文件, /*/development/*/logback.xml 可以被一个叫做 logback-development.xml 的文件解析(优先于 logback.xml)。
如果你不想提供 label 而让服务器使用default label,你可以提供一个 useDefaultLabel 请求参数。因此,前面的默认配置文件的例子可以是 /sample/default/nginx.conf?useDefaultLabel

目前,Spring Cloud Config 可以为git、SVN、本地后端和AWS S3提供纯文本。对git、SVN和本地后端的支持是相同的。AWS S3的工作方式有些不同。下面的章节展示了每一种的工作方式:

提供二进制文件服务

为了从配置服务器获取二进制文件,你将需要发送一个 application/octet-streamAccept header。

Git,SVN 和本地后端

考虑以下GIT或SVN仓库或本地后端的例子:

application.yml
nginx.conf

nginx.conf 可能类似于如下:

server {
    listen              80;
    server_name         ${nginx.server.name};
}

application.yml 可能类似于如下:

nginx:
  server:
    name: example.com
---
spring:
  profiles: development
nginx:
  server:
    name: develop.com

/sample/default/master/nginx.conf 资源可能如下:

server {
    listen              80;
    server_name         example.com;
}

/sample/development/master/nginx.conf 可能如下:

server {
    listen              80;
    server_name         develop.com;
}

AWS S3

要为AWS s3提供纯文本服务,Config Server 应用程序需要包括对 io.awspring.cloud:spring-cloud-aws-context 的依赖。有关如何设置该依赖的详细信息,请参见 《Spring Cloud AWS参考指南》。此外,当将Spring Cloud AWS与Spring Boot一起使用时,包括自动配置的依赖是非常有用的。然后你需要配置Spring Cloud AWS,如 《Spring Cloud AWS参考指南》中所述。

解密纯文本

默认情况下,纯文本文件中的加密值不会被解密。为了启用纯文本文件的解密,请在 bootstrap.[yml|properties] 中设置 spring.cloud.config.server.encrypt.enabled=truespring.cloud.config.server.encrypt.plainTextEncrypt=true

解密纯文本文件只支持 YAML、JSON 和 properties 文件扩展名。

如果该功能被启用,并且请求一个不支持的文件扩展,文件中的任何加密值将不会被解密。

嵌入配置服务器

配置服务器最好作为一个独立的应用程序运行。然而,如果需要的话,你可以把它嵌入到另一个应用程序中。要做到这一点,请使用 @EnableConfigServer 注解。在这种情况下,一个名为 spring.cloud.config.server.bootstrap 的可选属性会很有用。它是一个标志,表示服务器是否应该从自己的远程资源库配置自己。默认情况下,该标志是关闭的,因为它可能延迟启动。然而,当嵌入到另一个应用程序中时,以与其他应用程序相同的方式初始化是有意义的。当设置 spring.cloud.config.server.bootstraptrue 时,你还必须使用 复合 environment repository配置。例如

spring:
  application:
    name: configserver
  profiles:
    active: composite
  cloud:
    config:
      server:
        composite:
          - type: native
            search-locations: ${HOME}/Desktop/config
        bootstrap: true
如果你使用 bootstrap 标志,配置服务器需要在 bootstrap.yml 中配置其名称和仓库 URI。

要改变服务器端点的位置,你可以(选择性地)设置 spring.cloud.config.server.prefix(例如,/config),以在一个前缀下提供资源。该前缀应以 / 开头,但不以 / 结尾。它被应用于配置服务器中的 @RequestMappings(即在 Spring Boot server.servletPathserver.contextPath 的前缀之下)。

如果你想直接从后端仓库(而不是从配置服务器)读取应用程序的配置,你基本上想要一个没有端点的嵌入式配置服务器。你可以通过不使用 @EnableConfigServer 注解(设置 spring.cloud.config.server.bootstrap=true)完全关闭端点。

推送通知和 Spring Cloud Bus

许多源代码库提供商(如Github、Gitlab、Gitea、Gitee、Gogs或Bitbucket)通过webhook通知你库中的变化。你可以通过供应商的用户界面将webhook配置为一个URL和一组你感兴趣的事件。例如, Github 使用POST向webhook发送一个包含提交列表的JSON body 和一个设置为 push 的头(X-Github-Event)。如果你添加了对 spring-cloud-config-monitor 库的依赖,并在你的配置服务器中激活了Spring Cloud Bus,那么就会启用 /monitor 端点。

当 webhook 被激活时,配置服务器会向它认为可能发生变化的应用程序发送一个 RefreshRemoteApplicationEvent。变化检测可以是战略性的。然而,默认情况下,它寻找与应用程序名称相匹配的文件中的变化(例如,foo.properties 是针对 foo 应用程序的,而 application.properties 是针对所有应用程序的)。当你想覆盖该行为时,要使用的策略是 PropertyPathNotificationExtractor,它接受请求 header 和 body 作为参数,并返回一个变化的文件路径列表。

默认配置可以在Github、Gitlab、Gitea、Gitee、Gogs或Bitbucket中使用。除了来自Github、Gitlab、Gitee或Bitbucket的JSON通知外,你还可以通过向 /monitor 发送带有表单编码的 body 参数的 path={application} 模式来触发变更通知。这样做是为了向与 {application} 模式相匹配的应用程序进行广播(可以包含通配符)。

只有当配置服务器和客户端应用程序中的 spring-cloud-bus 都被激活时,才会传输 RefreshRemoteApplicationEvent
默认配置也会检测本地git仓库的文件系统变化。在这种情况下,不使用webhook。然而,只要你编辑一个配置文件,就会有一个 refresh 广播。

AOT和原生镜像的支持

4.0.0 以来,Spring Cloud Config Server 支持 Spring AOT 转换。然而,目前还不支持GraalVM的原生镜像。实现原生镜像支持被 graal#5134 所阻挡,很可能需要完成 https://github.com/graalvm/taming-build-time-initialization 的工作才能得到修复。

Spring Cloud Config 客户端

Spring Boot 应用程序可以立即利用 Spring 配置服务器(或由应用程序开发人员提供的其他外部属性源)。它还可以获得一些与 Environment 变化事件有关的额外的有用功能。

Spring Boot 配置数据导入

Spring Boot 2.4引入了一种通过 spring.config.import 属性导入配置数据的新方法。现在,这是与配置服务器绑定的默认方式。

要选择性地连接到配置服务器,请在 application.properties 中设置以下内容:

application.properties
spring.config.import=optional:configserver:

这将在 "http://localhost:8888" 的默认位置连接到配置服务器。删除 optional: 前缀将导致配置客户端在无法连接到配置服务器时失败。要改变配置服务器的位置,可以设置 spring.cloud.config.uri 或在 spring.config.import 语句中添加url,如 spring.config.import=optional:configserver:http://myhost:8888。import 属性中的位置优先于 uri 属性。

通过 spring.config.import 导入的 Spring Boot 配置数据方法不需要一个 bootstrap 文件(properties 或 yaml)。

Config First Bootstrap

要使用传统的 bootstrap 方式连接到配置服务器,必须通过一个属性或 spring-cloud-starter-bootstrap starter 启用 bootstrap。该属性是 spring.cloud.bootstrap.enabled=true。它必须被设置为系统属性或环境变量。一旦启用bootstrap,classpath上有Spring Cloud Config Client的任何应用程序将按如下方式连接到配置服务器: 当配置客户端启动时,它会绑定到配置服务器(通过 spring.cloud.config.uri bootstrap 配置属性)并使用远程属性源初始化 Spring Environment

这种行为的结果是,所有想要使用配置服务器的客户端应用程序都需要一个 bootstrap.yml(或一个环境变量),其服务器地址设置在 spring.cloud.config.uri(默认为 "http://localhost:8888")。

Discovery First Lookup

除非你使用 config first bootstrap,否则你需要在配置属性中设置一个 spring.config.import 属性,并加上 optional: 前缀。例如,spring.config.import=optional:configserver:

如果你使用 DiscoveryClient 实现,如 Spring Cloud Netflix 和 Eureka Service Discovery 或 Spring Cloud Consul,你可以让配置服务器向 Discovery 服务注册。

如果你喜欢使用 DiscoveryClient 来定位配置服务器,你可以通过设置 spring.cloud.config.discovery.enabled=true(默认是 false)来实现。例如,使用Spring Cloud Netflix,你需要定义Eureka服务器地址(例如,在 eureka.client.serviceUrl.defaultZone 中)。使用这个选项的代价是在启动时要进行额外的网络往返,以定位服务注册。其好处是,只要 discovery 服务是一个固定点,配置服务器就可以改变其坐标。默认的服务 ID 是 configserver,但你可以在客户端通过设置 spring.cloud.config.discovery.serviceId 来改变它(而在服务器上,以服务的通常方式,如设置 spring.application.name)。

discovery 客户端的实现都支持某种元数据映射(例如,我们有 Eureka.instance.metadataMap 用于Eureka)。配置服务器的一些额外属性可能需要在其服务注册元数据中进行配置,以便客户端能够正确连接。如果配置服务器用 HTTP Basic 来保证安全,你可以将凭证配置为 userpassword。另外,如果配置服务器有一个 context path,你可以设置 configPath。例如,下面的YAML文件是针对作为 Eureka 客户端的配置服务器的:

eureka:
  instance:
    ...
    metadataMap:
      user: osufhalskjrtl
      password: lviuhlszvaorhvlo5847
      configPath: /config

使用 Eureka 和 WebClient 的 Discovery First Bootstrap

如果你使用 Spring Cloud Netflix 的 Eureka DiscoveryClient,并且想使用 WebClient 而不是 JerseyRestTemplate,你需要在 classpath 上包含 WebClient,并设置 eureka.client.webclient.enabled=true

配置客户端快速失败

在某些情况下,如果服务不能连接到配置服务器,你可能想让它启动失败。如果这是需要的行为,请设置 bootstrap 配置属性 spring.cloud.config.fail-fast=true,使客户端以异常停止。

要使用 spring.config.import 获得类似的功能,只需省略 optional: 前缀。

配置客户重试

如果你预计配置服务器在你的应用程序启动时可能偶尔不可用,你可以让它在失败后继续尝试。首先,你需要设置 spring.cloud.config.fail-fast=true。然后你需要将 spring-retryspring-boot-starter-aop 添加到你的 classpath。默认行为是重试六次,初始退避间隔为1000ms,后续退避的指数乘数为1.1。你可以通过设置 spring.cloud.config.retry.* 配置属性来配置这些属性(以及其他属性)。

要想完全控制重试行为,并且使用传统的 bootstrap,请添加一个 RetryOperationsInterceptor 类型的 @Bean,ID为 configServerRetryInterceptor。Spring Retry有一个 RetryInterceptorBuilder,支持创建一个。

用 spring.config.import 配置客户端重试

重试在 Spring Boot 的 spring.config.import 语句中起作用,正常的 properties 也起作用。但是,如果 import 语句是在配置文件中,比如 application-prod.properties,那么你需要用不同的方式来配置重试。配置需要作为url参数放在 import 语句中。

application-prod.properties
spring.config.import=configserver:http://configserver.example.com?fail-fast=true&max-attempts=10&max-interval=1500&multiplier=1.2&initial-interval=1100"

这将设置 spring.cloud.config.fail-fast=true(注意上面缺少前缀)和所有可用的 spring.cloud.config.retry.* 配置属性。

定位远程配置资源

配置服务为来自 /{application}/{profile}/{label} 的属性源提供服务,其中客户端应用程序的默认绑定如下:

  • "application" = ${spring.application.name}

  • "profile" = ${spring.profiles.active} (实际上是 Environment.getActiveProfiles())

  • "label" = "master"

当设置属性 ${spring.application.name} 时,不要在你的应用程序名称前加上保留词 application-,以防止在解析正确的属性源时出现问题。

你可以通过设置 spring.cloud.config.*(其中 *nameprofilelabel)来覆盖所有的配置。label 对于回滚到以前版本的配置非常有用。在默认的配置服务器实现中,它可以是一个 git label、分支名称或提交ID。label 也可以以逗号分隔的列表形式提供。在这种情况下,列表中的项目会被逐一尝试,直到有一个成功。这种行为在处理一个特性分支时很有用。例如,你可能想让配置 label 与你的分支保持一致,但让它成为可选项(在这种情况下,使用 spring.cloud.config.label=myfeature,develop)。

为配置服务器指定多个URL

当你部署了多个配置服务器实例,并且预计一个或多个实例会时常不可用或无法满足请求时(比如Git服务器宕机),为了确保高可用性,你可以指定多个URL(在 spring.cloud.config.uri 属性下以逗号分隔的列表形式)或让所有实例在Eureka等服务注册中心注册(如果使用 Discovery-First Bootstrap 模式)。

spring.cloud.config.uri 下列出的 URL 将按照列出的顺序进行尝试。默认情况下,配置客户端将尝试从每个URL获取属性,直到尝试成功,以确保高可用性。

但是,如果你只想在配置服务器不运行(即应用程序已退出)或发生连接超时时确保高可用性,请将 spring.cloud.config.multiple-uri-strategy 设置为 connection-timeout-only。(spring.cloud.config.multiple-uri-strategy 的默认值是 always。)例如,如果配置服务器返回500(内部服务器错误)响应或配置客户端从配置服务器收到401(由于凭证错误或其他原因),配置客户端不会尝试从其他URL获取属性。400错误(可能是404除外)表明是用户问题而不是可用性问题。注意,如果配置服务器被设置为使用Git服务器,而调用Git服务器失败,可能会出现404错误。

可以在一个 spring.config.import key 下指定多个位置,而不是 spring.cloud.config.uri。位置将按照它们被定义的顺序进行处理,后面的导入优先。但是,如果 spring.cloud.config.fail-fasttrue,如果第一次配置服务器调用因任何原因而不成功,配置客户端将失败。如果 fail-fastfalse,它将尝试所有的URL,直到有一个调用成功,不管失败的原因是什么。(spring.cloud.config.multiple-uri-strategy 不适用于在 spring.config.import 下指定URL的情况)。

如果你在配置服务器上使用 HTTP basic security,目前只有在你将凭证嵌入你在 spring.cloud.config.uri 属性下指定的每个 URL 中时,才可能支持每个配置服务器的认证凭证。如果你使用任何其他类型的安全机制,你(目前)无法支持每台配置服务器的认证和授权。

配置超时

如果你想配置超时阈值:

  • 读取超时可以通过使用属性 spring.cloud.config.request-read-timeout 进行配置。

  • 连接超时可以通过使用属性 spring.cloud.config.request-connect-timeout 进行配置。

安全

如果你在服务器上使用 HTTP Basic security,客户需要知道密码(如果不是默认的,还需要知道用户名)。你可以通过配置服务器URI或通过单独的用户名和密码属性来指定用户名和密码,如下面的例子中所示:

spring:
  cloud:
    config:
     uri: https://user:secret@myconfig.mycompany.com

下面的例子显示了传递相同信息的另一种方式:

spring:
  cloud:
    config:
     uri: https://myconfig.mycompany.com
     username: user
     password: secret

spring.cloud.config.passwordspring.cloud.config.username 的值会覆盖 URI 中提供的任何内容。

如果你在 Cloud Foundry 上部署应用程序,提供密码的最佳方式是通过服务凭证(如 URI 中,因为它不需要在配置文件中)。以下示例适用于本地和 Cloud Foundry 上用户提供的名为 configserver 的服务:

spring:
  cloud:
    config:
     uri: ${vcap.services.configserver.credentials.uri:http://user:password@localhost:8888}

如果配置服务器需要客户端的TLS证书,你可以通过 properties 配置客户端的 TLS 证书和 trust store,如下面的例子所示:

spring:
  cloud:
    config:
      uri: https://myconfig.myconfig.com
      tls:
        enabled: true
        key-store: <path-of-key-store>
        key-store-type: PKCS12
        key-store-password: <key-store-password>
        key-password: <key-password>
        trust-store: <path-of-trust-store>
        trust-store-type: PKCS12
        trust-store-password: <trust-store-password>

spring.cloud.config.tls.enabled 需要为 true,以启用配置客户端TLS。当 spring.cloud.config.tls.trust-store 被省略时,会使用JVM默认的trust store。spring.cloud.config.tls.key-store-typespring.cloud.config.tls.trust-store-type 的默认值是 PKCS12。当 password 属性被省略时,将假定为空 password。

如果你使用另一种形式的安全,你可能需要向 ConfigServicePropertySourceLocator 提供一个 RestTemplate(例如,通过在 bootstrap 上下文中抓取并注入它)。

健康指标

配置客户端提供了一个 Spring Boot 健康指示器,试图从配置服务器加载配置。可以通过设置 health.config.enabled=false 来禁用该健康指标。出于性能原因,响应也会被缓存。默认的缓存生存时间是5分钟。要改变该值,请设置 health.config.time-to-live 属性(单位:毫秒)。

提供一个自定义的 RestTemplate

在某些情况下,你可能需要定制从客户端向配置服务器发出的请求。通常情况下,这样做涉及传递特殊的 Authorization header 信息,以验证对服务器的请求。

使用配置数据提供一个自定义RestTemplate

在使用配置数据时,要提供一个自定义的 RestTemplate

  1. 创建一个实现了 BootstrapRegistryInitializer 的类

    CustomBootstrapRegistryInitializer.java
    public class CustomBootstrapRegistryInitializer implements BootstrapRegistryInitializer {
    
    	@Override
    	public void initialize(BootstrapRegistry registry) {
    		registry.register(RestTemplate.class, context -> {
    			RestTemplate restTemplate = new RestTemplate();
    			// Customize RestTemplate here
    			return restTemplate;
    		});
    	}
    
    }
    
  2. resources/META-INF 中,创建一个名为 spring.factories 的文件,并指定你的自定义配置,如下例所示:

    spring.factories
    org.springframework.boot.BootstrapRegistryInitializer=com.my.config.client.CustomBootstrapRegistryInitializer
使用 Bootstrap 提供一个自定义 RestTemplate

在使用 Bootstrap 时,要提供一个自定义的 RestTemplate

  1. 创建一个具有 PropertySourceLocator 实现的新配置bean,如下例所示:

    CustomConfigServiceBootstrapConfiguration.java
    @Configuration
    public class CustomConfigServiceBootstrapConfiguration {
        @Bean
        public ConfigServicePropertySourceLocator configServicePropertySourceLocator() {
            ConfigClientProperties clientProperties = configClientProperties();
           ConfigServicePropertySourceLocator configServicePropertySourceLocator =  new ConfigServicePropertySourceLocator(clientProperties);
            configServicePropertySourceLocator.setRestTemplate(customRestTemplate(clientProperties));
            return configServicePropertySourceLocator;
        }
    }
    
    对于添加 Authorization header 的简化方法,可以使用 spring.cloud.config.headers.* 属性来代替。
  2. resources/META-INF 中,创建一个名为 spring.factories 的文件,并指定你的自定义配置,如下例所示:

    spring.factories
    org.springframework.cloud.bootstrap.BootstrapConfiguration = com.my.config.client.CustomConfigServiceBootstrapConfiguration

Vault

当使用Vault作为配置服务器的后端时,客户端需要为服务器提供一个 Token,以便从Vault检索值。这个Token可以通过在 bootstrap.yml 中设置 spring.cloud.config.token 在客户端中提供,如以下例子所示:

spring:
  cloud:
    config:
      token: YourVaultToken

Vault中的嵌套key

Vault支持在存储在Vault中的值中嵌套key的能力,如下面的例子所示:

echo -n '{"appA": {"secret": "appAsecret"}, "bar": "baz"}' | vault write secret/myapp -

这个命令会将一个JSON对象写入你的Vault中。要在Spring中访问这些值,你可以使用传统的dot(.)注解,如以下例子所示

@Value("${appA.secret}")
String name = "World";

前面的代码将设置 name 变量的值为 appAsecret

AOT 和原生镜像的支持

4.0.0 开始,Spring Cloud Config Client 支持 Spring AOT 转换和 GraalVM 原生镜像。

AOT和原生镜像支持不适用于 config first bootstrap(使用 spring.config.use-legacy-processing=true)。
Refresh scope 不支持原生镜像。如果你打算将你的配置客户端应用程序作为一个原生镜像运行,确保将 spring.cloud.refresh.enabled 属性设置为 false
在构建包含Spring Cloud Config Client的项目时,你必须确保它所连接的配置数据源(如Spring Cloud Config Server、Consul、Zookeeper、Vault等)是可用的。例如,如果你从Spring Cloud Config Server检索配置数据,请确保它的实例正在运行,并且在Config Client设置中指定的端口可用。这是必要的,因为应用程序上下文在构建时被优化,需要解析目标 environment。
由于在AOT和原生模式中,配置正在被处理,并且在构建时对上下文进行了优化,任何会影响Bean创建的属性(比如在bootstrap上下文中使用的属性)都应该在构建时和运行时被设置为相同的值,以避免出现意外行为。
由于Config Client在从本地镜像启动时连接到正在运行的数据源(如Config Server),快速启动时间将因该网络通信所需时间而减慢。

附录

可观察性元数据

Observability - Metrics

Below you can find a list of all metrics declared by this project.

Environment Repository

Observation created around an EnvironmentRepository.

Metric name spring.cloud.config.environment.find (defined by convention class org.springframework.cloud.config.server.environment.ObservationEnvironmentRepositoryObservationConvention). Type timer.

Metric name spring.cloud.config.environment.find.active (defined by convention class org.springframework.cloud.config.server.environment.ObservationEnvironmentRepositoryObservationConvention). Type long task timer.

KeyValues that are added after starting the Observation might be missing from the *.active metrics.
Micrometer internally uses nanoseconds for the baseunit. However, each backend determines the actual baseunit. (i.e. Prometheus uses seconds)

Fully qualified name of the enclosing class org.springframework.cloud.config.server.environment.DocumentedConfigObservation.

All tags must be prefixed with spring.cloud.config.environment prefix!
Table 4. Low cardinality Keys

Name

Description

spring.cloud.config.environment.application (required)

Application name for which properties are being queried for.

spring.cloud.config.environment.class (required)

Implementation of the EnvironmentRepository.

spring.cloud.config.environment.label (required)

Label for which properties are being queried for.

spring.cloud.config.environment.profile (required)

Application name for which properties are being queried for.

Observability - Spans

Below you can find a list of all spans declared by this project.

Environment Repository Span

Observation created around an EnvironmentRepository.

Span name spring.cloud.config.environment.find (defined by convention class org.springframework.cloud.config.server.environment.ObservationEnvironmentRepositoryObservationConvention).

Fully qualified name of the enclosing class org.springframework.cloud.config.server.environment.DocumentedConfigObservation.

All tags must be prefixed with spring.cloud.config.environment prefix!
Table 5. Tag Keys

Name

Description

spring.cloud.config.environment.application (required)

Application name for which properties are being queried for.

spring.cloud.config.environment.class (required)

Implementation of the EnvironmentRepository.

spring.cloud.config.environment.label (required)

Label for which properties are being queried for.

spring.cloud.config.environment.profile (required)

Application name for which properties are being queried for.