Kubernetes 用の DiscoveryClient
このプロジェクトは、Kubernetes (英語) 用のディスカバリクライアント [GitHub] (英語) の実装を提供します。このクライアントを使用すると、Kubernetes エンドポイント ( サービス (英語) を参照) を名前でクエリできます。サービスは通常、http
および https
アドレスを表すエンドポイントのコレクションとして Kubernetes API サーバーによって公開され、クライアントは pod として実行されている Spring Boot アプリケーションからアクセスできます。
DiscoveryClient は、型 ExternalName
のサービスも見つけることができます (ExternalName サービス (英語) を参照)。現時点では、外部名サポート型のサービスは、次のプロパティ spring.cloud.kubernetes.discovery.include-external-name-services
が true
に設定されている場合にのみ使用できます (デフォルトでは false
です)。
サポートしている検出クライアントには 3 つの種類があります。
1.
Fabric8 Kubernetes クライアント
<dependency>
<groupId>org.springframework.cloud</groupId>
<artifactId>spring-cloud-starter-kubernetes-fabric8</artifactId>
</dependency>
2.
Kubernetes Java クライアント
<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 つのオプションがあります。
selective namespaces
。例:
spring.cloud.kubernetes.discovery.namespaces[0]=ns1
spring.cloud.kubernetes.discovery.namespaces[1]=ns2
このような構成では、検出クライアントは 2 つの名前空間 ns1
と ns2
内のサービスのみを検索するようになります。
all-namespaces
.
spring.cloud.kubernetes.discovery.all-namespaces=true
このようなオプションは存在しますが、これは kube-api とアプリケーションの両方に負担をかける可能性があります。このような設定が必要になることはまれです。
one namespace
。上記のいずれも指定しない場合は、これがデフォルト設定になります。これは、名前空間の解決で概説されているルールに基づいて機能します。
上記のオプションは、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"
名前空間の設定が完了したら、次にどのサービスを検出するかという問題に答える必要があります。これは、どのフィルターを適用するかという問題として考えてください。デフォルトでは、フィルターはまったく適用されず、すべてのサービスが検出されます。検出クライアントが検出できるものを絞り込む必要がある場合は、次の 2 つのオプションがあります。
特定のサービスラベルに一致するサービスのみを取得します。このプロパティは、
spring.cloud.kubernetes.discovery.service-labels
で指定されます。Map
を受け入れ、そのようなラベルを持つサービス (サービス定義のmetadata.labels
で表示) のみが考慮されます。もう 1 つのオプションは、SpEL 式を使用することです。これは
spring.cloud.kubernetes.discovery.filter
プロパティで示され、その値は選択したクライアントによって異なります。fabric8 クライアントを使用する場合、この SpEL 式はio.fabric8.kubernetes.api.model.Service
クラスに対して作成する必要があります。次のような例があります。
spring.cloud.kubernetes.discovery.filter='#root.metadata.namespace matches "^.+A$"'
これは、検出クライアントに、大文字の A
で終わる metadata.namespace
を持つサービスのみを取得するように指示します。
検出クライアントが k8s ネイティブクライアントに基づいている場合、SpEL 式は io.kubernetes.client.openapi.models.V1Service
クラスに基づいている必要があります。上記と同じフィルターがここでも機能します。
検出クライアントが http ベースのクライアントである場合、SeEL 式は同じ io.kubernetes.client.openapi.models.V1Service
クラスに基づく必要がありますが、唯一の違いは、これを デプロイ yaml の env 変数として設定する必要があることです。
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$"'
ここで、検出クライアントが何を返すべきかを考えます。一般に、DiscoveryClient
には getServices
と getInstances
という 2 つのメソッドがあります。
getServices
は、metadata.name
に表示されるサービス名を返します。
このメソッドは、検索用に選択した異なる名前空間間で重複するサービス名があっても、一意のサービス名を返します。 |
getInstances
は List<ServiceInstance>
を返します。ServiceInstance
が持つ通常のフィールドの他に、名前空間や pod メタデータなどのデータも追加します (これらについてはドキュメントで詳しく説明します)。現時点で返されるデータは次のとおりです。
instanceId
- サービスインスタンスの一意の IDserviceId
- サービスの名前 (getServices
を呼び出して報告されたものと同じです)host
- インスタンスの IP (またはExternalName
型のサービスの場合は名前)port
- インスタンスのポート番号。ポート番号の選択にはルールがあるため、もう少し説明が必要です。サービスにポートが定義されていない場合は、0 (ゼロ) が返されます。
サービスに 1 つのポートが定義されている場合は、そのポートが返されます。
サービスにラベル
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
- 見つかったインスタンスの名前空間。Map<String, Map<String, String>>
形式のサービスインスタンス (pod) のpod-metadata
ラベルとアノテーション。このサポートは、spring.cloud.kubernetes.discovery.metadata.add-pod-labels=true
および / またはspring.cloud.kubernetes.discovery.metadata.add-pod-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 を呼び出すと、それらも返されます。ExternalName と他の型を区別するには、ServiceInstance::getMetadata を調べて type というフィールドを検索します。これが返されるサービスの型になります: ExternalName /ClusterIP など。何らかの理由で DiscoveryClient を無効にする必要がある場合は、application.properties で次のプロパティを設定できます。 |
spring.main.cloud-platform=NONE
アプリケーションを実行する場所に応じて、検出クライアントのサポートは自動的に行われることに注意してください。そのため、上記の設定は必要ない場合もあります。
一部の 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 検出サーバーの場合、これは デプロイ 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
メソッドを使用して、後続の 2 つのハートビートに違いがあるかどうかを確認する必要があります。equals 契約に準拠した正しい実装を返すように注意します。エンドポイントは、次のいずれかで照会されます。- all-namespaces
(spring.cloud.kubernetes.discovery.all-namespaces=true
経由で有効化)
selective namespaces
(spring.cloud.kubernetes.discovery.namespaces
経由で有効化)、例:上記の 2 つのパスが使用されない場合は、名前空間の解決経由の
one namespace
になります。
何らかの理由でカタログウォッチャーを無効にする場合は、spring.cloud.kubernetes.discovery.catalog-services-watch.enabled=false を設定する必要があります。http 検出サーバーの場合、これは デプロイに設定された環境変数である必要があります。例: |
SPRING_CLOUD_KUBERNETES_DISCOVERY_CATALOGSERVICESWATCH_ENABLED=FALSE
カタログウォッチの機能は、サポートしている 3 つの検出クライアントすべてで動作しますが、http クライアントの場合は注意が必要な点がいくつかあります。
1 つ目は、この機能はデフォルトで無効になっており、次の 2 か所で有効にする必要があることです。
デプロイマニフェストの環境変数を介して検出サーバーで、例:
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"
検出クライアントでは、
application.properties
のプロパティを介して次のようにします。spring.cloud.kubernetes.http.discovery.catalog.watcher.enabled=true
2 番目のポイントは、これがバージョン
3.0.6
以降でのみサポートされていることです。http 検出にはサーバーとクライアントの 2 つのコンポーネントがあるため、それらのバージョンを合わせることを強くお勧めします。そうしないと、機能しない可能性があります。
カタログウォッチャーを無効にする場合は、サーバーとクライアントの両方で無効にする必要があります。
デフォルトでは、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
)。もちろん、クラスターもそれをサポートする必要があります。実際、このプロパティを有効にしても、クラスターがそれをサポートしていない場合、アプリケーションの起動は失敗します。このようなサポートを有効にする場合は、適切なロール /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"]