Spring Cloud Config Client

Spring Boot 應用程式可以立即利用 Spring Config Server (或其他由應用程式開發人員提供的外部屬性來源)。它也取得一些與 Environment 變更事件相關的額外實用功能。

Spring Boot Config 資料匯入

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

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

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

這將連線至位於預設位置 "http://localhost: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 profile 載入所有組態。這允許 Spring Boot 收集可能啟用任何額外 profile 的所有組態。在收集所有已啟用的 profile 後,它將載入任何針對作用中 profile 的額外組態。因此,您可能會看到向 Spring Cloud Config Server 發出多個請求以擷取組態。這是正常的,並且是在使用 spring.config.import 時 Spring Boot 載入組態方式的副作用。在先前版本的 Spring Cloud Config 中,只會發出單一請求,但這表示您無法從來自 Config Server 的組態啟用 profile。現在,僅使用 'default' profile 的額外請求使這成為可能。

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

Config 優先啟動

若要使用舊版 bootstrap 連線至 Config Server 的方式,必須透過屬性或 spring-cloud-starter-bootstrap 啟動器啟用 bootstrap。該屬性為 spring.cloud.bootstrap.enabled=true。它必須設定為系統屬性或環境變數。一旦 bootstrap 已啟用,classpath 上具有 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 中 (預設為 "http://localhost:8888")。

Discovery 優先查找

除非您使用Config 優先啟動,否則您需要在組態屬性中使用具有 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) 來變更它。

discovery client 實作都支援某種類型的中繼資料對應 (例如,我們針對 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 的 Discovery 優先啟動

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

Config Client 快速失敗

在某些情況下,您可能希望在服務無法連線至 Config Server 時讓服務啟動失敗。如果這是所需的行為,請設定 bootstrap 組態屬性 spring.cloud.config.fail-fast=true,以使用戶端停止並顯示例外狀況。

若要使用 spring.config.import 取得類似的功能,只需省略 optional: 前綴即可。

Config Client 重試

如果您預期 config server 在您的應用程式啟動時偶爾可能無法使用,您可以使其在失敗後持續嘗試。首先,您需要設定 spring.cloud.config.fail-fast=true。然後,您需要將 spring-retryspring-boot-starter-aop 新增至您的 classpath。預設行為是重試六次,初始退避間隔為 1000 毫秒,後續退避的指數乘數為 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,支援建立一個。

使用 spring.config.import 的 Config Client 重試

重試適用於 Spring Boot spring.config.import 陳述式,且一般屬性也適用。但是,如果 import 陳述式位於 profile 中,例如 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 標籤、分支名稱或 commit ID。標籤也可以作為逗號分隔的清單提供。在這種情況下,清單中的項目會逐一嘗試,直到其中一個成功為止。當處理功能分支時,此行為可能很有用。例如,您可能想要將 config 標籤與您的分支對齊,但使其成為選擇性的 (在這種情況下,請使用 spring.cloud.config.label=myfeature,develop)。

指定 Config Server 的多個 URL

為了確保高可用性,當您部署多個 Config Server 實例並預期一個或多個實例無法使用或無法回應來自一段時間的請求時 (例如,如果 Git 伺服器關閉),您可以指定多個 URL (作為 spring.cloud.config.uri 屬性下的逗號分隔清單) 或讓您的所有實例在服務註冊表 (如 Eureka) 中註冊 (如果使用 Discovery-First 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 基本安全性,則目前只有在您將認證嵌入到您在 spring.cloud.config.uri 屬性下指定的每個 URL 中時,才有可能支援每個 Config Server 的驗證認證。如果您使用任何其他類型的安全性機制,您目前無法支援每個 Config Server 的驗證和授權。

組態逾時

如果您想要組態逾時閾值

  • 可以使用 spring.cloud.config.request-read-timeout 屬性來組態讀取逾時。

  • 可以使用 spring.cloud.config.request-connect-timeout 屬性來組態連線逾時。

安全性

如果您在伺服器上使用 HTTP Basic 安全性,用戶端需要知道密碼 (以及使用者名稱,如果不是預設的使用者名稱)。您可以透過 config server URI 或透過個別的使用者名稱和密碼屬性來指定使用者名稱和密碼,如下列範例所示

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 中,因為它不需要在 config 檔案中)。以下範例在本地和 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。當省略密碼屬性時,將假設為空密碼。

如果您使用另一種形式的安全性,您可能需要提供 RestTemplateConfigServicePropertySourceLocator (例如,透過在 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 擷取值。此 token 可以在用戶端中透過在 bootstrap.yml 中設定 spring.cloud.config.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 與原生映像檔支援

4.0.0 起,Spring Cloud Config Client 支援 Spring AOT 轉換和 GraalVM 原生映像檔。

AOT 和原生映像檔支援不適用於Config 優先啟動 (搭配 spring.config.use-legacy-processing=true)。
原生映像檔不支援重新整理範圍。如果您要將您的 config client 應用程式作為原生映像檔執行,請務必將 spring.cloud.refresh.enabled 屬性設定為 false
在建置包含 Spring Cloud Config Client 的專案時,您必須確保它連線的組態資料來源 (例如,Spring Cloud Config Server、Consul、Zookeeper、Vault 等) 可用。例如,如果您從 Spring Cloud Config Server 擷取組態資料,請確保您已執行其執行個體並在 Config Client 設定中指示的連接埠上可用。這是必要的,因為應用程式內容正在建置時進行最佳化,並且需要解析目標環境。
由於在 AOT 和原生模式下,組態正在處理中,且內容正在建置時進行最佳化,因此任何會影響 bean 建立的屬性 (例如在 bootstrap 內容中使用的屬性) 都應在建置時和執行時設定為相同的值,以避免發生非預期的行為。
由於 Config Client 在從原生映像檔啟動時連線到正在執行的資料來源 (例如 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

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

封閉類別的完整限定名稱 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 (必要)

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