最新の安定バージョンについては、Spring Cloud Kubernetes 3.3.0 を使用してください! |
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という名前のポートを使用してポート番号を計算します。最後の手段として、ポートリストの最初のポートを選択します。この最後のオプションでは、非決定的な動作が発生する可能性があります。
サービスインスタンスの
urischeme、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"]