Databricks – łączenie z danymi z Azure SQL Database i Azure Storage za pomocą Entra, hasła i loginu oraz Key Vault

Połączenie z Azure SQL Database – za pomocą loginu i hasła – bez użycia Azure Key Vault

Aby połączyć się z bazą Azure SQL za pomocą loginu i hasła, musimy podać w kodzie hasło do bazy, login do bazy, nazwę serwera (nie bazy) na którym nasza baza jest postawiona i nazwę bazy. Nazwy te możemy odczytać po zalogowaniu do bazy w portalu Azure

Kod do pobrania z bazy Azure SQL danych z tabeli Sales:

server_name = "serverdawidbrejecki.database.windows.net"

database_name = "sqldawidbrejecki"

username = "dawidbrejecki"

password = ""

jdbc_url = f"jdbc:sqlserver://{server_name}:1433;database={database_name}"

connection_properties = {

    "user": username,

    "password": password,

    "driver": "com.microsoft.sqlserver.jdbc.SQLServerDriver"

}

query = "SELECT * FROM sales"

df = spark.read.jdbc(url=jdbc_url, table=f"({query}) as query", properties=connection_properties)

Do zmiennej query przypisujemy zapytanie SQL które wyciąga nam informacje z bazy. Może być ono bardziej skomplikowane i wyciągać informacje np z dwóch tabel z bazy np.

select order_date, customer_name from sales left join customers on sales.customer_id=customer.id

Podczas próby łączenia się z bazą może pojawić się błąd typu:

Oznacza to, że IP naszych zasobów Databricks jest blokowany przez serwer Azure SQL. Aby to naprawić trzeba najpierw poznać nasz adres (ze strony Databricks) lub za pomocą kodu:

Uzyskany adres IP dodajemy do reguły firewalla naszego serwera Azure SQL:

Zapis do tabeli w Azure SQL Database

W kodzie musimy sprecyzować nazwę tabeli do jakiej zapisujemy – u nas do new_sales_data

df.write \

    .format("jdbc") \

    .option("url", jdbc_url) \

    .option("dbtable", "new_sales_data") \

    .option("user", jdbc_properties["user"]) \

    .option("password", jdbc_properties["password"]) \

    .option("driver", jdbc_properties["driver"]) \

    .mode("append") \

    .save()

Połączenie z Azure Blob Storage (analogicznie kroki wykonuje się dla Data Lake)

Pobieranie danych z Bloba jest mniej kłopotliwe:

storage_account_name = "blobdawidbrejecki"

container_name = "salesdata"

account_key = ""

spark.conf.set(

    f"fs.azure.account.key.{storage_account_name}.blob.core.windows.net",

    account_key

)

df = spark.read.csv(f"wasbs://{container_name}@{storage_account_name}.blob.core.windows.net/azure/sales_2021.csv", header=True)

Jako account_key pobieramy wchodząc w zakładkę Access Keys naszego bloba i kopiujemy Key:

W kodzie wpisujemy także nazwę bloba, kontenera w którym jest nasz plik z danymi oraz pełną ścieżkę do pliku.

Zapis do pliku na Blob

df.write.mode("overwrite").option("header", "true").csv(f"wasbs://{container_name}@{storage_account_name}.blob.core.windows.net/output.csv")

Połączenie do Azure Data Lake za pomocą Microsoft Entra i Azure Key Vault

Kolejnym rodzajem połączenia do naszego storage jest zarejestrowanie aplikacji w Microsoft Entra, ukrycie jej secretu w Azure Key Vault, nadanie odpowiedniej roli Databricks i wykorzystanie secret codu w notebooku.

Aby utworzyć aplikację, wyszukujemy Microsoft Entra i klikamy:

Po utworzeniu aplikacja będzie widoczna w App registrations

Klikamy na nią i spisujemy potrzebne nam później client_id oraz tenant_id

I tworzymy secret dla tej aplikacji:

Spisujemy wartość Value

