Spring Cloud Config 客戶端

Spring Boot 應用程式可以直接利用 Spring Config Server(或應用程式開發者提供的其他外部屬性源)的優勢。它還獲得了一些與 Environment 更改事件相關的額外有用特性。

Spring Boot Config Data 匯入

Spring Boot 2.4 引入了一種透過 spring.config.import 屬性匯入配置資料的新方式。這現在是繫結到 Config Server 的預設方式。

要選擇性地連線到 Config Server,請在 application.properties 中設定以下內容

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

這將連線到預設位置 "https://:8888" 的 Config Server。移除 optional: 字首將導致 Config Client 在無法連線到 Config Server 時失敗。要更改 Config Server 的位置,可以設定 spring.cloud.config.uri 或將 URL 新增到 spring.config.import 語句中,例如 spring.config.import=optional:configserver:http://myhost:8888。import 屬性中的位置優先於 uri 屬性。

Spring Boot Config Data 透過兩個步驟解析配置。首先,它使用 default 配置檔案載入所有配置。這使得 Spring Boot 可以收集所有可能啟用任何額外配置檔案的配置。在收集所有啟用的配置檔案後,它將載入活動配置檔案的任何額外配置。因此,您可能會看到向 Spring Cloud Config Server 傳送多個請求以獲取配置。這是正常的,也是在使用 spring.config.import 時 Spring Boot 載入配置的方式的副作用。在 Spring Cloud Config 的早期版本中,只進行一次請求,但這表示您無法從 Config Server 的配置中啟用配置檔案。現在透過僅包含 default 配置檔案的額外請求,這成為了可能。

透過 spring.config.import 進行 Spring Boot Config Data 匯入的方��不需要 bootstrap 檔案(properties 或 yaml)。

配置優先 Bootstrap

要使用傳統的 bootstrap 方式連線到 Config Server,必須透過屬性或 spring-cloud-starter-bootstrap 啟動器啟用 bootstrap。屬性為 spring.cloud.bootstrap.enabled=true。它必須設定為系統屬性或環境變數。啟用 bootstrap 後,任何類路徑中包含 Spring Cloud Config Client 的應用程式都將按如下方式連線到 Config Server:Config client 啟動時,它會繫結到 Config Server(透過 spring.cloud.config.uri bootstrap 配置屬性)並使用遠端屬性源初始化 Spring Environment

這種行為的最終結果是,所有想要使用 Config Server 的客戶端應用程式都需要一個 bootstrap.yml(或環境變數),並在其中設定 spring.cloud.config.uri 中的伺服器地址(預設為 "https://:8888")。

發現優先查詢

除非您使用配置優先 Bootstrap,否則您需要在配置屬性中使用 optional: 字首設定 spring.config.import 屬性。例如,spring.config.import=optional:configserver:

如果您使用 DiscoveryClient 實現,例如 Spring Cloud Netflix 和 Eureka Service Discovery 或 Spring Cloud Consul,您可以讓 Config Server 在 Discovery Service 中註冊。

如果您更喜歡使用 DiscoveryClient 來定位 Config Server,您可以透過設定 spring.cloud.config.discovery.enabled=true(預設為 false)來實現。例如,對於 Spring Cloud Netflix,您需要定義 Eureka 伺服器地址(例如,在 eureka.client.serviceUrl.defaultZone 中)。使用此選項的代價是在啟動時需要額外的網路往返來定位服務註冊。好處是,只要 Discovery Service 是一個固定點,Config Server 就可以更改其座標。預設的服務 ID 是 configserver,但您可以在客戶端透過設定 spring.cloud.config.discovery.serviceId(以及在伺服器上,以服務通常的方式,例如透過設定 spring.application.name)來更改它。

發現客戶端實現都支援某種元資料對映(例如,Eureka 有 eureka.instance.metadataMap)。Config Server 的一些額外屬性可能需要在其服務註冊元資料中配置,以便客戶端能夠正確連線。如果 Config Server 使用 HTTP Basic 保護,您可以將憑據配置為 userpassword。此外,如果 Config Server 有一個上下文路徑,您可以設定 configPath。例如,以下 YAML 檔案適用於作為 Eureka 客戶端的 Config Server

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

使用 Eureka 和 WebClient 的發現優先 Bootstrap

