リアクティブインフラストラクチャ
このセクションでは、Spring Vault を使用したリアクティブプログラミングのサポートに関する基本情報について説明します。
リアクティブプログラミングとは何ですか?
簡単に言うと、リアクティブプログラミングとは、非同期でイベント駆動型であり、水平方向(つまり、クラスタリングを通じて)ではなく垂直方向(つまり、JVM 内)にスケーリングするために少ないスレッドを必要とするノンブロッキングアプリケーションに関するものです。
リアクティブアプリケーションの重要な側面は、プロデューサーがコンシューマーを圧倒しないようにするメカニズムであるバックプレッシャーの概念です。たとえば、HTTP 接続が遅すぎる場合にデータベースから HTTP レスポンスに拡張するリアクティブコンポーネントのパイプラインでは、ネットワーク容量が解放されるまでデータリポジトリの速度が低下したり完全に停止したりすることもあります。
リアクティブ Vault クライアント
Spring Vault のリアクティブクライアントサポートは、コンポーザブル認証ステップと、Reactor Netty または Jetty を介した Spring の関数 WebClient
上に構築されており、完全にノンブロッキングのイベント駆動型 HTTP クライアントの両方を備えています。
VaultTokenSupplier
を VaultToken
のサプライヤーとして公開して HTTP リクエストを認証し、ReactiveVaultOperations
をプライマリエントリポイントとして公開します。VaultEndpoint
、ClientOptions
、SSL のコア構成は、さまざまなクライアント実装で再利用されます。
パッケージ org.springframework.vault.core
にあるクラス ReactiveVaultTemplate
は、Spring のリアクティブ Vault サポートの中心的なクラスであり、Vault と対話するための豊富な機能セットを提供します。このテンプレートは、Vault のデータを読み取り、書き込み、削除するための便利な操作を提供し、ドメインオブジェクトと Vault データ間のマッピングを提供します。
一度構成すると、ReactiveVaultTemplate はスレッドセーフになり、複数のインスタンスで再利用できます。 |
Vault ドキュメントとドメインクラス間のマッピングは、WebClient
とそのコーデックに委譲することによって行われます。
ReactiveVaultTemplate
クラスは、インターフェース ReactiveVaultOperations
を実装します。ReactiveVaultOperations
のメソッドは、API と CLI に慣れている既存の Vault 開発者が API を使い慣れるように、可能な限り Vault API で使用可能なメソッドにちなんで名付けられています。例: 「書き込み」、「削除」、「読み取り」などのメソッドが見つかります。設計のゴールは、Vault API と ReactiveVaultOperations
の使用をできるだけ簡単に移行できるようにすることでした。2 つの API の主な違いは、JSON キーと値のペアではなく、ドメインオブジェクトを ReactiveVaultOperations
に渡すことができることです。
ReactiveVaultTemplate インスタンスの操作を参照するための推奨される方法は、そのインターフェース ReactiveVaultOperations を使用することです。 |
ReactiveVaultTemplate
によって明示的に公開されていない機能は、基になる API にアクセスするためにいくつかの実行コールバックメソッドの 1 つを使用できます。実行コールバックは、WebClient
オブジェクトへの参照を提供します。詳細については、セクション実行コールバックを参照してください。
次に、Spring コンテナーのコンテキストで Vault を操作する方法の例を見てみましょう。
Spring Vault Bean の登録と構成
Spring Vault の使用には、Spring コンテキストは必要ありません。ただし、管理コンテキスト内に登録された ReactiveVaultTemplate
および VaultTokenSupplier
のインスタンスは、Spring IoC コンテナーによって提供されるライフサイクルイベントに参加します。これは、アプリケーションのシャットダウン時にアクティブな Vault セッションを破棄できます。また、アプリケーション全体で同じ ReactiveVaultTemplate
インスタンスを再利用することにも利点があります。
Spring Vault には、Spring コンテキスト内で使用する Bean 定義を提供するサポート構成クラスが付属しています。アプリケーション構成クラスは通常、AbstractVaultConfiguration
から拡張され、環境固有の追加の詳細を提供する必要があります。
AbstractVaultConfiguration
から拡張するには、` VaultEndpoint vaultEndpoint()` および ClientAuthentication clientAuthentication()
メソッドを実装する必要があります。
@Configuration
public class AppConfig extends AbstractReactiveVaultConfiguration {
/**
* Specify an endpoint for connecting to Vault.
*/
@Override
public VaultEndpoint vaultEndpoint() {
return new VaultEndpoint(); (1)
}
/**
* Configure a client authentication.
* Please consider a more secure authentication method
* for production use.
*/
@Override
public ClientAuthentication clientAuthentication() {
return new TokenAuthentication("…"); (2)
}
}
1 | デフォルトで https://localhost:8200 を指す新しい VaultEndpoint を作成します。 |
2 | このサンプルでは、TokenAuthentication を使用してすぐに開始します。サポートされている認証方法の詳細については、[vault.core.authentication] を参照してください。 |
セッション管理
Spring Vault には、Vault リクエストを認証するためのトークンが必要です。認証の詳細については、[vault.core.authentication] を参照してください。リアクティブクライアントには、契約が VaultTokenSupplier
で定義されているノンブロッキングトークンサプライヤーが必要です。トークンは静的であることも、宣言された認証フローを通じて取得することもできます。Vault ログインは、認証された Vault インタラクションごとに発生するべきではありませんが、セッショントークンはセッション全体にわたって保持される必要があります。この側面は、ReactiveLifecycleAwareSessionManager
などの ReactiveSessionManager
を実装するセッションマネージャーによって処理されます。
実行コールバック
すべての Spring テンプレートクラスに共通する設計上の特徴の 1 つは、すべての機能がテンプレート実行コールバックメソッドの 1 つにルーティングされることです。これにより、例外と、必要になる可能性のあるリソース管理が一貫して実行されるようになります。これは、Vault よりも JDBC と JMS の場合に必要性がはるかに高かったのですが、それでもアクセスとロギングを行うための単一の場所を提供します。そのため、Vault API にアクセスして、ReactiveVaultTemplate
でメソッドとして公開していない珍しい操作を実行するには、execute コールバックを使用することをお勧めします。
実行コールバックメソッドのリストを次に示します。
<T> T
doWithVault(Function<WebClient, ? extends T> clientCallback)
指定されたWebClient
のリアクティブシーケンスを構成し、セッションコンテキストなしで Vault と対話できるようにします。<T> T
doWithSession(Function<WebClient, ? extends T> clientCallback)
指定されたWebClient
のリアクティブシーケンスを構成し、認証されたセッションで Vault と対話できるようにします。
コールバックを使用して Vault を初期化する例を次に示します。
reactiveVaultOperations.doWithVault(webClient -> {
return webClient.put()
.uri("/sys/init")
.syncBody(request)
.retrieve()
.toEntity(VaultInitializationResponse.class);
});