閉域構成の Azure Databricks でプロキシ設定を試してみた

## はじめに
閉域構成の Azrure Databricks からインターネットへ通信（ライブラリのインストール）する際にプロキシサーバを経由する方法を検証してみました。
構成は以下のようなイメージとなります。仮想ネットワーク vnet_spoke-01 にあるクラスターから仮想ネットワーク vnet_on-premises にあるプロキシサーバ（vm-proxy）を経由してインターネットに出るように設定していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/59f922b1-4470-4e9a-a6ea-ad1fd17fa982.png)

## 閉域構成の Azrure Databricks の作成
Azrure Databricks のデプロイについてはこちらの記事をご参照ください。
（本構成では vnet_hub 内のワークスペースへの接続用 VM は不要のため、作成しなくても問題ないです）

https://qiita.com/satoshi_enomoto/items/f8b688c1a0ae6bcd6364

## プロキシサーバの設定
プロキシサーバの設定についてはこちらの記事をご参照ください。

https://qiita.com/satoshi_enomoto/items/75a5ba02c034e05094a8

追加の設定として、プロキシサーバ（vm-proxy）のファイアウォールの受信規則の追加が必要となります。
「セキュリティが強化された Windows Defender ファイアウォール」 > 「受信の規則：Squid Cache Server」 > 「スコープ」 > 「リモートIPアドレス」 で vnet_spoke-01 のアドレス範囲（10.1.0.0/16）を追加します。
（ホストサブネットのアドレス範囲が含まれていればOKのはずです）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/32ac7fe8-b908-4314-8399-33da4ead8fce.png)

## VNet 間接続の構成
vnet_on-premises（疑似オンプレネットワーク）と vnet_hub の接続については VPN ゲートウェイを用いた VNet 間接続で構成しました。VNet 間接続の構成およびワークスペースへの接続についてはこちらの記事をご参照ください。

https://qiita.com/satoshi_enomoto/items/9d011f5e6d49750ad304

## 仮想ネットワークのピアリング設定
Azrure Databricks における仮想ネットワークピアリングの概要は以下となります。
今回は Databricks をデプロイしている vnet_spoke-01 と vnet_hub のピアリングを設定していきます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/28a36eb6-ccd3-4a19-adba-0bbf33ff137f.png)

https://learn.microsoft.com/ja-jp/azure/databricks/security/network/classic/vnet-peering

また、vnet_hub に VPN ゲートウェイを構成しているため、以下の手順を基に設定しました。

https://learn.microsoft.com/ja-jp/azure/vpn-gateway/vpn-gateway-peering-gateway-transit#to-add-a-peering-and-enable-transit

vnet_hub からピアリングを開き、追加を選択します。
設定値は以下の通りとなります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/d8931f6a-64ba-46f3-8f67-3d93a7926cd1.png)

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/b4ed780a-a1ce-4d52-a784-d3a956f8df8b.png)

正常に設定できると以下のようになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/ec26b3ee-d6bc-4091-bacc-b34058af8d7a.png)

ここまででクラスターからプロキシサーバのネットワークが繋がったことになります。

## 接続確認
ノートブックでプロキシを設定したライブラリのインストールを実行すると正常に完了することが確認できます。
プロキシには vm-proxy のプライベート IP と Squid のポートを指定します。

```python:
%pip install --proxy http://<プロキシのプライベート IP>:<Squid のポート> <ライブラリ名>
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/11bb1568-8680-49e4-a376-8a0da6c4175d.png)

## Databricks でのプロキシ設定
ここではグローバル init スクリプトを使用したプロキシ設定の方法を紹介したいと思います。
以下のようにスクリプトを設定して、クラスターを再起動します。

```bash:
#!/bin/bash

proxy="http://<プロキシのプライベート IP>:<Squid のポート>"

echo "export http_proxy=${proxy}" >> /databricks/spark/conf/spark-env.sh
echo "export https_proxy=${proxy}" >> /databricks/spark/conf/spark-env.sh
echo "export no_proxy=<ワークスペース ID >,localhost,127.0.0.1,<ワークスペースのリージョン>.azuredatabricks.net" >> /databricks/spark/conf/spark-env.sh

echo "export http_proxy=${proxy}" >> /etc/environment
echo "export https_proxy=${proxy}" >> /etc/environment
echo "export no_proxy=<ワークスペース ID >,localhost,127.0.0.1,<ワークスペースのリージョン>.azuredatabricks.net" >> /etc/environment

pip config set global.proxy ${proxy}

exit 0
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/54dcb5de-1f71-4e07-b943-69a699a0ef5c.png)

:::note info
no_proxy について
http_proxy を設定すると Databricks 内の通信もプロキシサーバを経由してしまい、クラスターが Volume や Workspace フォルダにアクセスできない事象が発生します。
そのため、Databricks 内の通信については no_proxy を設定する必要があるようです。
参考記事は[こちら](https://kb.databricks.com/clusters/cluster-startup-failure-while-running-proxy-configured-init-script-with-other-init-scripts?from_search=181962211)。
:::

以下のコードでプロキシが設定されているか確認できます。

```python:
import os

for key, value in os.environ.items():
    print(f'{key}={value}')
```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/5fede0c1-3b9b-4d0e-b6a2-0371f73a7bd5.png)

グローバル init で設定されているため、ライブラリのインストール時はプロキシを指定しなくても正常に完了することが確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/50dbe648-4568-4750-ba81-2b6bbe09d895.png)

また、インターネットへ出ていく際のグローバル IP を取得してみると、プロキシサーバ（vm-proxy）のパブリック IP が表示されます。

```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)
```

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3478068/c569e071-35b6-4ec0-83d7-5288b7d4d71d.png)

## おわりに
公式ドキュメントではグローバル init ではなく、コンピューティングポリシーまたはクラスタースコープの init が推奨されています。
コンピューティングポリシーを使用した方法は別記事で紹介したいと思います。

https://learn.microsoft.com/ja-jp/azure/databricks/init-scripts/global