Azure Cosmos DB Java v4 SDKで冗長化されたインスタンスのリージョンやURLを取得する

このエントリは2025/02/14現在の情報に基づいています。将来の機能追加や変更に伴い、記載事項からの乖離が発生する発生する可能性があります。

問い合わせ

いつもの問い合わせ主から珍しくCosmos DBに関する問い合わせがあった。

冗長化されたインスタンスのリージョンやURLをJava SDK v3で取得する方法は以前教えてもらったが、v4ではどうなのか?AsyncDocumentClientでは取得できないようなのだが。

問い合わせ主の内容は、以前記載した以下の記事はJava SDK v3用だが、v4の例を教えてくれ(記事にしてくれ)、という圧であった。

確かにアップデートされていたので、まとめておく。

事前準備

Cosmos DBのサービスを作成し、東西日本リージョンで冗長化した上で、片方を書き込み可能、他方を読み取り専用にしておく。

各Regionに冗長化されたCosmos DBのURIを取得するには

v4では、CosmosManagerクラスのインスタンスを作成する必要がある。このクラスを使う場合には、Azure RBACを使う必要があるので、最初にデータプレーンへのRBACを構成する必要がある。

データ プレーンのロールベースのアクセス制御と Azure Cosmos DB for NoSQL を使用する / Use data plane role-based access control with Azure Cosmos DB for NoSQL
https://learn.microsoft.com/azure/cosmos-db/nosql/security/how-to-grant-data-plane-role-based-access

以前RBACについて以下の記事で書いていたが、古いので、今後は使わないのが吉。

Microsoft Entra ID を使用して Azure Cosmos DB アカウントのロールベースのアクセス制御を構成する (日本語のみ)
https://learn.microsoft.com/azure/cosmos-db/how-to-setup-rbac

今回の場合、最低限

Microsoft.DocumentDB/databaseAccounts/readMetadata

の権限が含まれているロールであればよい。

$ az cosmosdb sql role definition list \
  -g <resource_group> \
  -a <cosmosdb_account>

上記コマンドで確認すると、

  • Cosmos DB Built-in Data Contributor
  • Cosmos DB Built-in Data Reader

のいずれかでよいので、今回はCosmos DB Built-in Data Readerロール(以下、Readerロール)を使うことにする。ReaderロールのIDは以下のような構造である。

/subscriptions/<SubscriptionId>/resourceGroups/<ResourceGroup>/providers/Microsoft.DocumentDB/databaseAccounts/<CosmosDBAccount>/sqlRoleDefinitions/00000000-0000-0000-0000-000000000001

ちなみに、Contributorロールは以下。

/subscriptions/<SubscriptionId>/resourceGroups/<ResourceGroup>/providers/Microsoft.DocumentDB/databaseAccounts/<CosmosDBAccount>/sqlRoleDefinitions/00000000-0000-0000-0000-000000000002

試してみる

以下の方針で構成し、実際に取得できるか確認する。

  1. User assigned managed identityを作成
  2. Readerロールに作成したmanaged identityを追加

1. User assigned managed identityを作成

PrincipalIDを後で使うので、CLIで作成しつつ、PrincipalIDを取得しておく。

principalId=$(az identity create -g <resource_group> -n <managedID_Name> --query "principalId" -o tsv)

2. Readerロールに作成したmanaged identityを追加

ロール割り当て時のスコープは、Cosmos DBアカウントのルートでよい。

scopeId="/"

あとは、先ほどのReaderロールのIDを使って、ロール割り当てすればOK。

az cosmosdb sql role assignment create \
 -g <resource_group> \
 -a <cosmosdb-account> \
 -d <role_id> \
 -p $principalId \
 -s $scopeId

3. Code

まず、CosmosManagerインスタンスを作成する。今回はUser assigned managed identityを使っているので、Client IDを指定しているが、もしApp Serviceなどで動作させる場合、System assigned managed identityを使うこともできる。その場合はClient IDの指定は不要。

AzureProfile profile = new AzureProfile(AzureEnvironment.AZURE);
DefaultAzureCredential defaultAzureCredential = new DefaultAzureCredentialBuilder()
        .managedIdentityClientId(clientId)
        .build();
CosmosManager cosmosManager = CosmosManager.authenticate(defaultAzureCredential, profile);

AzureProfile Class
https://learn.microsoft.com/java/api/com.azure.core.management.profile.azureprofile

その上で、DatabaseAccounts(複数形であることに注意)を取得する。

CosmosDBAccounts dbAccounts = cosmosManager.databaseAccounts();

読み取り先を知りたい場合は readableReplications を、書き込み先を知りたい場合は writableReplications を取得する。いずれも、List<Location>を返すので、Listを拡張forで処理するなり、Streamに渡すなりすればよい。以下はreadableReplicationsの例。

for (CosmosDBAccount cosmosDBAccount : dbAccounts.list()) {
    for (Location loc : cosmosDBAccount.readableReplications()) {
        System.out.printf("Location [%s] Endpoint [%s]\n", loc.locationName(), loc.documentEndpoint());
    }
}

4. テスト

AzureProfileでサブスクリプションID、Entra IDのテナントIDを指定していなかったので、実行時には環境変数でTenant ID、Subscription IDを定義する必要がある。もちろんインスタンス作成時に指定していれば不要。

export AZURE_SUBSCRIPTION_ID=xxxx
export AZURE_TENANT_ID=yyyy

その上で、実際に実行してみると、Readableの場合は

Location [Japan East] Endpoint [https://<cosmosdb_account>-japaneast.documents.azure.com:443/]
Location [Japan West] Endpoint [https://<cosmosdb_account>-japanwest.documents.azure.com:443/]

Writableの場合は、マルチリージョン書き込みを許容していないので、1件のみ出力する。

Location [Japan East] Endpoint [https://<cosmosdb_account>-japaneast.documents.azure.com:443/]

コメントを残す

このサイトはスパムを低減するために Akismet を使っています。コメントデータの処理方法の詳細はこちらをご覧ください