Azure DatabricksをPlivate Link構成でデプロイしてみた

## はじめに
Azure Databricks を Private Link 構成によるデプロイを試してみました。
構成は以下のようなイメージとなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/bf11f7d2-a975-4a2c-ba1b-827480e65283.png)

今回は標準デプロイで実施しました。詳細は以下のドキュメントをご確認ください。

https://learn.microsoft.com/ja-jp/azure/databricks/security/network/classic/private-link-standard

## 仮想ネットワークを作成
Databricksをデプロイするための仮想ネットワークは以下の要件を満たす必要があります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/4c9741ed-ac66-4c32-ac8c-8036db440f46.png)

https://learn.microsoft.com/ja-jp/azure/databricks/security/network/classic/vnet-inject#virtual-network-requirements

今回は以下のように仮想ネットワークを作成しました。

|  | 仮想ネットワーク① | 仮想ネットワーク② |
|:-----------|:------------|:------------|
| 仮想ネットワーク名 | vnet_hub | vnet_spoke-01 |
| アドレス範囲 | 172.16.0.0/16 | 10.1.0.0/16 |
| サブネット① | private-endpoint | databricks_host |
| サブネット①範囲 | 172.16.0.0/27 | 10.1.0.0/24 |
| サブネット①用途 | プライベートエンドポイント用 | Databricks のホストサブネット（パブリックサブネット）|
| サブネット② | default | databricks_container |
| サブネット②範囲 | 172.16.0.32/29 | 10.1.1.0/24 |
| サブネット②用途 | DatabricksへアクセスするためのVM用 |  Databricks のコンテナサブネット（プライベートサブネット） |
| サブネット③ | - | private-endpoint |
| サブネット③範囲 | - | 10.1.2.0/27 |
| サブネット③用途 | - | プライベートエンドポイント用 |

## Azure Databricks ワークスペースとプライベートエンドポイントを作成
以下のドキュメントの手順を基に作成しました。

https://learn.microsoft.com/ja-jp/azure/databricks/security/network/classic/private-link-standard#create-the-workspace-and-private-endpoints-in-the-azure-portal-ui

ワークスペースの設定値は以下となります。価格レベルは Premium としています。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/714724cd-2236-48ef-bda5-5cae62012505.png)

:::note info
Nat Gatewayについて
ドキュメントの手順には無かった、Nat Gateway の設定値があります。おそらくですが、[Azure の仮想マシンの既定の送信アクセス接続の廃止](https://azure.microsoft.com/en-us/updates?id=default-outbound-access-for-vms-in-azure-will-be-retired-transition-to-a-new-method-of-internet-access)が予定されているため、クラスター（VM）のアウトバウンド用に Nat Gateway が強制的に作成されるようです。
既定の送信アクセスについては[こちら](https://learn.microsoft.com/ja-jp/azure/virtual-network/ip-services/default-outbound-access)をご確認ください。
:::

ワークスペースと同時にバックエンド用のプライベートエンドポイントを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/8d08ee8a-5794-464f-8aed-88a7a677313b.png)

上記以外（暗号化や Security & compliance）の設定値はデフォルトのままで作成しました。

続いてフロントエンド用のプライベートエンドポイントを作成します。設定値は以下の通り。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/787c2168-a2d5-4b3d-a7bd-f710b0248281.png)

最後に Web ブラウザー認証用のプライベートエンドポイントを作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/0a58c72f-14c4-49df-99e6-28d3cbcd2d4f.png)

:::note info
Web ブラウザー認証用のプライベートエンドポイントについて
Web ブラウザー認証用のプライベートエンドポイントをホストするためのワークスペースを別途作成することが推奨されていますが、今回はワークスペースを１つにしています。
詳細は[こちら](https://learn.microsoft.com/ja-jp/azure/databricks/security/network/classic/private-link-standard#step-4-create-a-private-endpoint-to-support-sso-for-web-browser-access)をご確認ください。
:::

また、プライベート DNS ゾーンは以下のように設定しています。
* privatelink.azuredatabricks.net は 以下のようにレコードをセットして vnet_spoke-01 にリンク

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/986426fb-b4ba-4a25-8cdd-e0fb57941489.png)

* azuredatabricks.net は 以下のようにレコードをセットして vnet_hub にリンク

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/6b5e2529-4196-4e3f-b955-0bda795c38ec.png)

:::note info
adb-dp-xxx.xxのレコードセットについて
クラスターの Spark UI を表示するために必要なレコードとなります。
Spark UI を新規タブで開いて、URL を確認してみるとワークスペースの FQDN とは異なることがわかります。
そのため別途名前解決が必要なようです。

* Spark UI の URL

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/322dbd65-c776-4546-ac0a-3bfa3505a4c5.png)

* ワークスペースの URL

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/60edfb62-6c60-4b24-b376-c3e65bc8c5f9.png)
:::

## テスト
### Databricks ワークスペースへの接続テスト
vnet_hub 内にワークスペースへの接続用VM（vm-connect-check）をデプロイします。これにより、プライベートDNSゾーン（azuredatabricks.net）でフロントエンドとWeb ブラウザー認証用のプライベートエンドポイントへの名前解決が可能となるため、ワークスペースへの接続が可能となります。
リモートデスクトップ接続でVMに入って、ワークスペースに接続すると以下のように接続できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/86397466-3751-4e4d-ae1f-f6e361402464.png)

:::note info
ローカル端末からの接続について
以下のように接続に失敗します。これはローカル端末が存在するネットワークと仮想ネットワークがつながっていないためとなります。
これによりパブリックネットワークからのアクセスが無効となっていることが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/00724cc5-a3b6-4c3b-a5fd-a95d431adb50.png)

:::

### クラスターテスト
クラスター（Personal Compute）を作成して JSON を表示すると、プライベート IP とパブリック IP を確認することができます。
プライベート IP はコンテナサブネットの範囲、パブリック IP はホストサブネットの範囲になっていることがわかります。
今回は Vnet インジェクションでデプロイしているため、どちらもプライベート IP となっていますが、既定のデプロイの場合は片方がパブリック IP となるはずです。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/b7cf5126-bf1d-4acf-b2fd-94c65c284f5c.png)

また、以下のようにインターネットへ出ていく際のグローバル IP を取得してみると、強制的に作成された Nat Gateway のパブリック IP が表示されます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/fb69ee84-b291-45b9-86ca-798fbdba3f09.png)

<details><summary>グローバル IP を取得するサンプルコード</summary>

```python:
import requests

def get_public_ip():
    response = requests.get('https://api.ipify.org?format=json')
    ip = response.json()['ip']
    return ip

# グローバルIPアドレスを取得する
public_ip = get_public_ip()
print(public_ip)
```

</details>

## おわりに
Databricks の閉域構成について以下の記事がとても参考になりました。
併せてご参照ください。

https://speakerdeck.com/nakazax/azure-databricks-learning-series-number-3-network-design

https://qiita.com/samskeyti/items/08985ba910fae726124e