다음을 통해 공유


Azure Cosmos DB for NoSQL용 Spark 3 커넥터와 함께 서비스 주체 사용

이 문서에서는 역할 기반 액세스 제어와 함께 사용할 수 있는 Microsoft Entra 애플리케이션 및 서비스 주체를 만드는 방법을 알아봅니다. 그런 다음 이 서비스 주체를 사용하여 Spark 3에서 Azure Cosmos DB for NoSQL 계정에 연결할 수 있습니다.

필수 조건

비밀 및 자격 증명 기록하기

이 섹션에서는 클라이언트 암호를 만들고 나중에 사용할 수 있도록 값을 기록합니다.

  1. Azure Portal을 엽니다.

  2. 기존 Microsoft Entra 애플리케이션으로 이동합니다.

  3. 인증서 및 비밀 페이지로 이동합니다. 그런 다음 새 비밀을 만듭니다. 이 문서의 뒷부분에서 사용할 수 있도록 클라이언트 암호 값을 저장합니다.

  4. 개요 페이지로 이동합니다. 애플리케이션(클라이언트) ID, 개체 ID디렉터리(테넌트) ID 값을 찾아서 기록합니다. 이 문서의 뒷부분에서도 이러한 값을 사용합니다.

  5. 기존 Azure Cosmos DB for NoSQL 계정으로 이동합니다.

  6. 개요 페이지에서 URI 값을 기록합니다. 또한 구독 ID리소스 그룹 값을 기록해 둡니다. 이 문서의 뒷부분에서 이러한 값을 사용합니다.

정의 및 할당 만들기

이 섹션에서는 Microsoft Entra ID 역할 정의를 만듭니다. 그런 다음, 컨테이너에서 항목을 읽고 쓸 수 있는 권한이 있는 역할을 할당합니다.

  1. az role definition create 명령을 사용하여 역할을 만듭니다. Azure Cosmos DB for 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 출력에서 고유 식별자를 페치 위해 만든 역할 정의를 나열합니다. JSON 출력의 id 값을 기록합니다.

    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>를 이 문서의 앞부분에서 기록한 개체 ID로 바꿉니다. 또한 <role-definition-id>를 이전 단계의 az cosmosdb sql role definition list 명령 실행에서 가져온 id 값으로 바꿉니다.

    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 for NoSQL 계정에 할당했으므로 Notebook을 실행할 수 있습니다.

  1. Azure Databricks 작업 영역을 엽니다.

  2. 작업 영역 인터페이스에서 새 클러스터를 만듭니다. 최소한 다음 설정을 사용하여 클러스터를 구성합니다.

    버전
    런타임 버전 13.3 LTS (Scala 2.12, Spark 3.4.1)
  3. 작업 영역 인터페이스를 사용하여 com.azure.cosmos.spark그룹 IDMaven Central에서 Maven 패키지를 검색합니다. 접두사 azure-cosmos-spark_3-4이 붙은 아티팩트 ID를 사용하여 Spark 3.4용 패키지를 클러스터에 설치합니다.

  4. 마지막으로 새 Notebook을 만듭니다.

    기본적으로 Notebook은 최근 만들어진 클러스터에 연결됩니다.

  5. Notebook 내에서 NoSQL 계정 엔드포인트, 데이터베이스 이름, 컨테이너 이름에 대한 Azure Cosmos DB Spark 커넥터 구성 설정을 지정합니다. 이 문서의 앞부분에 기록된 구독 ID, 리소스 그룹, 애플리케이션(클라이언트) ID, 디렉터리(테넌트) ID, 클라이언트 암호 값을 사용합니다.

    # 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. Spark를 사용하여 API for NoSQL 리소스를 관리하도록 카탈로그 API를 구성합니다.

    # 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 구성에 비밀 추가를 참조하세요.