Verwenden eines Dienstprinzipals mit dem Spark 3-Konnektor für Azure Cosmos DB for NoSQL
In diesem Artikel erfahren Sie, wie Sie eine Microsoft Entra-Anwendung und einen Dienstprinzipal erstellen, die mit der rollenbasierten Zugriffssteuerung verwendet werden können. Anschließend können Sie diesen Dienstprinzipal verwenden, um eine Verbindung mit einem Azure Cosmos DB for NoSQL-Konto von Spark 3 herzustellen.
Voraussetzungen
- Ein vorhandenes Azure Cosmos DB for NoSQL-Konto
- Falls Sie bereits über ein vorhandenes Azure-Abonnement verfügen, erstellen Sie ein neues Konto.
- Kein Azure-Abonnement? Sie können Azure Cosmos DB kostenlos testen, ohne dass eine Kreditkarte erforderlich ist.
- Ein vorhandener Azure Databricks-Arbeitsbereich
- Registrierte Microsoft Entra-Anwendung und Dienstprinzipal
- Wenn Sie keinen Dienstprinzipal und keine Anwendung haben, registrieren Sie eine Anwendung über das Azure-Portal.
Erstellen eines Geheimnisses und Notieren der Anmeldeinformationen
In diesem Abschnitt erstellen Sie einen geheimen Clientschlüssel und notieren den Wert für die spätere Verwendung.
Öffnen Sie das Azure-Portal.
Navigieren Sie zu Ihrer vorhandenen Microsoft Entra-Anwendung.
Wechseln Sie zur Seite Zertifikate und Geheimnisse. Erstellen Sie dann ein neues Geheimnis. Speichern Sie den Wert für den geheimen Clientschlüssel, der später in diesem Artikel verwendet werden soll.
Wechseln Sie zur Seite Übersicht. Suchen Sie die Werte für Anwendungs-ID (Client-ID), Objekt-ID und Verzeichnis-ID (Mandanten-ID). Notieren Sie sich diese Werte. Sie verwenden diese Werte auch im weiteren Verlauf dieses Artikels.
Navigieren Sie zu Ihrem vorhandenen Azure Cosmos DB for NoSQL-Konto.
Notieren Sie sich den Wert für URI auf der Seite Übersicht. Notieren Sie sich außerdem die Werte für Abonnement-ID und Ressourcengruppe. Sie benötigen diese Werte im weiteren Verlauf dieses Artikels.
Erstellen einer Definition und einer Zuweisung
In diesem Abschnitt erstellen Sie eine Microsoft Entra ID-Rollendefinition. Anschließend weisen Sie diese Rolle mit Berechtigungen zum Lesen und Schreiben für die Elemente in den Containern zu.
Erstellen Sie eine Rolle mithilfe des Befehls
az role definition create
. Übergeben Sie den Azure Cosmos DB for NoSQL-Kontonamen und die Ressourcengruppe, gefolgt von einem JSON-Text, der die benutzerdefinierte Rolle definiert. Der Bereich der Rolle wird zudem mit/
auf die Kontoebene festgelegt. Stellen Sie sicher, dass Sie einen eindeutigen Namen für Ihre Rolle mithilfe derRoleName
-Eigenschaft des Anforderungstextes angeben.az cosmosdb sql role definition create \ --resource-group "<resource-group-name>" \ --account-name "<account-name>" \ --body '{ "RoleName": "<role-definition-name>", "Type": "CustomRole", "AssignableScopes": ["/"], "Permissions": [{ "DataActions": [ "Microsoft.DocumentDB/databaseAccounts/readMetadata", "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*", "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*" ] }] }'
Listen Sie die von Ihnen erstellte Rollendefinition auf, um ihren eindeutigen Bezeichner in der JSON-Ausgabe abzurufen. Notieren Sie sich den
id
-Wert der JSON-Ausgabe.az cosmosdb sql role definition list \ --resource-group "<resource-group-name>" \ --account-name "<account-name>"
[ { ..., "id": "/subscriptions/<subscription-id>/resourceGroups/<resource-grou-name>/providers/Microsoft.DocumentDB/databaseAccounts/<account-name>/sqlRoleDefinitions/<role-definition-id>", ... "permissions": [ { "dataActions": [ "Microsoft.DocumentDB/databaseAccounts/readMetadata", "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/items/*", "Microsoft.DocumentDB/databaseAccounts/sqlDatabases/containers/*" ], "notDataActions": [] } ], ... } ]
Verwenden Sie
az cosmosdb sql role assignment create
, um eine Rollenzuweisung zu erstellen. Ersetzen Sie die<aad-principal-id>
durch die Objekt-ID, die Sie sich weiter oben in diesem Artikel notiert haben. Ersetzen Sie auch<role-definition-id>
durch denid
-Wert, der bei der Ausführung des Befehlsaz cosmosdb sql role definition list
in einem vorherigen Schritt abgerufen wurde.az cosmosdb sql role assignment create \ --resource-group "<resource-group-name>" \ --account-name "<account-name>" \ --scope "/" \ --principal-id "<account-name>" \ --role-definition-id "<role-definition-id>"
Verwenden eines Dienstprinzipals
Nachdem Sie nun eine Microsoft Entra-Anwendung und einen Dienstprinzipal erstellt, eine benutzerdefinierte Rolle erstellt und dieser Rolle Berechtigungen für Ihr Azure Cosmos DB for NoSQL-Konto zugewiesen haben, sollten Sie ein Notebook ausführen können.
Öffnen Sie Ihren Azure Databricks-Arbeitsbereich.
Erstellen Sie auf der Oberfläche des Arbeitsbereichs einen neuen Cluster. Konfigurieren Sie den Cluster mit den folgenden (minimalen) Einstellungen:
Version Wert Laufzeitversion 13.3 LTS (Scala 2.12, Spark 3.4.1)
Verwenden Sie die Benutzeroberfläche des Arbeitsbereichs, um in Maven Central nach Maven-Paketen mit der Gruppen-ID
com.azure.cosmos.spark
zu suchen. Installieren Sie das für Spark 3.4 spezifische Paket (der Artefakt-ID des Clusters hat das Präfixazure-cosmos-spark_3-4
).Erstellen Sie zuletzt neues Notebook.
Tipp
Standardmäßig wird das Notebook an den zuletzt erstellten Cluster angefügt.
Legen Sie im Notebook die Konfigurationseinstellungen des Spark-Connectors von Azure Cosmos DB für den NoSQL-Kontoendpunkt, den Datenbanknamen und den Containernamen fest. Verwenden Sie die Abonnement-ID, die Ressourcengruppe, die Anwendungs-ID (Client-ID), die Verzeichnis-ID (Mandanten-ID) und die Werte für den geheimen Clientschlüssel, die Sie sich weiter oben in diesem Artikel notiert haben.
# Set configuration settings config = { "spark.cosmos.accountEndpoint": "<nosql-account-endpoint>", "spark.cosmos.auth.type": "ServicePrincipal", "spark.cosmos.account.subscriptionId": "<subscription-id>", "spark.cosmos.account.resourceGroupName": "<resource-group-name>", "spark.cosmos.account.tenantId": "<entra-tenant-id>", "spark.cosmos.auth.aad.clientId": "<entra-app-client-id>", "spark.cosmos.auth.aad.clientSecret": "<entra-app-client-secret>", "spark.cosmos.database": "<database-name>", "spark.cosmos.container": "<container-name>" }
// Set configuration settings val config = Map( "spark.cosmos.accountEndpoint" -> "<nosql-account-endpoint>", "spark.cosmos.auth.type" -> "ServicePrincipal", "spark.cosmos.account.subscriptionId" -> "<subscription-id>", "spark.cosmos.account.resourceGroupName" -> "<resource-group-name>", "spark.cosmos.account.tenantId" -> "<entra-tenant-id>", "spark.cosmos.auth.aad.clientId" -> "<entra-app-client-id>", "spark.cosmos.auth.aad.clientSecret" -> "<entra-app-client-secret>", "spark.cosmos.database" -> "<database-name>", "spark.cosmos.container" -> "<container-name>" )
Konfigurieren Sie mithilfe von Spark die Katalog-API zum Verwalten der API für NoSQL-Ressourcen.
# Configure Catalog Api spark.conf.set("spark.sql.catalog.cosmosCatalog", "com.azure.cosmos.spark.CosmosCatalog") spark.conf.set("spark.sql.catalog.cosmosCatalog.spark.cosmos.accountEndpoint", "<nosql-account-endpoint>") spark.conf.set("spark.sql.catalog.cosmosCatalog.spark.cosmos.auth.type", "ServicePrincipal") spark.conf.set("spark.sql.catalog.cosmosCatalog.spark.cosmos.account.subscriptionId", "<subscription-id>") spark.conf.set("spark.sql.catalog.cosmosCatalog.spark.cosmos.account.resourceGroupName", "<resource-group-name>") spark.conf.set("spark.sql.catalog.cosmosCatalog.spark.cosmos.account.tenantId", "<entra-tenant-id>") spark.conf.set("spark.sql.catalog.cosmosCatalog.spark.cosmos.auth.aad.clientId", "<entra-app-client-id>") spark.conf.set("spark.sql.catalog.cosmosCatalog.spark.cosmos.auth.aad.clientSecret", "<entra-app-client-secret>")
// Configure Catalog Api spark.conf.set(s"spark.sql.catalog.cosmosCatalog", "com.azure.cosmos.spark.CosmosCatalog") spark.conf.set(s"spark.sql.catalog.cosmosCatalog.spark.cosmos.accountEndpoint", "<nosql-account-endpoint>") spark.conf.set(s"spark.sql.catalog.cosmosCatalog.spark.cosmos.auth.type", "ServicePrincipal") spark.conf.set(s"spark.sql.catalog.cosmosCatalog.spark.cosmos.account.subscriptionId", "<subscription-id>") spark.conf.set(s"spark.sql.catalog.cosmosCatalog.spark.cosmos.account.resourceGroupName", "<resource-group-name>") spark.conf.set(s"spark.sql.catalog.cosmosCatalog.spark.cosmos.account.tenantId", "<entra-tenant-id>") spark.conf.set(s"spark.sql.catalog.cosmosCatalog.spark.cosmos.auth.aad.clientId", "<entra-app-client-id>") spark.conf.set(s"spark.sql.catalog.cosmosCatalog.spark.cosmos.auth.aad.clientSecret", "<entra-app-client-secret>")
Erstellen Sie eine neue Datenbank mithilfe von
CREATE DATABASE IF NOT EXISTS
. Geben Sie Ihren Datenbanknamen an.# Create a database using the Catalog API spark.sql("CREATE DATABASE IF NOT EXISTS cosmosCatalog.{};".format("<database-name>"))
// Create a database using the Catalog API spark.sql(s"CREATE DATABASE IF NOT EXISTS cosmosCatalog.<database-name>;")
Erstellen Sie einen neuen Container unter Verwendung des Datenbanknamens, des Containernamens, des Partitionsschlüsselpfads und der von Ihnen angegebenen Durchsatzwerte.
# Create a products container using the Catalog API spark.sql("CREATE TABLE IF NOT EXISTS cosmosCatalog.{}.{} USING cosmos.oltp TBLPROPERTIES(partitionKeyPath = '{}', manualThroughput = '{}')".format("<database-name>", "<container-name>", "<partition-key-path>", "<throughput>"))
// Create a products container using the Catalog API spark.sql(s"CREATE TABLE IF NOT EXISTS cosmosCatalog.<database-name>.<container-name> using cosmos.oltp TBLPROPERTIES(partitionKeyPath = '<partition-key-path>', manualThroughput = '<throughput>')")
Erstellen Sie ein Beispieldataset.
# Create sample data products = ( ("68719518391", "gear-surf-surfboards", "Yamba Surfboard", 12, 850.00, False), ("68719518371", "gear-surf-surfboards", "Kiama Classic Surfboard", 25, 790.00, True) )
// Create sample data val products = Seq( ("68719518391", "gear-surf-surfboards", "Yamba Surfboard", 12, 850.00, false), ("68719518371", "gear-surf-surfboards", "Kiama Classic Surfboard", 25, 790.00, true) )
Verwenden Sie
spark.createDataFrame
und die zuvor gespeicherte OLTP-Konfiguration (Online Transaction Processing), um Beispieldaten zum Zielcontainer hinzuzufügen.# Ingest sample data spark.createDataFrame(products) \ .toDF("id", "category", "name", "quantity", "price", "clearance") \ .write \ .format("cosmos.oltp") \ .options(config) \ .mode("APPEND") \ .save()
// Ingest sample data spark.createDataFrame(products) .toDF("id", "category", "name", "quantity", "price", "clearance") .write .format("cosmos.oltp") .options(config) .mode("APPEND") .save()
Tipp
In diesem Schnellstartbeispiel werden den Variablen Anmeldeinformationen im Klartext zugewiesen. Aus Sicherheitsgründen wird empfohlen, Geheimnisse zu verwenden. Weitere Informationen zum Konfigurieren von Geheimnissen finden Sie unter Hinzufügen von Geheimnissen zu Ihrer Spark-Konfiguration.