使用 ConfigMap
PropertySource
Kubernetes 提供了一個名為 ConfigMap
的資源,用於將參數外部化,以金鑰值對或嵌入式 application.properties
或 application.yaml
檔案的形式傳遞給您的應用程式。Spring Cloud Kubernetes Config 專案使 Kubernetes ConfigMap
實例在應用程式啟動期間可用,並在偵測到觀察到的 ConfigMap
實例發生變更時,觸發 Bean 或 Spring 內容的熱重新載入。
以下所有內容主要參考使用 ConfigMap 的範例進行解釋,但同樣適用於 Secrets,即:每個功能都支援兩者。
預設行為是根據 Kubernetes ConfigMap
建立 Fabric8ConfigMapPropertySource
(或 KubernetesClientConfigMapPropertySource
),該 ConfigMap
的 metadata.name
為下列其中之一
-
spring.cloud.kubernetes.config.name
的值 -
您的 Spring 應用程式的值 (由
spring.application.name
屬性定義) -
字串常值
"application"
但是,更進階的設定是可能的,您可以使用多個 ConfigMap
實例。spring.cloud.kubernetes.config.sources
清單使這成為可能。例如,您可以定義以下 ConfigMap
實例
spring:
application:
name: cloud-k8s-app
cloud:
kubernetes:
config:
name: default-name
namespace: default-namespace
sources:
# Spring Cloud Kubernetes looks up a ConfigMap named c1 in namespace default-namespace
- name: c1
# Spring Cloud Kubernetes looks up a ConfigMap named default-name in whatever namespace n2
- namespace: n2
# Spring Cloud Kubernetes looks up a ConfigMap named c3 in namespace n3
- namespace: n3
name: c3
在上述範例中,如果未設定 spring.cloud.kubernetes.config.namespace
,則名為 c1
的 ConfigMap
將在應用程式執行的命名空間中查找。請參閱 命名空間解析,以更好地了解如何解析應用程式的命名空間。
找到的任何符合條件的 ConfigMap
都會按如下方式處理
-
套用個別組態屬性。
-
將名為
spring.application.name
的屬性的內容 (如果不存在,則為application.yaml/properties
) 套用為yaml
(或properties
) -
將上述名稱 + 每個活動設定檔的內容套用為屬性檔案。
一個範例應該會更清楚。假設 spring.application.name=my-app
,且我們有一個名為 k8s
的活動設定檔。對於如下組態
kind: ConfigMap
apiVersion: v1
metadata:
name: my-app
data:
my-app.yaml: |-
...
my-app-k8s.yaml: |-
..
my-app-dev.yaml: |-
..
not-my-app.yaml: |-
..
someProp: someValue
這就是我們最終載入的內容
-
my-app.yaml
被視為檔案 -
my-app-k8s.yaml
被視為檔案 -
my-app-dev.yaml
已忽略,因為dev
不是活動設定檔 -
not-my-app.yaml
已忽略,因為它與spring.application.name
不符 -
someProp: someValue
純屬性
屬性的載入順序如下
-
首先從
my-app.yaml
載入所有屬性 -
然後從基於設定檔的來源載入所有屬性:
my-app-k8s.yaml
-
然後載入所有純屬性
someProp: someValue
這表示基於設定檔的來源優先於非基於設定檔的來源 (就像在原始 Spring 應用程式中一樣);純屬性優先於基於設定檔和非基於設定檔的來源。以下是一個範例
kind: ConfigMap
apiVersion: v1
metadata:
name: my-app
data:
my-app-k8s.yaml: |-
key1=valueA
key2=valueB
my-app.yaml: |-
key1=valueC
key2=valueA
key1: valueD
在處理這樣的 ConfigMap 後,您將在屬性中得到:key1=valueD
、key2=valueB
。
上述流程的唯一例外是當 ConfigMap
包含單一金鑰時,該金鑰表示該檔案是 YAML 或 properties 檔案。在這種情況下,金鑰的名稱不必是 application.yaml
或 application.properties
(它可以是任何名稱),並且屬性的值會被正確處理。此功能有助於使用類似以下方式建立 ConfigMap
的使用案例
kubectl create configmap game-config --from-file=/path/to/app-config.yaml
假設我們有一個名為 demo
的 Spring Boot 應用程式,它使用以下屬性來讀取其執行緒池組態。
-
pool.size.core
-
pool.size.maximum
這可以外部化到 yaml
格式的 config map,如下所示
kind: ConfigMap
apiVersion: v1
metadata:
name: demo
data:
pool.size.core: 1
pool.size.max: 16
個別屬性在大多數情況下都能正常運作。但是,有時,嵌入式 yaml
更方便。在這種情況下,我們使用名為 application.yaml
的單一屬性來嵌入我們的 yaml
,如下所示
kind: ConfigMap
apiVersion: v1
metadata:
name: demo
data:
application.yaml: |-
pool:
size:
core: 1
max:16
以下範例也適用
kind: ConfigMap
apiVersion: v1
metadata:
name: demo
data:
custom-name.yaml: |-
pool:
size:
core: 1
max:16
您也可以定義基於標籤的搜尋,例如
spring:
application:
name: labeled-configmap-with-prefix
cloud:
kubernetes:
config:
enableApi: true
useNameAsPrefix: true
namespace: spring-k8s
sources:
- labels:
letter: a
這將在命名空間 spring-k8s
中搜尋每個具有標籤 {letter : a}
的 configmap。這裡需要注意的重要事項是,與依名稱讀取 configmap 不同,這可能會導致讀取多個 config map。與往常一樣,Secrets 也支援相同的功能。
您可以根據讀取 ConfigMap
時合併在一起的活動設定檔,以不同的方式設定 Spring Boot 應用程式。您可以透過使用 application.properties
或 application.yaml
屬性,為不同的設定檔提供不同的屬性值,每個設定檔都在其自己的文件中 (以 ---
序列表示),如下所示
kind: ConfigMap
apiVersion: v1
metadata:
name: demo
data:
application.yml: |-
greeting:
message: Say Hello to the World
farewell:
message: Say Goodbye
---
spring:
profiles: development
greeting:
message: Say Hello to the Developers
farewell:
message: Say Goodbye to the Developers
---
spring:
profiles: production
greeting:
message: Say Hello to the Ops
在上述情況下,載入到具有 development
設定檔的 Spring 應用程式中的組態如下
greeting:
message: Say Hello to the Developers
farewell:
message: Say Goodbye to the Developers
但是,如果 production
設定檔處於活動狀態,則組態變為
greeting:
message: Say Hello to the Ops
farewell:
message: Say Goodbye
如果兩個設定檔都處於活動狀態,則 ConfigMap
中最後出現的屬性會覆寫任何先前的值。
另一個選項是為每個設定檔建立不同的 config map,Spring Boot 將根據活動設定檔自動擷取它
kind: ConfigMap
apiVersion: v1
metadata:
name: demo
data:
application.yml: |-
greeting:
message: Say Hello to the World
farewell:
message: Say Goodbye
kind: ConfigMap
apiVersion: v1
metadata:
name: demo-development
data:
application.yml: |-
spring:
profiles: development
greeting:
message: Say Hello to the Developers
farewell:
message: Say Goodbye to the Developers
kind: ConfigMap
apiVersion: v1
metadata:
name: demo-production
data:
application.yml: |-
spring:
profiles: production
greeting:
message: Say Hello to the Ops
farewell:
message: Say Goodbye
若要告知 Spring Boot 應啟用哪個 profile
,請參閱 Spring Boot 文件。在部署到 Kubernetes 時啟用特定設定檔的一個選項是使用環境變數啟動 Spring Boot 應用程式,您可以在 PodSpec 的容器規格中定義該環境變數。部署資源檔案,如下所示
apiVersion: apps/v1
kind: Deployment
metadata:
name: deployment-name
labels:
app: deployment-name
spec:
replicas: 1
selector:
matchLabels:
app: deployment-name
template:
metadata:
labels:
app: deployment-name
spec:
containers:
- name: container-name
image: your-image
env:
- name: SPRING_PROFILES_ACTIVE
value: "development"
您可能會遇到有多個 config map 具有相同屬性名稱的情況。例如
kind: ConfigMap
apiVersion: v1
metadata:
name: config-map-one
data:
application.yml: |-
greeting:
message: Say Hello from one
和
kind: ConfigMap
apiVersion: v1
metadata:
name: config-map-two
data:
application.yml: |-
greeting:
message: Say Hello from two
根據您將這些 config map 放置在 bootstrap.yaml|properties
中的順序,您可能會得到非預期的結果 (最後一個 config map 勝出)。例如
spring:
application:
name: cloud-k8s-app
cloud:
kubernetes:
config:
namespace: default-namespace
sources:
- name: config-map-two
- name: config-map-one
將導致屬性 greetings.message
為 Say Hello from one
。
有一種方法可以透過指定 useNameAsPrefix
來變更此預設組態。例如
spring:
application:
name: with-prefix
cloud:
kubernetes:
config:
useNameAsPrefix: true
namespace: default-namespace
sources:
- name: config-map-one
useNameAsPrefix: false
- name: config-map-two
這樣的組態將導致產生兩個屬性
-
greetings.message
等於Say Hello from one
。 -
config-map-two.greetings.message
等於Say Hello from two
請注意,spring.cloud.kubernetes.config.useNameAsPrefix
的優先順序低於 spring.cloud.kubernetes.config.sources.useNameAsPrefix
。這允許您為所有來源設定「預設」策略,同時僅允許覆寫少數來源。
如果使用 config map 名稱不是選項,您可以指定不同的策略,稱為:explicitPrefix
。由於這是您選擇的明確前綴,因此只能將其提供給 sources
層級。同時,它的優先順序高於 useNameAsPrefix
。假設我們有第三個 config map,其中包含這些項目
kind: ConfigMap
apiVersion: v1
metadata:
name: config-map-three
data:
application.yml: |-
greeting:
message: Say Hello from three
如下所示的組態
spring:
application:
name: with-prefix
cloud:
kubernetes:
config:
useNameAsPrefix: true
namespace: default-namespace
sources:
- name: config-map-one
useNameAsPrefix: false
- name: config-map-two
explicitPrefix: two
- name: config-map-three
將導致產生三個屬性
-
greetings.message
等於Say Hello from one
。 -
two.greetings.message
等於Say Hello from two
。 -
config-map-three.greetings.message
等於Say Hello from three
。
您可以使用與設定 configmap 前綴相同的方式,為 secrets 設定前綴;對於基於名稱的 secrets 和基於標籤的 secrets 都是如此。例如
spring:
application:
name: prefix-based-secrets
cloud:
kubernetes:
secrets:
enableApi: true
useNameAsPrefix: true
namespace: spring-k8s
sources:
- labels:
letter: a
useNameAsPrefix: false
- labels:
letter: b
explicitPrefix: two
- labels:
letter: c
- labels:
letter: d
useNameAsPrefix: true
- name: my-secret
在產生屬性來源時,適用與 config map 相同的處理規則。唯一的區別在於,潛在地,依標籤查找 secrets 可能意味著我們找到多個來源。在這種情況下,前綴 (如果透過 useNameAsPrefix
指定) 將是為這些特定標籤找到的所有 secrets 的名稱。
還有一點需要記住的是,我們支援每個來源而不是每個 secret 的 prefix
。解釋這一點的最簡單方法是透過範例
spring:
application:
name: prefix-based-secrets
cloud:
kubernetes:
secrets:
enableApi: true
useNameAsPrefix: true
namespace: spring-k8s
sources:
- labels:
color: blue
useNameAsPrefix: true
假設符合此標籤的查詢將提供兩個 secrets 作為結果:secret-a
和 secret-b
。這兩個 secrets 都具有相同的屬性名稱:color=sea-blue
和 color=ocean-blue
。未定義哪個 color
將最終成為屬性來源的一部分,但它的前綴將是 secret-a.secret-b
(串連自然排序的 secrets 名稱)。
如果您需要更精細的結果,則可以選擇新增更多標籤以唯一識別 secret。
預設情況下,除了讀取 sources
組態中指定的 config map 之外,Spring 也會嘗試從「設定檔感知」來源讀取所有屬性。解釋這一點的最簡單方法是透過範例。假設您的應用程式啟用了一個名為 "dev" 的設定檔,並且您具有如下所示的組態
spring:
application:
name: spring-k8s
cloud:
kubernetes:
config:
namespace: default-namespace
sources:
- name: config-map-one
除了讀取 config-map-one
之外,Spring 也會嘗試讀取 config-map-one-dev
;以這種特定順序。每個活動設定檔都會產生這樣一個設定檔感知 config map。
雖然您的應用程式不應受到此類 config map 的影響,但如果需要,可以停用它
spring:
application:
name: spring-k8s
cloud:
kubernetes:
config:
includeProfileSpecificSources: false
namespace: default-namespace
sources:
- name: config-map-one
includeProfileSpecificSources: false
請注意,就像之前一樣,您可以指定此屬性的兩個層級:對於所有 config map 或對於個別 config map;後者具有更高的優先順序。
您應該查看安全性設定章節。若要從 Pod 內部存取 config map,您需要具有正確的 Kubernetes 服務帳戶、角色和角色繫結。 |
使用 ConfigMap
實例的另一個選項是將它們掛載到 Pod 中,方法是執行 Spring Cloud Kubernetes 應用程式,並讓 Spring Cloud Kubernetes 從檔案系統讀取它們。
此功能已棄用,將在未來版本中移除 (請改用 spring.config.import )。此行為由 spring.cloud.kubernetes.config.paths 屬性控制。您可以將其與先前描述的機制結合使用,或取代該機制。spring.cloud.kubernetes.config.paths 預期每個屬性檔案的完整路徑清單,因為不會遞迴剖析目錄。例如 |
spring:
cloud:
kubernetes:
config:
paths:
- /tmp/application.properties
- /var/application.yaml
如果您使用 spring.cloud.kubernetes.config.paths 或 spring.cloud.kubernetes.secrets.path ,自動重新載入功能將無法運作。您需要向 /actuator/refresh 端點發出 POST 請求,或重新啟動/重新部署應用程式。 |
在某些情況下,您的應用程式可能無法使用 Kubernetes API 載入某些 ConfigMaps
。如果您希望您的應用程式在這種情況下啟動程序失敗,您可以設定 spring.cloud.kubernetes.config.fail-fast=true
,使應用程式啟動失敗並顯示例外狀況。
您也可以讓您的應用程式在失敗時重試載入 ConfigMap
屬性來源。首先,您需要設定 spring.cloud.kubernetes.config.fail-fast=true
。然後,您需要將 spring-retry
和 spring-boot-starter-aop
新增至您的類別路徑。您可以透過設定 spring.cloud.kubernetes.config.retry.*
屬性來組態重試屬性,例如最大嘗試次數、退避選項 (如初始間隔、乘數、最大間隔)。
如果您已經因為某些原因在類別路徑上具有 spring-retry 和 spring-boot-starter-aop ,並且想要啟用快速失敗,但不希望啟用重試;您可以透過設定 spring.cloud.kubernetes.config.retry.enabled=false 來停用 ConfigMap PropertySources 的重試。 |
名稱 | 類型 | 預設值 | 描述 |
---|---|---|---|
|
|
|
啟用 ConfigMaps |
|
|
|
設定要查找的 |
|
|
用戶端命名空間 |
設定要查找的 Kubernetes 命名空間 |
|
|
|
設定掛載 |
|
|
|
啟用或停用透過 API 取用 |
|
|
|
當載入 |
|
|
|
啟用或停用組態重試。 |
|
|
|
初始重試間隔,以毫秒為單位。 |
|
|
|
最大嘗試次數。 |
|
|
|
退避的最大間隔。 |
|
|
|
下一個間隔的乘數。 |