外部 Cassandra データストアを使用する

このトピックでは、Apigee ハイブリッド ランタイムを別の Kubernetes クラスタの Cassandra データストアに接続する方法について説明します。この構成では、ランタイム クラスタに Cassandra Pod がありません。この構成の名前は、外部データストア モードです。

2 クラスタ トポロジ

外部データストア モードでは、次の 2 つの Kubernetes クラスタが使用されます。

  • Cassandra クラスタは Cassandra リングを実行します。ハイブリッド ランタイム コンポーネントは実行されません。
  • ランタイム クラスタはハイブリッド ランタイム コンポーネントを実行しますが、Cassandra Pod はありません。ランタイム コンポーネントは、ネットワークを介して Cassandra クラスタ内の Cassandra リングに接続します。

Apigee Operator は両方のクラスタで実行されます。各クラスタに cert-manager、Apigee カスタム リソース定義(CRD)、apigee-operator チャートをインストールします。次の表に、各クラスタのコンポーネントを示します。

コンポーネント Cassandra クラスタ ランタイム クラスタ
cert-manager ○ ○
Apigee CRD と apigee-operator チャート ○ ○
apigee-datastore のグラフ はい(Cassandra Pod を使用) はい(replicaCount: 0 あり、Cassandra Pod なし)
apigee-telemetry、apigee-redis、apigee-ingress-manager、apigee-org、apigee-env、apigee-virtualhost などの他のすべてのハイブリッド チャート いいえ ○

Apigee オペレーターは、クラスタごとに異なるジョブを実行します。

  • Cassandra クラスタでは、オペレーターが Cassandra Pod を作成します。また、リングをスケーリングするときなど、Cassandra のライフサイクルも管理します。
  • ランタイム クラスタでは、オペレーターは Cassandra Pod を作成しません。ヘッドレス Service と、Cassandra クラスタ内の Cassandra リングを指す Endpoints オブジェクトを作成します。動的エンドポイント同期を有効にすると、ランタイム クラスタのオペレータは Cassandra クラスタから Cassandra エンドポイントも読み取ります。

設定の概要

次の手順を順番に実行します。順序が重要です。ランタイム クラスタが証明書を発行する前に、共有認証局(CA)がランタイム クラスタに存在している必要があります。詳細については、オペレータをインストールする前に Apigee CA を共有するをご覧ください。

  1. Cassandra クラスタに、cert-manager、Apigee CRD、apigee-operator チャート、apigee-datastore チャートをインストールします。
  2. Cassandra クラスタ内の Cassandra Pod の準備ができていることを確認します。
  3. ランタイム クラスタに cert-manager をインストールします。
  4. Cassandra クラスタからランタイム クラスタに apigee-ca シークレットをコピーします。この手順は、ランタイム クラスタに apigee-operator チャートをインストールする前に行ってください。
  5. ランタイム クラスタにハイブリッド ランタイム コンポーネントをインストールします。apigee-datastore グラフには外部データストアのオーバーライドを使用します。Cassandra クラスタと同じ Cassandra 認証情報を使用します。
  6. (推奨)動的エンドポイントの同期を有効にします。
  7. 接続を確認します。

各チャートをインストールする手順については、Helm を使用して Apigee ハイブリッドをインストールするをご覧ください。

始める前に

環境が次の要件を満たしていることを確認します。

  • Cassandra へのネットワーク接続。ランタイム クラスタは、TCP ポート 9042 で Cassandra Pod に接続する必要があります。2 つのクラスタを共有 VPC に配置するか、クラスタ間にプライベート接続があるネットワークに配置します。
  • 1 つのリージョン。2 つのクラスタを同じリージョンに配置します。クラスタ間のラウンドトリップ時間は、各ランタイム リクエストのレイテンシに追加されます。
  • 両方のクラスタに cert-manager がインストールされている。各クラスタで、cert-manager はランタイムと Cassandra 間の mTLS 接続用の証明書を発行します。Cassandra クラスタとランタイム クラスタに cert-manager をインストールします。
  • 各 Cassandra Pod へのルート。Cassandra クライアント ドライバは、各 Cassandra Pod に直接接続します。ランタイム クラスタは、1 つのアドレスだけでなく、各 Cassandra Pod の IP アドレスに接続する必要があります。リングの前にロードバランサまたは単一の仮想 IP アドレスがある場合、この要件は満たされません。
  • Kubernetes API サーバーへのネットワーク接続。この要件は、動的エンドポイント同期を使用する場合にのみ適用されます。ランタイム クラスタは、Cassandra クラスタの Kubernetes API サーバーに接続する必要があります。

