Compartir a través de


Uso de una entidad de servicio con el conector Spark 3 para Azure Cosmos DB for NoSQL

En este artículo, aprenderá a crear una aplicación de Microsoft Entra y una entidad de servicio que se puede usar con el control de acceso basado en rol. Después, puede usar esta entidad de servicio para conectarse a una cuenta de Azure Cosmos DB for NoSQL desde Spark 3.

Requisitos previos

Creación de credenciales secretas y de registro

En esta sección, crearemos un secreto de cliente y registraremos el valor para usarlo más adelante.

  1. Abra Azure Portal.

  2. Vaya a la aplicación Microsoft Entra existente.

  3. En la página Certificados y secretos: Después, cree un secreto. Guarde el secreto de cliente para usarlo más adelante en esta guía.

  4. Vaya a la página Información general. Busque y registre los valores de Id. de aplicación (cliente), Id. de objeto e Id. de directorio (inquilino). Estos valores se usarán más adelante en el tutorial.

  5. Vaya a su cuenta Azure Cosmos DB for NoSQL existente.

  6. Registre el valor del URI en la página Información general. Registre también los valores de Id. de suscripción y Grupo de recursos. Usará estos valores más adelante en este artículo.

Creación de una definición y una asignación

En esta sección, creará una definición de rol de id. de Entra de Microsoft. A continuación, asigne ese rol con permisos para leer y escribir elementos en los contenedores.

  1. Cree un rol utilizando el comando az role definition create. Pase el nombre de la cuenta y el grupo de recursos de Azure Cosmos DB for NoSQL, seguido de un cuerpo de JSON que defina el rol personalizado. El rol también tiene como ámbito el nivel de cuenta mediante /. Asegúrese de proporcionar un nombre único para el rol mediante la propiedad RoleName del cuerpo de la solicitud.

    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/*"
                ]
            }]
        }'
    
  2. Enumere la definición de rol que creó para capturar su identificador único en la salida JSON. Registre el valor id de la salida JSON.

    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": []
          }
        ],
        ...
      }
    ]
    
  3. Use az cosmosdb sql role assignment create para crear una asignación de roles. Reemplace <aad-principal-id> por el identificador de objeto que registró anteriormente en esta guía. Además, reemplace <role-definition-id> por el valor id capturado al ejecutar el comando az cosmosdb sql role definition list que ejecutó en un paso anterior.

    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>"
    

Uso de una entidad de servicio

Ahora que ha creado una aplicación de Microsoft Entra y una entidad de servicio, ha creado un rol personalizado y ha asignado los permisos de ese rol a su cuenta de Azure Cosmos DB for NoSQL, debería ser capaz de ejecutar un cuaderno.

  1. Abra el área de trabajo de Azure Databricks.

  2. En la interfaz del área de trabajo, cree un nuevo clúster. Configure el clúster con estas opciones, como mínimo:

    Versión Valor
    Versión del entorno de ejecución 13.3 LTS (Scala 2.12, Spark 3.4.1)
  3. Use la interfaz del área de trabajo para buscar paquetes de Maven desde Central de Maven con un Id. de grupo de com.azure.cosmos.spark. Instale el paquete específicamente para Spark 3.4 con unId.de Artefacto prefijo con azure-cosmos-spark_3-4 en el clúster.

  4. Por último, cree un nuevo cuaderno.

    Sugerencia

    De manera predeterminada, el cuaderno está asociado al clúster creado recientemente.

  5. Dentro del cuaderno, establezca los ajustes de configuración del conector Spark de Azure Cosmos DB para el punto final de la cuenta NoSQL, el nombre de la base de datos y el nombre del contenedor. Use los valores Id.de suscripción, Grupo de recursos, Id. de aplicación (cliente), Id.de directorio (inquilino) y Secreto de cliente registrados anteriormente en esta guía.

    # 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>" 
    )
    
  6. Configure la API de catálogo para administrar la API para recursos NoSQL mediante Spark.

    # 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>")
    
  7. Cree una nueva base de datos mediante CREATE DATABASE IF NOT EXISTS. Asegúrese de proporcionar el nombre de la base de datos.

    # 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>;")
    
  8. Cree un contenedor con el nombre de la base de datos, el nombre del contenedor, la ruta de acceso de clave de partición y los valores de rendimiento que especifique.

    # 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>')")
    
  9. Cree un conjunto de datos de ejemplo.

    # 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)
    )
    
  10. Use spark.createDataFrame y la configuración de procesamiento de transacciones en línea (OLTP) guardadas anteriormente para agregar datos de ejemplo al contenedor de destino.

    # 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()
    

    Sugerencia

    En este ejemplo de inicio rápido, las credenciales se asignan a variables en texto no cifrado. Por motivos de seguridad, se recomienda usar secretos. Para más información sobre cómo configurar secretos, consulte Adición de secretos a la configuración de Spark.