Kubernetes 的 DiscoveryClient
此專案為 Kubernetes 提供 Discovery Client 的實作。此用戶端可讓您依名稱查詢 Kubernetes 端點 (請參閱服務)。服務通常由 Kubernetes API 伺服器公開為端點集合,這些端點代表 http
和 https
位址,且用戶端可以從作為 Pod 執行的 Spring Boot 應用程式存取。
DiscoveryClient 也可以尋找類型為 ExternalName
的服務 (請參閱 ExternalName 服務)。目前,只有在將以下屬性 spring.cloud.kubernetes.discovery.include-external-name-services
設定為 true
(預設為 false
) 時,才支援外部名稱服務類型。
我們支援 3 種 DiscoveryClient 類型
1.
Fabric8 Kubernetes Client
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-fabric8</artifactId>
</dependency>
2.
Kubernetes Java Client
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-client</artifactId>
</dependency>
3.
HTTP 基礎 DiscoveryClient
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-discoveryclient</artifactId>
</dependency>
spring-cloud-starter-kubernetes-discoveryclient 設計為與 Spring Cloud Kubernetes DiscoveryServer 搭配使用。 |
若要啟用 DiscoveryClient
的載入,請將 @EnableDiscoveryClient
新增至相應的組態或應用程式類別,如下列範例所示
@SpringBootApplication
@EnableDiscoveryClient
public class Application {
public static void main(String[] args) {
SpringApplication.run(Application.class, args);
}
}
然後,您可以透過自動裝配將用戶端注入到您的程式碼中,如下列範例所示
@Autowired
private DiscoveryClient discoveryClient;
您應該問自己的第一個問題是 DiscoveryClient
應該在哪裡探索服務。在 Kubernetes 世界中,這表示哪個命名空間。這裡有 3 個選項
-
選擇性命名空間
。例如
spring.cloud.kubernetes.discovery.namespaces[0]=ns1
spring.cloud.kubernetes.discovery.namespaces[1]=ns2
此組態會讓 Discovery Client 僅在兩個命名空間 ns1
和 ns2
中搜尋服務。
-
所有命名空間
.
spring.cloud.kubernetes.discovery.all-namespaces=true
雖然存在此選項,但這可能會對 kube-api 和您的應用程式造成負擔。很少需要此設定。
-
單一命名空間
。如果您未指定上述任何一個,這是預設設定。它適用於 命名空間解析 中概述的規則。
上述選項對於 Fabric8 和 k8s 用戶端而言,其運作方式與書寫方式完全相同。對於 HTTP 基礎用戶端,您需要在伺服器上啟用這些選項。這可以透過在用於將映像部署到叢集中的 deployment.yaml 中設定它們來達成,使用環境變數。 |
例如
containers:
- name: discovery-server
image: springcloud/spring-cloud-kubernetes-discoveryserver:3.0.5-SNAPSHOT
env:
- name: SPRING_CLOUD_KUBERNETES_DISCOVERY_NAMESPACES_0
value: "namespace-a"
設定命名空間之後,下一個要回答的問題是要探索哪些服務。將其視為要套用的篩選器。預設情況下,不會套用任何篩選,且會探索所有服務。如果您需要縮小 Discovery Client 可以找到的範圍,您有兩個選項
-
僅採用符合特定服務標籤的服務。此屬性以
spring.cloud.kubernetes.discovery.service-labels
指定。它接受Map
,且只會考慮具有這些標籤 (如服務定義中的metadata.labels
所示) 的服務。 -
另一個選項是使用 SpEL 運算式。這由
spring.cloud.kubernetes.discovery.filter
屬性表示,且其值取決於您選擇的用戶端。如果您使用 Fabric8 用戶端,則必須針對io.fabric8.kubernetes.api.model.Service
類別建立此 SpEL 運算式。其中一個範例可能是
spring.cloud.kubernetes.discovery.filter='#root.metadata.namespace matches "^.+A$"'
這會告知 Discovery Client 僅取得具有以上大寫 A
結尾的 metadata.namespace
的服務。
如果您的 Discovery Client 是以 k8s-native 用戶端為基礎,則 SpEL 運算式必須以 io.kubernetes.client.openapi.models.V1Service
類別為基礎。上面顯示的相同篩選器在這裡也適用。
如果您的 Discovery Client 是 HTTP 基礎的用戶端,則 SeEL 運算式必須以相同的 io.kubernetes.client.openapi.models.V1Service
類別為基礎,唯一的區別是這需要設定為部署 yaml 中的環境變數
containers: - name: discovery-server image: springcloud/spring-cloud-kubernetes-discoveryserver:3.0.5-SNAPSHOT env: - name: SPRING_CLOUD_KUBERNETES_DISCOVERY_FILTER value: '#root.metadata.namespace matches "^.+A$"'
現在是時候思考 Discovery Client 應該傳回什麼。一般而言,DiscoveryClient
有兩種方法:getServices
和 getInstances
。
getServices
將傳回服務名稱,如 metadata.name
中所示。
即使在您選擇搜尋的不同命名空間中存在重複項,此方法也會傳回唯一的服務名稱。 |
getInstances
傳回 List<ServiceInstance>
。除了 ServiceInstance
具有的常用欄位之外,我們還新增了一些資料,例如命名空間或 Pod 中繼資料 (有關這些的更多說明將在文件中後續提供)。以下是我們目前傳回的資料
-
instanceId
- 服務執行個體的唯一 ID -
serviceId
- 服務的名稱 (與呼叫getServices
所報告的名稱相同) -
host
- 執行個體的 IP (或ExternalName
服務類型的情況下為名稱) -
port
- 執行個體的連接埠號碼。這需要更多說明,因為選擇連接埠號碼有其規則-
服務未定義連接埠,將傳回 0 (零)。
-
服務已定義單一連接埠,將傳回該連接埠。
-
如果服務具有標籤
primary-port-name
,我們將使用具有標籤值中指定名稱的連接埠號碼。 -
如果不存在上述標籤,則我們將使用
spring.cloud.kubernetes.discovery.primary-port-name
中指定的連接埠名稱來尋找連接埠號碼。 -
如果未指定上述任一項,我們將使用名為
https
或http
的連接埠來計算連接埠號碼。 -
作為最後手段,我們將選取連接埠清單中的第一個連接埠。最後一個選項可能會導致非決定性行為。
-
-
服務執行個體的
uri
-
scheme
為http
或https
(取決於secure
結果) -
服務的
metadata
-
labels
(如果透過spring.cloud.kubernetes.discovery.metadata.add-labels=true
要求)。如果設定了標籤金鑰,則可以使用spring.cloud.kubernetes.discovery.metadata.labels-prefix
的值來「加上前置詞」。 -
annotations
(如果透過spring.cloud.kubernetes.discovery.metadata.add-annotations=true
要求)。如果設定了註解金鑰,則可以使用spring.cloud.kubernetes.discovery.metadata.annotations-prefix
的值來「加上前置詞」。 -
ports
(如果透過spring.cloud.kubernetes.discovery.metadata.add-ports=true
要求)。如果設定了連接埠金鑰,則可以使用spring.cloud.kubernetes.discovery.metadata.ports-prefix
的值來「加上前置詞」。 -
k8s_namespace
,其值為執行個體所在的命名空間。 -
type
,其保留服務類型,例如ClusterIP
或ExternalName
-
-
secure
,如果發現的連接埠應視為安全。我們將使用上面概述的相同規則來尋找連接埠名稱和號碼,然後-
如果此服務具有名為
secured
的標籤,且具有任何值:["true", "on", "yes", "1"]
,則將找到的連接埠視為安全。 -
如果未找到此類標籤,請搜尋名為
secured
的註解,並套用相同的上述規則。 -
如果此連接埠號碼是
spring.cloud.kubernetes.discovery.known-secure-ports
的一部分 (預設情況下,此值保留[443, 8443]
),則將連接埠號碼視為安全。 -
最後的手段是查看連接埠名稱是否符合
https
;如果符合,則將此連接埠視為安全。
-
-
namespace
- 找到的執行個體的命名空間。 -
服務執行個體 (Pod) 的
pod-metadata
標籤和註解,格式為Map<String, Map<String, String>>
。需要透過spring.cloud.kubernetes.discovery.metadata.add-pod-labels=true
和/或spring.cloud.kubernetes.discovery.metadata.add-annotaations=true
啟用此支援
若要探索未由 Kubernetes API 伺服器標示為「就緒」的服務端點位址,您可以在 application.properties
中設定以下屬性 (預設值:false)
spring.cloud.kubernetes.discovery.include-not-ready-addresses=true
在基於監視目的探索服務時,這可能很有用,並且可以檢查未就緒服務執行個體的 /health 端點。如果您想要取得 ServiceInstance 清單以也包含 ExternalName 類型服務,則需要透過以下方式啟用該支援:spring.cloud.kubernetes.discovery.include-external-name-services=true 。如此一來,在呼叫 DiscoveryClient::getInstances 時,也會傳回這些服務。您可以透過檢查 ServiceInstance::getMetadata 並尋找名為 type 的欄位來區分 ExternalName 和任何其他類型。這將是傳回的服務類型:ExternalName /ClusterIP 等。如果基於任何原因,您需要停用 DiscoveryClient ,您可以在 application.properties 中設定以下屬性 |
spring.main.cloud-platform=NONE
請注意,Discovery Client 的支援是自動的,取決於您執行應用程式的位置。因此,可能不需要上述設定。
某些 Spring Cloud 组件使用 DiscoveryClient
以取得有關本機服務執行個體的資訊。為了使其運作,您需要將 Kubernetes 服務名稱與 spring.application.name
屬性對齊。
spring.application.name 對於在 Kubernetes 中為應用程式註冊的名稱沒有任何影響 |
Spring Cloud Kubernetes 也可以監視 Kubernetes 服務目錄的變更,並相應地更新 DiscoveryClient
實作。為了啟用此功能,您需要在應用程式中的組態類別上新增 @EnableScheduling
。所謂「監視」,我們指的是我們將每隔 spring.cloud.kubernetes.discovery.catalog-services-watch-delay
毫秒 (預設值為 30000
) 發佈一次心跳事件。對於 HTTP Discovery Server,這必須是在 deployment yaml 中設定的環境變數
containers: - name: discovery-server image: springcloud/spring-cloud-kubernetes-discoveryserver:3.0.5-SNAPSHOT env: - name: SPRING_CLOUD_KUBERNETES_DISCOVERY_CATALOGSERVICESWATCHDELAY value: 3000
心跳事件將包含目標參考 (及其所有端點位址的命名空間 (如需傳回內容的確切詳細資訊,您可以查看 KubernetesCatalogWatch
內部)。這是實作細節,且心跳事件的接聽程式不應依賴這些細節。相反地,他們應該查看兩個後續心跳之間是否存在差異,方法是透過 equals
方法。我們將負責傳回符合 equals 合約的正確實作。端點將在以下任一項中查詢:- all-namespaces
(透過 spring.cloud.kubernetes.discovery.all-namespaces=true
啟用)
-
選擇性命名空間
(透過spring.cloud.kubernetes.discovery.namespaces
啟用),例如 -
如果未採用上述兩種路徑,則透過 命名空間解析
單一命名空間
。
如果基於任何原因,您想要停用目錄監視器,則需要設定 spring.cloud.kubernetes.discovery.catalog-services-watch.enabled=false 。對於 HTTP Discovery Server,這需要是例如部署中設定的環境變數 |
SPRING_CLOUD_KUBERNETES_DISCOVERY_CATALOGSERVICESWATCH_ENABLED=FALSE
目錄監視的功能適用於我們支援的所有 3 個 Discovery Client,但如果使用 HTTP 用戶端,則需要注意一些注意事項。
-
第一個是預設停用此功能,且需要在兩個位置啟用
-
在 Discovery Server 中,透過部署資訊清單中的環境變數,例如
containers: - name: discovery-server image: springcloud/spring-cloud-kubernetes-discoveryserver:3.0.5-SNAPSHOT env: - name: SPRING_CLOUD_KUBERNETES_HTTP_DISCOVERY_CATALOG_WATCHER_ENABLED value: "TRUE"
-
在 Discovery Client 中,透過
application.properties
中的屬性,例如spring.cloud.kubernetes.http.discovery.catalog.watcher.enabled=true
-
-
第二點是僅自版本
3.0.6
及更高版本起支援此功能。 -
由於 HTTP Discovery 具有兩個组件:伺服器和用戶端,因此我們強烈建議對齊它們之間的版本,否則可能無法運作。
-
如果您決定停用目錄監視器,則需要在伺服器和用戶端中都停用它。
預設情況下,我們使用 Endpoints
(請參閱 kubernetes.io/docs/concepts/services-networking/service/#endpoints) API 來找出服務的目前狀態。不過,還有另一種方法,透過 EndpointSlices
(kubernetes.io/docs/concepts/services-networking/endpoint-slices/)。可以透過屬性啟用此支援:spring.cloud.kubernetes.discovery.use-endpoint-slices=true
(預設值為 false
)。當然,您的叢集也必須支援它。事實上,如果您啟用此屬性,但您的叢集不支援它,我們將無法啟動應用程式。如果您決定啟用此支援,您也需要正確的 Role/ClusterRole 設定。例如
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
namespace: default
name: namespace-reader
rules:
- apiGroups: ["discovery.k8s.io"]
resources: ["endpointslices"]
verbs: ["get", "list", "watch"]