オペレータをインストールする前に Apigee CA を共有する

ランタイム クラスタに cert-manager をインストールします。次に、Cassandra クラスタからランタイム クラスタに CA Secret をコピーします。

kubectl --context CASSANDRA_CLUSTER -n cert-manager get secret apigee-ca -o yaml \
  | grep -v -E '^\s+(resourceVersion|uid|creationTimestamp|selfLink):' \
  | kubectl --context RUNTIME_CLUSTER -n cert-manager apply -f -

次のように置き換えます。

  • CASSANDRA_CLUSTER: Cassandra クラスタの kubectl コンテキスト。
  • RUNTIME_CLUSTER: ランタイム クラスタの kubectl コンテキスト。

grep コマンドは、Cassandra クラスタに属するメタデータ フィールドを削除します。Kubernetes API サーバーは、resourceVersion 値を持つオブジェクトを作成しません。

マルチリージョン インストールでは、同じ共有 CA の原則が使用されます。同様のコピー手順については、ルート CA 証明書をローテーションするをご覧ください。Cassandra mTLS の構成については、Cassandra の認証を構成するをご覧ください。

両方のクラスタで同じ Cassandra 認証情報を使用する

2 つのクラスタのオーバーライド ファイルで、次のいずれかの方法を使用します。

  • cassandra.auth(default、admin、ddl、dml、jmx、jolokia)で同じユーザー名とパスワードを設定します。
  • cassandra.auth.secret を設定します。各クラスタで、シークレットに同じユーザーとパスワードが含まれている必要があります。シークレットを作成するをご覧ください。
  • cassandra.auth.secretProviderClass を、同じシークレット ストアを読み取る SecretProviderClass に設定します。Hashicorp Vault への Cassandra Secret の保存をご覧ください。

認証情報 Secret を Cassandra クラスタからコピーしません。ランタイム クラスタのグラフは、オーバーライドから Secret を作成します。認証エラーを見つけるには、接続を確認するをご覧ください。

外部データストアを構成する

ランタイム クラスタでは、apigee-datastore チャートで Cassandra Pod を作成してはなりません。Cassandra クラスタの Cassandra リングを指している必要があります。次の cassandra 設定をランタイム クラスタのオーバーライド ファイルに追加します。

cassandra:
  # No Cassandra pods in the runtime cluster.
  replicaCount: 0
  properties:
    # A comma-separated list of the Cassandra pod IP addresses.
    externalHost: "CASSANDRA_IP_ADDRESSES"
  storage:
    # Required, even with replicaCount: 0.
    storageSize: "10Gi"

ここで

  • CASSANDRA_IP_ADDRESSES は、Cassandra クラスタ内の Cassandra Pod の IP アドレスのカンマ区切りのリストです。例: 10.0.0.1:9042,10.0.0.2:9042,10.0.0.3:9042。:9042 接尾辞は省略可能です。リストを取得するには、次のコマンドを実行します。
    kubectl --context CASSANDRA_CLUSTER -n APIGEE_NAMESPACE get pods -l app=apigee-cassandra \
      -o jsonpath='{.items[*].status.podIP}' | tr ' ' ','
  • APIGEE_NAMESPACE は Apigee Namespace です。デフォルトは apigee です。
  • replicaCount: 0 は、ランタイム クラスタに Cassandra Pod を作成しないようにオペレータに指示します。オペレーターは、externalHost アドレスを参照するヘッドレス Service と Endpoints オブジェクトを作成します。
  • cassandra.properties.externalHost は、Cassandra IP アドレスのカンマ区切りのリストです。各アドレスには :port 接尾辞を付けることができますが、オペレーターはポートを無視し、常にポート 9042 を使用します。演算子は IP アドレスのみを受け入れます。ホスト名と DNS 名は無視され、無視されたエントリごとに警告がログに書き込まれます。
  • cassandra.storage.storageSize は必須ですが、ランタイム クラスタは Cassandra の PersistentVolume を作成しません。ApigeeDatastore 検証 Webhook は常に storageSize をチェックします。有効な数量(例: 10Gi)を使用します。

