Поделиться через


Использование субъекта-службы с соединителем Spark 3 для Azure Cosmos DB для NoSQL

В этой статье вы узнаете, как создать приложение Microsoft Entra и субъект-службу, которые можно использовать с управлением доступом на основе ролей. Затем эту службу можно использовать для подключения к учетной записи Azure Cosmos DB для NoSQL из Spark 3.

Необходимые компоненты

Создание секрета и учетных данных записи

В этом разделе вы создадите секрет клиента и запишите значение для последующего использования.

  1. Откройте портал Azure.

  2. Перейдите к существующему приложению Microsoft Entra.

  3. Перейдите на страницу "Сертификаты и секреты ". Затем создайте новый секрет. Сохраните значение секрета клиента для использования далее в этой статье.

  4. Перейдите на страницу Обзор. Найдите и запишите значения для идентификатора приложения (клиента), идентификатора объекта и каталога (клиента). Эти значения также используются далее в этой статье.

  5. Перейдите к существующей учетной записи Azure Cosmos DB для NoSQL.

  6. Запишите значение URI на странице обзора. Также запишите значения идентификатора подписки и группы ресурсов. Эти значения используются далее в этой статье.

Создание определения и назначения

В этом разделе описано, как создать определение роли идентификатора Microsoft Entra. Затем вы назначите эту роль с разрешениями на чтение и запись элементов в контейнерах.

  1. Создайте роль с помощью az role definition create команды. Передайте имя учетной записи и группу ресурсов Azure Cosmos DB для NoSQL, а затем текст JSON, определяющий пользовательскую роль. Роль также распространяется на уровень учетной записи с помощью /. Убедитесь, что вы предоставляете уникальное имя для роли с помощью RoleName свойства текста запроса.

    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. Перечислите определение роли, созданное для получения уникального идентификатора в выходных данных JSON. id Запишите значение выходных данных 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. Используется az cosmosdb sql role assignment create для создания назначения ролей. Замените <aad-principal-id> идентификатор объекта, записанный ранее в этой статье. Кроме того, замените <role-definition-id> id значение, полученное при выполнении az cosmosdb sql role definition list команды на предыдущем шаге.

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

Использование субъекта-службы

Теперь, когда вы создали приложение Microsoft Entra и субъект-службу, создали пользовательскую роль и назначили этим разрешениям роли учетной записи Azure Cosmos DB для NoSQL, вы сможете запустить записную книжку.

  1. Откройте рабочую область Azure Databricks.

  2. В интерфейсе рабочей области создайте новый кластер. Настройте кластер с этими параметрами как минимум:

    Версия Значение
    Версия среды выполнения 13.3 LTS (Scala 2.12, Spark 3.4.1)
  3. Используйте интерфейс рабочей области для поиска пакетов Maven из Maven Central с идентификатором com.azure.cosmos.sparkгруппы. Установите пакет специально для Spark 3.4 с префиксом идентификатора артефакта, заданным в azure-cosmos-spark_3-4 кластере.

  4. Наконец, создайте новую записную книжку.

    Совет

    По умолчанию записная книжка подключена к недавно созданному кластеру.

  5. В записной книжке задайте параметры конфигурации соединителя Spark Azure Cosmos DB для конечной точки учетной записи NoSQL, имени базы данных и имени контейнера. Используйте идентификатор подписки, группу ресурсов, идентификатор приложения (клиента), идентификатор каталога (клиента) и значения секрета клиента, записанные ранее в этой статье.

    # 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. Настройте API каталога для управления ресурсами API noSQL с помощью 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. Создайте новую базу данных с помощью CREATE DATABASE IF NOT EXISTS. Убедитесь, что укажите имя базы данных.

    # 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. Создайте контейнер с помощью имени базы данных, имени контейнера, пути ключа секции и заданных значений пропускной способности.

    # 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. Создание примера набора данных.

    # 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. Используйте spark.createDataFrame и ранее сохраненную конфигурацию обработки транзакций (OLTP) для добавления примеров данных в целевой контейнер.

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

    Совет

    В этом кратком руководстве учетные данные назначаются переменным в виде ясного текста. Для безопасности рекомендуется использовать секреты. Дополнительные сведения о настройке секретов см. в разделе "Добавление секретов в конфигурацию Spark".