Azure Cosmos DB for NoSQL용 Spark 3 커넥터와 함께 서비스 주체 사용
이 문서에서는 역할 기반 액세스 제어와 함께 사용할 수 있는 Microsoft Entra 애플리케이션 및 서비스 주체를 만드는 방법을 알아봅니다. 그런 다음 이 서비스 주체를 사용하여 Spark 3에서 Azure Cosmos DB for NoSQL 계정에 연결할 수 있습니다.
필수 조건
- 기존 Azure Cosmos DB API for NoSQL 계정.
- 기존 Azure 구독이 있는 경우 새 계정을 만듭니다.
- Azure 구독이 없으신가요? 신용 카드 없이 Azure Cosmos DB를 무료로 사용해 볼 수 있습니다.
- 기존 Azure Databricks 작업 영역
- 등록된 Microsoft Entra 애플리케이션 및 서비스 주체입니다.
- 서비스 주체와 애플리케이션이 없는 경우 Azure Portal을 사용하여 애플리케이션을 등록합니다.
비밀 및 자격 증명 기록하기
이 섹션에서는 클라이언트 암호를 만들고 나중에 사용할 수 있도록 값을 기록합니다.
Azure Portal을 엽니다.
기존 Microsoft Entra 애플리케이션으로 이동합니다.
인증서 및 비밀 페이지로 이동합니다. 그런 다음 새 비밀을 만듭니다. 이 문서의 뒷부분에서 사용할 수 있도록 클라이언트 암호 값을 저장합니다.
개요 페이지로 이동합니다. 애플리케이션(클라이언트) ID, 개체 ID 및 디렉터리(테넌트) ID 값을 찾아서 기록합니다. 이 문서의 뒷부분에서도 이러한 값을 사용합니다.
기존 Azure Cosmos DB for NoSQL 계정으로 이동합니다.
개요 페이지에서 URI 값을 기록합니다. 또한 구독 ID 및 리소스 그룹 값을 기록해 둡니다. 이 문서의 뒷부분에서 이러한 값을 사용합니다.
정의 및 할당 만들기
이 섹션에서는 Microsoft Entra ID 역할 정의를 만듭니다. 그런 다음, 컨테이너에서 항목을 읽고 쓸 수 있는 권한이 있는 역할을 할당합니다.
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/*" ] }] }'
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": [] } ], ... } ]
역할 할당을 만들려면
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을 실행할 수 있습니다.
Azure Databricks 작업 영역을 엽니다.
작업 영역 인터페이스에서 새 클러스터를 만듭니다. 최소한 다음 설정을 사용하여 클러스터를 구성합니다.
버전 값 런타임 버전 13.3 LTS (Scala 2.12, Spark 3.4.1)
작업 영역 인터페이스를 사용하여
com.azure.cosmos.spark
의 그룹 ID로 Maven Central에서 Maven 패키지를 검색합니다. 접두사azure-cosmos-spark_3-4
이 붙은 아티팩트 ID를 사용하여 Spark 3.4용 패키지를 클러스터에 설치합니다.마지막으로 새 Notebook을 만듭니다.
팁
기본적으로 Notebook은 최근 만들어진 클러스터에 연결됩니다.
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>" )
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>")
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>;")
지정한 데이터베이스 이름, 컨테이너 이름, 파티션 키 경로, 처리량 값을 사용하여 새 컨테이너를 만듭니다.
# 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>')")
샘플 데이터 세트를 만듭니다.
# 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) )
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 구성에 비밀 추가를 참조하세요.