如果您使用 Spring Cloud Netflix 的 Eureka DiscoveryClient,並且還想使用 WebClient 而不是 Jersey 或 RestTemplate,您需要在類路徑中包含 WebClient,並設定 eureka.client.webclient.enabled=true

Config 客戶端快速失敗

在某些情況下,如果服務無法連線到 Config Server,您可能希望其啟動失敗。如果這是期望的行為,請設定 bootstrap 配置屬性 spring.cloud.config.fail-fast=true,使客戶端丟擲異常並停止。

要使用 spring.config.import 獲得類似的功能,只需省略 optional: 字首。

Config 客戶端重試

如果您預計 config server 在應用程式啟動時可能偶爾不可用,您可以讓它在失敗後繼續嘗試。首先,您需要設定 spring.cloud.config.fail-fast=true。然後您需要在類路徑中新增 spring-retryspring-boot-starter-aop。預設行為是重試六次,初始回退間隔為 1000ms,後續回退使用 1.1 的指數乘數。您可以透過設定 spring.cloud.config.retry.* 配置屬性來配置這些屬性(及其他屬性)。要使用隨機指數回退策略,請將 spring.cloud.config.retry.useRandomPolicy 設定為 true

spring.cloud.config.retry.useRandomPolicytrue 時,即使使用隨機指數回退策略,max-attemptsinitial-intervalmax-intervalmultiplier 屬性仍會生效。關於它們如何使用的詳細資訊可以在 Spring Retry 中的 ExponentialRandomBackOffPolicyExponentialBackOffPolicy 中找到。
要完全控制重試行為並使用傳統的 bootstrap,請新增一個型別為 RetryOperationsInterceptor 且 ID 為 configServerRetryInterceptor@Bean。Spring Retry 有一個 RetryInterceptorBuilder 支援建立此類 Bean。

使用 spring.config.import 的 Config 客戶端重試

重試功能適用於 Spring Boot 的 spring.config.import 語句和常規屬性。但是,如果 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.* 配置屬性。

定位遠端配置資源

Config Service 從 /{application}/{profile}/{label} 提供屬性源,客戶端應用程式中的預設繫結如下

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

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

  • "label" = "master"

設定屬性 ${spring.application.name} 時,請勿在應用程式名稱前加上保留字 application-,以避免解析到錯誤的屬性源。

您可以透過設定 spring.cloud.config.*(其中 *nameprofilelabel)來覆蓋所有這些值。label 對於回滾到以前的配置版本非常有用。對於預設的 Config Server 實現,它可以是 git 標籤、分支名稱或提交 ID。Label 也可以提供為逗號分隔的列表。當處理特性分支時,這種行為非常有用。例如,您可能希望將 config label 與您的分支對齊,但使其成為可選的(在這種情況下,請使用 spring.cloud.config.label=myfeature,develop)。

請求多個標籤

在 Spring Cloud Config 4.2.0 之前,如果您將 spring.cloud.config.label 設定為逗號分隔的標籤列表,Config Client 會嘗試透過向 Config Server 發出請求來逐個嘗試每個標籤,直到找到一個可用的標籤。這意味著如果找到第一個標籤,後續標籤將不再嘗試。

自 Spring Cloud Config 4.2.0 起,如果您將 spring.cloud.config.label 設定為逗號分隔的標籤列表並且設定 spring.cloud.config.send-all-labels,Config Client 將使用逗號分隔的標籤列表向 Config Server 發出單個請求,如果 CONFIG SERVER 使用 4.2.0 或更高版本,它將返回一個包含所有標籤屬性源的單個響應。

spring.cloud-config.send-all-labels 設定為 true,將 spring.cloud.config.label 設定為逗號分隔的標籤列表,並使用早於 4.2.0 版本的 Config Server 將導致意外行為,因為 Config Server 會嘗試查詢與逗號分隔列表值匹配的標籤,而不會嘗試拆分標籤。

透過在單個請求中傳送所有標籤,可以減少向 Config Server 發出的請求數量。

spring.cloud.config.send-all-labels 預設設定為 false,因此舊的行為仍然是預設行為,並且它還保持與舊版本 Config Server 的相容性。

指定 Config Server 的多個 URL