Teraz przechodzimy do naszego Data Lake. Tworzymy nową rolę IAM:

Szukam roli Storage Blob Data Contributor. Taka rola pozwoli nam zarówno na odczyt jak i zapis plików na storage

Teraz najważniejsza część: jako membera naszej roli wyszukujemy i zaznaczamy naszą utworzoną wcześniej aplikację

Aby nie pisać secretu tej aplikacji w formie jawnej, tworzymy Key Vault, by dodać do niego secret. Dzięki temu w kodzie Spark będziemy odwoływać się tylko do nazwy naszego secretu, nie jego wartości.

W Key Vault aby zacząć dodawać secrety musimy utworzyć rolę dla swojego konta jako Key Vault Secret Officer.

Następnie tworzymy rolę Key Vault Secrets User dla aplikacji AzureDatabricks, aby z jej poziomu można było pobierać secrety.

Ze strony Azure wszystko jest już skonfigurowane. Przenosimy się teraz do Databricks. Najpierw tworzymy scope (kontener przechowujący secrety), do którego dodajemy zasób Key Vault:

Dodajemy scope w Azure Key Vault. Nadajemy mu nazwę oraz wklejamy jego wartość generowaną podczas tworzenia secretu dla naszej aplikacji.

Nazwę secretu oraz informacje o Key Vault z properties przydadzą nam się w kolejnych krokach.

Ze strony Azure wszystko jest już skonfigurowane. Przenosimy się teraz do Databricks. Najpierw tworzymy scope (kontener przechowujący secrety), do którego dodajemy zasób Key Vault. Aby utworzyć secret należy zamienić nasz link otwartego notebooka:

https://adb-1747152247359772.12.azuredatabricks.net/editor/notebooks/397325365964120?o=1747152247359772#command/6084179303286158

Na następujący:

https://adb-1747152247359772.12.azuredatabricks.net/#secrets/createScope

Jak widać, dodajemy #secrets/createScope na końcu adresu azuredatabricks.net

Przenosi to nas do strony, na której tworzymy scope dla naszego workspace. Podajemy Vault URL oraz Resource ID oraz nazwę scope (przyda się później)

Następujący kod umożliwia podłączenie się do Data Lake:

service_credential = dbutils.secrets.get(scope="scope602",key="secret602")

spark.conf.set("fs.azure.account.auth.type.datalakedawidbrejecki.dfs.core.windows.net", "OAuth")

spark.conf.set("fs.azure.account.oauth.provider.type.datalakedawidbrejecki.dfs.core.windows.net", "org.apache.hadoop.fs.azurebfs.oauth2.ClientCredsTokenProvider")

spark.conf.set("fs.azure.account.oauth2.client.id.datalakedawidbrejecki.dfs.core.windows.net", "3da8b5fb-c930-4dcb-8e5f-b99e9cd6f7a9")

spark.conf.set("fs.azure.account.oauth2.client.secret.datalakedawidbrejecki.dfs.core.windows.net", service_credential)

spark.conf.set("fs.azure.account.oauth2.client.endpoint.datalakedawidbrejecki.dfs.core.windows.net", "https://login.microsoftonline.com/47afbd54-bcae-422f-98c1-1be52da6638c/oauth2/token")

Objaśnienia:

scope602 – oznacza nazwę Scope utworzoną w Databricks

secret602 – jest to nazwa secretu utworzona w Key Vault

datalakedawidbrejecki – nazwa Data Lake

3da8b5fb-c930-4dcb-8e5f-b99e9cd6f7a9 – client ID aplikacji

47afbd54-bcae-422f-98c1-1be52da6638c – tenant ID aplikacji

Pobieramy dane z pliku salesall.csv w kontenerze salesall z Data Lake:

df=spark.read.csv("abfss://salesall@datalakedawidbrejecki.dfs.core.windows.net/salesall.csv")

Zalecana strona z dokumentacją:

https://docs.databricks.com/en/connect/storage/azure-storage.html