10. Spring Cloud Config Client

Spring Boot application 可以立即利用 Spring Config Server(或 application 开发人员提供的其他外部 property 源)。它还会获得与Environment change events 相关的一些其他有用的 features。

10.1 Config First Bootstrap

在 classpath 上具有 Spring Cloud Config Client 的任何 application 的默认行为如下:当 config client 启动时,它绑定到 Config Server(通过spring.cloud.config.uri bootstrap configuration property)并使用 remote property 源初始化 Spring Environment

此行为的最终结果是,所有想要使用配置服务器的 client 应用程序都需要bootstrap.yml(或环境变量),其服务器地址在spring.cloud.config.uri中设置(默认为“http://localhost:8888”)。

10.2 Discovery First Bootstrap

如果您使用`DiscoveryClient implementation,例如 Spring Cloud Netflix 和 Eureka Service Discovery 或 Spring Cloud Consul,您可以让 Config Server 注册 Discovery Service。但是,在默认的“Config First”模式下,clients 无法利用注册。

如果您更喜欢使用DiscoveryClient来定位配置服务器,可以通过设置spring.cloud.config.discovery.enabled=true(默认为false)来实现。这样做的最终结果是 client applications 都需要具有适当发现 configuration 的bootstrap.yml(或环境变量)。对于 example,使用 Spring Cloud Netflix,您需要定义 Eureka 服务器地址(对于 example,在eureka.client.serviceUrl.defaultZone中)。使用此选项的价格是启动时额外的网络往返,以查找服务注册。好处是,当 Discovery Service 是一个固定点时,Config Server 可以更改其坐标。默认服务 ID 是configserver,但您可以通过设置spring.cloud.config.discovery.serviceId(在服务器上,以通常的方式设置服务,例如通过设置spring.application.name)来更改 client 上的服务 ID。

发现 client implementations 都支持某种元数据 map(对于 example,_E用于 Eureka)。可能需要在其服务注册元数据中配置 Config Server 的一些其他 properties,以便 clients 可以正确连接。如果使用 HTTP Basic 保护 Config Server,则可以将凭据配置为usernamepassword。此外,如果 Config Server 具有 context 路径,则可以设置configPath。对于 example,以下 YAML 文件用于 Eureka client 的 Config Server:

bootstrap.yml.

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

10.3 配置 Client 快速失败

在某些情况下,如果服务无法连接到 Config Server,您可能希望无法启动服务。如果这是所需的行为,请设置 bootstrap configuration property spring.cloud.config.fail-fast=true以使 client 停止并返回 Exception。

10.4 配置 Client 重试

如果您希望在 application 启动时配置服务器偶尔不可用,您可以在失败后继续尝试。首先,您需要设置spring.cloud.config.fail-fast=true。然后你需要将spring-retryspring-boot-starter-aop添加到 classpath。默认行为是重试六次,初始退避间隔为 1000 毫秒,指数乘数为 1.1,用于后续退避。您可以通过设置spring.cloud.config.retry.* configuration properties 来配置这些 properties(和其他)。

要完全控制重试行为,请添加@Bean类型RetryOperationsInterceptor,ID 为configServerRetryInterceptor。 Spring Retry 有RetryInterceptorBuilder支持 creating one。

10.5 查找 Remote Configuration 资源

Config Service 从/{name}/{profile}/{label}提供 property 源,其中 client 应用程序中的默认绑定如下:

  • “name”= ${spring.application.name}

  • “profile”= ${spring.profiles.active}(实际Environment.getActiveProfiles())

  • “label”=“ master”

设置 property ${spring.application.name}时,不要在 app name 前加上保留字application-,以防止问题解决正确的 property 源。

您可以通过设置spring.cloud.config.*(其中*nameprofilelabel)来覆盖所有这些。 label对于回滚到以前版本的 configuration 非常有用。使用默认的 Config Server implementation,它可以是 git 标签,分支 name 或提交 ID。标签也可以作为 comma-separated 列表提供。在这种情况下,列表中的项目将逐个尝试,直到成功为止。在 feature 分支上工作时,此行为很有用。例如,您可能希望将配置标签与分支对齐,但使其成为可选(在这种情况下,请使用spring.cloud.config.label=myfeature,develop)。

10.6 为 Config Server 指定多个 URL

要在部署了多个 Config Server 实例并且期望一个或多个实例从 time 到 time 不可用时确保高可用性,您可以指定多个 URL(作为spring.cloud.config.uri property 下的 comma-separated 列表)或者让所有实例都注册像 Eureka 这样的服务注册表(如果使用 Discovery-First Bootstrap 模式)。请注意,只有在 Config Server 未运行时(即,application 退出时)或发生连接超时时,才能确保高可用性。例如,如果 Config Server 返回 500(内部服务器错误)响应或 Config Client 从 Config Server 收到 401(由于凭据错误或其他原因),则 Config Client 不会尝试从其他 URL 获取 properties。这种错误表示用户问题而不是可用性问题。

如果在 Config Server 上使用 HTTP 基本安全性,则仅当您在spring.cloud.config.uri property 下指定的每个 URL 中嵌入凭据时,才能支持 per-Config Server 身份验证凭据。如果您使用任何其他类型的安全机制,则不能(当前)支持 per-Config Server 身份验证和授权。

10.7 配置读取超时

如果要配置读取超时,可以使用 property spring.cloud.config.request-read-timeout来完成。

10.8 安全

如果您在服务器上使用 HTTP Basic 安全性,客户端需要知道密码(如果不是默认用户名,则需要知道用户名)。您可以通过配置服务器 URI 或通过单独的用户名和密码 properties 指定用户名和密码,如以下 example 所示:

bootstrap.yml.

spring:
  cloud:
    config:
     uri: https://user:[emailprotected]

以下 example 显示了传递相同信息的另一种方法:

bootstrap.yml.

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

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

如果您在 Cloud Foundry 上部署应用程序,提供密码的最佳方式是通过服务凭据(例如在 URI 中,因为它不需要在配置文件中)。以下 example 在本地工作,而 Cloud Foundry 上的 user-provided 服务名为configserver

bootstrap.yml.

spring:
  cloud:
    config:
     uri: ${vcap.services.configserver.credentials.uri:http://user:[emailprotected]:8888}

如果您使用其他形式的安全性,则可能需要提供 RestTemplateConfigServicePropertySourceLocator(对于 example,通过在 bootstrap context 中抓取它并注入它)。

10.8.1 健康指标

Config Client 提供 Spring Boot 运行状况指示器,尝试从 Config Server 加载 configuration。可以通过设置health.config.enabled=false来禁用运行状况指示器。出于性能原因,还会缓存响应。要生存的默认缓存 time 是 5 分钟。要更改该 value,请设置health.config.time-to-live property(以毫秒为单位)。

10.8.2 提供自定义 RestTemplate

在某些情况下,您可能需要自定义从 client 对配置服务器发出的请求。通常,这样做涉及传递特殊的Authorization headers 来验证对服务器的请求。要提供自定义RestTemplate

  • 使用PropertySourceLocator的 implementation 创建一个新的 configuration 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;
    }
}
  • resources/META-INF中,创建一个名为spring.factories的文件并指定自定义配置,如下面的示例所示:

spring.factories.

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

10.8.3 Vault

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

bootstrap.yml.

spring:
  cloud:
    config:
      token: YourVaultToken

10.9 Vault 中的嵌套键

Vault 支持在 Vault 中存储的 value 中嵌套键的功能,如下面的示例所示:

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

此命令将 JSON object 写入 Vault。要在 Spring 中访问这些值,您可以使用传统的点(.)注释,如下面的 example 所示

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

前面的 code 会将name变量的 value 设置为appAsecret