リングをスケーリングするときや、Kubernetes が Pod を再スケジュールするときに、Pod の IP アドレスが変更されます。externalHost のリストが正しくなくなります。そのため、動的エンドポイント同期をおすすめします。動的エンドポイント同期により、Cassandra Pod の IP アドレスのリストが自動的に最新の状態に保たれます。externalHost は、簡単なインストールまたは初回設定の場合にのみ単独で使用します。

動的エンドポイント同期でエンドポイントを最新の状態に保つ

externalHost のみを使用する場合は、Cassandra リングが変更されるたびにオーバーライドを編集する必要があります。動的エンドポイント同期により、この手動の手順が不要になります。ランタイム クラスタ内のオペレーターは、Cassandra クラスタから準備完了の Cassandra エンドポイントを定期的に読み取ります。次に、これらのエンドポイントをランタイム クラスタの Endpoints オブジェクトにコピーします。

動的エンドポイントの同期をおすすめします。リングをスケーリングするか、Kubernetes が Pod を再スケジュールするたびに、Pod の IP アドレスが変更されます。動的エンドポイント同期は、Cassandra ヘッドレス Service の準備完了 Pod の IP アドレスを読み取ります。したがって、ランタイム クラスタ内の Endpoints オブジェクトには、常に現在の Cassandra Pod の IP アドレスが含まれます。

動的エンドポイント同期では、externalHost は引き続き必要です。演算子は、次の 2 つの条件で使用します。

  • Cassandra クラスタからの最初の読み取りが成功する前。
  • Cassandra クラスタからの読み取りが失敗し、以前の読み取りが成功したエンドポイントがない場合。

読み取りが失敗し、以前の読み取りが成功したエンドポイントがある場合、オペレーターはそれらのエンドポイントを保持します。ランタイムは Cassandra への接続を維持します。

動的エンドポイント同期を有効にするには、ランタイム クラスタのオーバーライド ファイルに externalEndpointsSync ブロックを追加します。

cassandra:
  replicaCount: 0
  properties:
    # The first endpoints, and the fallback if a read fails.
    externalHost: "CASSANDRA_IP_ADDRESSES"
    externalEndpointsSync:
      # A secret in the runtime cluster. Its "kubeconfig" key holds the
      # kubeconfig for the Cassandra cluster.
      secretRef: apigee-remote-cass-kubeconfig
      # The namespace of the Cassandra headless Service in the Cassandra cluster.
      namespace: apigee
      # The Cassandra headless Service in the Cassandra cluster.
      serviceName: apigee-cassandra-default
      # The interval between reads, in seconds. The default is 30.
      intervalSeconds: 30
  storage:
    storageSize: "10Gi"

Cassandra クラスタに読み取り専用のサービス アカウントを作成する

ランタイム クラスタのオペレーターは、kubeconfig を使用して Cassandra クラスタに接続します。この kubeconfig は、最小権限の読み取り専用 ServiceAccount を使用する必要があります。この ServiceAccount は、Cassandra エンドポイントの読み取りのみを行うことができます。Cassandra クラスタ内のリソースを変更することはできません。

Cassandra クラスタで、次のリソースを作成します。

  • ServiceAccount(apigee-endpoint-reader など)。
  • Cassandra Namespace の Role と RoleBinding。このロールは、コア endpoints に対する get、list、watch 動詞のみを付与します。create、update、patch、delete などの他の動詞は使用しないでください。他のリソースへのアクセス権を付与しないでください。
  • ServiceAccount の有効期間の長いトークン Secret。

次に、Cassandra クラスタの Kubernetes API サーバー用の kubeconfig ファイルを作成します。この kubeconfig は、ServiceAccount のトークンを使用する必要があります。ランタイム クラスタで、externalEndpointsSync.secretRef で設定した名前の Secret を作成します。kubeconfig を kubeconfig キーに入れます。

kubectl --context RUNTIME_CLUSTER -n APIGEE_NAMESPACE create secret generic \
  apigee-remote-cass-kubeconfig --from-file=kubeconfig=READER_KUBECONFIG_FILE