為了在高可用性部署多個 Config Server 例項並預計一個或多個例項有時不可用或無法響應請求(例如 Git 伺服器宕機),您可以指定多個 URL(在 spring.cloud.config.uri 屬性下以逗號分隔的列表形式)或者讓所有例項在 Eureka 等服務註冊中心註冊(如果使用發現優先 Bootstrap 模式)。

spring.cloud.config.uri 下列出的 URL 將按列表中的順序嘗試。預設情況下,Config Client 會嘗試從每個 URL 獲取屬性,直到嘗試成功以確保高可用性。

但是,如果您只想在 Config Server 未執行時(即應用程式已退出)或發生連線超時時確保高可用性,請將 spring.cloud.config.multiple-uri-strategy 設定為 connection-timeout-only。(spring.cloud.config.multiple-uri-strategy 的預設值為 always。)例如,如果 Config Server 返回 500(內部伺服器錯誤)響應,或 Config Client 從 Config Server 收到 401(由於憑據錯誤或其他原因),Config Client 不會嘗試從其他 URL 獲取屬性。400 錯誤(可能除了 404)表示使用者問題而不是可用性問題。請注意,如果 Config Server 設定為使用 Git 伺服器且呼叫 Git 伺服器失敗,可能會發生 404 錯誤。

可以在單個 spring.config.import 鍵下指定多個位置,而不是使用 spring.cloud.config.uri。位置將按照它們定義的順序處理,後匯入的優先。但是,如果 spring.cloud.config.fail-fasttrue,如果第一次呼叫 Config Server 因任何原因失敗,Config Client 將失敗。如果 fail-fastfalse,它將嘗試所有 URL,直到一次呼叫成功為止,無論失敗原因如何。(在使用 spring.config.import 下指定 URL 時,spring.cloud.config.multiple-uri-strategy 不適用。)

如果您在 Config Server 上使用 HTTP basic security,目前只有在您將憑據嵌入到您在 spring.cloud.config.uri 屬性下指定的每個 URL 中時,才可能支援每個 Config Server 的身份驗證憑據。如果您使用任何其他型別的安全機制,您目前無法支援每個 Config Server 的身份驗證和授權。

配置超時

如果您想配置超時閾值

  • 可以透過使用屬性 spring.cloud.config.request-read-timeout 來配置讀取超時。

  • 可以透過使用屬性 spring.cloud.config.request-connect-timeout 來配置連線超時。

配置字元集

如果您想配置伺服器應提供的特定字元集,您需要透過 charset 應用它。

spring:
  cloud:
    config:
      charset: UTF-8

字元集配置屬性定義為 java.nio.charset.Charset

安全

如果在伺服器上使用 HTTP Basic security,客戶端需要知道密碼(如果不是預設使用者,還需要知道使用者名稱)。您可以透過 config server URI 或透過單獨的 username 和 password 屬性來指定使用者名稱和密碼,如下例所示

spring:
  cloud:
    config:
     uri: https://user:[email protected]

以下示例顯示了傳遞相同資訊的另一種方式

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}

如果 config server 需要客戶端 TLS 證書,您可以透過屬性配置客戶端 TLS 證書和信任庫,如下例所示

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 以啟用 config 客戶端 TLS。省略 spring.cloud.config.tls.trust-store 時,使用 JVM 預設信任庫。spring.cloud.config.tls.key-store-typespring.cloud.config.tls.trust-store-type 的預設值為 PKCS12。省略密碼屬性時,假定為空密碼。

如果您使用另一種安全形式,您可能需要為 ConfigServicePropertySourceLocator提供一個 RestTemplate(例如,在 bootstrap 上下文中獲取並注入它)。

健康指示器

Config Client 提供了一個 Spring Boot 健康指示器,它嘗試從 Config Server 載入配置。可以透過設定 health.config.enabled=false 來停用健康指示器。響應也會被快取以提高效能。預設的快取生存時間為 5 分鐘。要更改此值,請設定 health.config.time-to-live 屬性(以毫秒為單位)。

提供自定義 RestTemplate

在某些情況下,您可能需要自定義客戶端向 config server 發出的請求。通常,這涉及傳遞特殊的 Authorization 頭以驗證對伺服器的請求。

使用 Config Data 提供自定義 RestTemplate

在使用 Config Data 時提供自定義 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. 建立一個新的配置 Bean,實現 PropertySourceLocator,如下例所示

    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 頭的方法,可以使用 spring.cloud.config.headers.* 屬性代替。
  2. resources/META-INF 中,建立一個名為 spring.factories 的檔案,並指定您的自定義配置,如下例所示

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

Vault

將 Vault 用作 config server 的後端時,客戶端需要提供一個 token 供伺服器從 Vault 中檢索值。可以在客戶端透過在 bootstrap.yml 中設定 spring.cloud.config.token 來提供此 token,如下例所示

spring:
  cloud:
    config:
      token: YourVaultToken

Vault 中的巢狀金鑰

Vault 支援在儲存在 Vault 中的值內巢狀金鑰的功能,如下例所示

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

此命令將一個 JSON 物件寫入您的 Vault。要在 Spring 中訪問這些值,您將使用傳統的點(.)註解,如下例所示

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

上面的程式碼會將 name 變數的值設定為 appAsecret

AOT 和 Native Image 支援

4.0.0 起,Spring Cloud Config Client 支援 Spring AOT 轉換和 GraalVM native images。

配置優先 Bootstrap(使用 spring.config.use-legacy-processing=true)不支援 AOT 和 native image。
Native image 不支援 refresh scope。如果您打算將 config client 應用程式作為 native image 執行,請確保將 spring.cloud.refresh.enabled 屬性設定為 false
構建包含 Spring Cloud Config Client 的專案時,必須確保其連線的配置資料來源(例如 Spring Cloud Config Server、Consul、Zookeeper、Vault 等)可用。例如,如果您從 Spring Cloud Config Server 檢索配置資料,請確保其例項正在執行並可在 Config Client 設定中指示的埠訪問。這是必要的,因為應用程式上下文在構建時進行了最佳化,需要解析目標環境。
由於在 AOT 和 native 模式下,配置在構建時進行處理和上下文進行最佳化,因此任何影響 bean 建立的屬性(例如 bootstrap 上下文中的屬性)在構建時和執行時應設定為相同的值,以避免意外行為。
由於 Config Client 在從 native image 啟動時會連線到執行的資料來源(例如 Config Server),快速啟動時間會因網路通訊所需的時間而變慢。

附錄

可觀測性元資料

可觀測性 - 指標

您可以在下方找到此專案宣告的所有指標列表。

環境倉庫

在 EnvironmentRepository 周圍建立的觀測。

指標名稱 spring.cloud.config.environment.find(由約定類 org.springframework.cloud.config.server.environment.ObservationEnvironmentRepositoryObservationConvention 定義)。型別 timer

指標名稱 spring.cloud.config.environment.find.active(由約定類 org.springframework.cloud.config.server.environment.ObservationEnvironmentRepositoryObservationConvention 定義)。型別 long task timer

在啟動觀測後新增的 KeyValues 可能在 *.active 指標中缺失。
Micrometer 內部使用 nanoseconds 作為基本單位。但是,每個後端決定實際的基本單位。(即 Prometheus 使用 seconds)

包含類的完全限定名 org.springframework.cloud.config.server.environment.DocumentedConfigObservation

所有標籤必須以 spring.cloud.config.environment 字首開頭!
表 1. 低基數鍵

名稱

描述

spring.cloud.config.environment.application (必填)

查詢屬性的應用程式名稱。

spring.cloud.config.environment.class (必填)

EnvironmentRepository 的實現。

spring.cloud.config.environment.label (必填)

查詢屬性的標籤。

spring.cloud.config.environment.profile (必填)

查詢屬性的應用程式名稱。

可觀測性 - Span

您可以在下方找到此專案宣告的所有 span 列表。

環境倉庫 Span

在 EnvironmentRepository 周圍建立的觀測。

Span 名稱 spring.cloud.config.environment.find(由約定類 org.springframework.cloud.config.server.environment.ObservationEnvironmentRepositoryObservationConvention 定義)。

包含類的完全限定名 org.springframework.cloud.config.server.environment.DocumentedConfigObservation

所有標籤必須以 spring.cloud.config.environment 字首開頭!
表 2. 標籤鍵

名稱

描述

spring.cloud.config.environment.application (必填)

查詢屬性的應用程式名稱。

spring.cloud.config.environment.class (必填)

EnvironmentRepository 的實現。

spring.cloud.config.environment.label (必填)

查詢屬性的標籤。

spring.cloud.config.environment.profile (必填)

查詢屬性的應用程式名稱。