READER_KUBECONFIG_FILE は、読み取り専用 ServiceAccount の kubeconfig ファイルへのパスに置き換えます。

kubeconfig には長期間有効なトークンが含まれています。このシークレットは、他の認証情報と同様に安全に保管してください。

動的エンドポイントの同期をモニタリングする

Cassandra クラスタからの読み取りが失敗した場合、ランタイムは接続を維持します。ただし、読み取りが再び成功するまで、ランタイム クラスタのエンドポイントは変更されません。同期をモニタリングして、Cassandra リングが変更される前に永続的な障害を見つけます。

ランタイム クラスタのオペレーターは、次のシグナルを送信します。

  • ApigeeDatastore リソースのステータスの EndpointSyncDegraded 条件。読み取りが 3 回連続して失敗すると、条件は True になります。理由は RemoteReadFailed または NoReadyRemoteEndpoints です。読み取りが成功すると、条件は False になり、理由は SyncSucceeded になります。
  • external_endpoint_sync_last_success_timestamp 指標。この指標は、最後に成功した読み取りの時刻(UNIX 秒単位)です。
  • external_endpoint_sync_failures_total 指標。この指標は、失敗した読み取りの数をカウントします。

2 つの指標には、ApigeeDatastore リソースの namespace ラベルと name ラベルがあります。オペレーターは、指標エンドポイントにこれらの指標を表示します。

条件を表示するには、次のコマンドを実行します。

kubectl --context RUNTIME_CLUSTER -n APIGEE_NAMESPACE get apigeedatastore default \
  -o jsonpath='{.status.conditions}'

EndpointSyncDegraded 条件のアラートをおすすめします。ApigeeDatastore ステータスは、オペレーターの再起動時に条件を保持します。読み取りが成功した場合にのみ、条件が False に設定されます。

指標でアラートも使用する場合は、次の 2 つの式のうちいずれかが true の場合にアラートを送信します。

  • time() - external_endpoint_sync_last_success_timestamp > 300
  • absent(external_endpoint_sync_last_success_timestamp)

オペレーターは、読み取りが成功した後にのみ指標を設定します。読み取りが失敗したときにオペレータが再起動すると、指標は存在しません。この場合、最初の式は一致せず、2 番目の式のみがアラートを送信します。

接続を確認する

ランタイム コンポーネントをインストールしたら、ランタイム クラスタで次のチェックを行います。

  1. ランタイム クラスタに Cassandra Pod がないことを確認します。

    kubectl --context RUNTIME_CLUSTER -n APIGEE_NAMESPACE get pods -l app=apigee-cassandra

    出力は No resources found です。

  2. Endpoints オブジェクトが Cassandra リングを指していることを確認します。

    kubectl --context RUNTIME_CLUSTER -n APIGEE_NAMESPACE get endpoints apigee-cassandra-default

    ENDPOINTS 列には、Cassandra の IP アドレスが表示されます。動的エンドポイント同期を使用する場合、これらは Cassandra クラスタ内の準備完了の Cassandra Pod の IP アドレスです。

  3. Cassandra 設定ジョブが完了したことを確認します。

    kubectl --context RUNTIME_CLUSTER -n APIGEE_NAMESPACE get jobs \
      | grep -E 'apigee-cassandra-(schema|user)-setup'

    COMPLETIONS 列には、各ジョブの 1/1 が表示されます。ジョブが完了しない場合は、ジョブのログで認証エラーを確認します。次に、2 つのクラスタで同じ Cassandra 認証情報を使用していることを確認します。

Cassandra リングをスケーリングする

Cassandra クラスタの Apigee オペレーターが Cassandra のライフサイクルを所有しています。Cassandra クラスタ内の Cassandra をスケーリングします。ランタイム クラスタから Cassandra をスケーリングすることはできません。

ランタイム クラスタの Cassandra リングと同じルールに従います。

  • Cassandra は 3 の倍数でスケーリングします。これにより、リングは 3 つのアベイラビリティ ゾーン間でバランスが保たれます。
  • Pod の数を増やす前に、Cassandra クラスタに十分なノード容量があることを確認してください。
  • 動的エンドポイント同期を使用しない場合は、スケーリング オペレーションのたびに externalHost を更新します。

詳細については、Cassandra のスケーリングをご覧ください。

次のステップ