
Databricks AppsでElementaryのレポートをホスティングしてみた
さがらです。
以前、Snowpark Container Servicesを使ってElementaryのレポートをWebで閲覧できる環境を構築する記事を書きました。
これと同じ「Elementaryのレポートをチーム内で閲覧できるようにしたい」という課題を、今回はDatabricks Appsで解決できないか試してみました。Dockerイメージは作らず、Python標準ライブラリのhttp.serverだけで配信する最小構成で進めます。
背景・課題
Elementaryはdbtのデータ品質テストの結果などをHTML形式のレポートとして可視化できるツールです。レポートはコマンド実行でelementary_report.htmlとelementary_output.jsonという静的ファイルとして生成されます。
ただ、このHTMLファイルをチームで共有しようとすると、
- ローカルにファイルを配ってブラウザで開く
- どこかしらWebサーバーにホスティングする
のいずれかが必要になります。前者はファイル配布のたびに手間がかかるため、何らかの形でWebホスティングしたいです。
過去の記事では、Snowpark Container Services上で配信する構成を試しました。今回はDatabricksを使っているチーム向けに、Databricks Appsで同じことができないかを確認します。
技術的アプローチ
Databricks Appsは、PythonやNode.jsのアプリケーションをDatabricksワークスペース上のサーバレス基盤で実行できる機能です。アプリの起動コマンドは、プロジェクトルートに置いたapp.yamlのcommandフィールドで定義できます。
今回はElementaryのレポートが静的なHTML / JSONファイルとして生成される点に注目し、WebアプリケーションフレームワークやDockerイメージは使わず、Python標準ライブラリのhttp.serverだけで配信します。
Databricks Apps上で動かすアプリは、DATABRICKS_APP_PORT環境変数で指定されたポートでHTTPリクエストをListenする必要があります。今回は起動スクリプトとしてserver.pyを用意し、Python側でos.environからDATABRICKS_APP_PORTを読み取ってhttp.serverを起動する構成にします。
app.yamlは以下のようにシンプルにserver.pyを呼び出すだけの定義にします。
command:
- python
- server.py
server.pyの中身(Python標準ライブラリのhttp.serverを使った最小構成のHTTPサーバー)とpublicディレクトリの構成については、後述の「試してみた」セクションで詳しく見ていきます。
Elementaryのレポートは通常、elementary_report.htmlとして生成されます。このファイル名のままでも、以下のようにファイル名まで指定すれば表示できます。
https://<databricks-app-url>/elementary_report.html
ただし、http.serverでは、ディレクトリにアクセスされたときにindex.htmlまたはindex.htmがデフォルトページとして返されます。そのため、Databricks AppsのURL直下にアクセスしただけでレポートを表示できるようにするため、今回はelementary_report.htmlをindex.htmlにリネームして配置します。
最終的なディレクトリ構成は以下のとおりです。
elementary-report-app/
├── app.yaml
├── server.py
└── public/
├── index.html
└── elementary_output.json
index.htmlは、Elementaryが生成したelementary_report.htmlをリネームしたものです。リネームは必須ではありませんが、チームメンバーに共有するURLをシンプルにするため、この構成にしています。
制限事項
- 今回の構成は静的ファイル配信のみを想定しています。バックエンドAPIやDB接続を伴うケースは別途アプリケーションコードの実装が必要です
- Elementaryのレポートはデプロイ時点のスナップショットになります。レポートを更新する場合は再度Databricks Appsへデプロイする必要があります
- Databricks Appsのアプリ名はワークスペース内で一意である必要があり、小文字英数字とハイフンのみ使用できます。また作成後の名前変更はできません
コスト
- Databricks Apps利用時のサーバレスコンピュートの稼働時間に応じた課金が発生します。詳細はDatabricksの公式の料金ページをご確認ください
前提条件
今回の検証は、以下が完了している前提で進めます。
- Databricks: Express Setupでワークスペースを作成済み
- Databricks CLI: ローカル環境にインストール済みで、対象ワークスペースにOAuth U2M認証で接続できる状態
- Elementaryのレポートファイル:
elementary_report.htmlとelementary_output.jsonが生成済み
事前準備
Databricks CLIの接続確認
まず、Databricks CLIから対象のワークスペースに接続できるようにプロファイルをセットアップします。CLIのプロファイル名は、本記事では例としてexpress-setupとしています。
databricks auth login --host https://<workspace-url>
ブラウザで認証後、続いてプロファイルが作成されているかを確認します。対象のプロファイルがVALIDになっていればOKです。
databricks auth profiles
次に、ログイン中のユーザー情報を取得して接続を確認します。
databricks current-user me --profile express-setup
ユーザー名やメールアドレスが返ってくれば、CLIからDatabricksへ接続できている状態です。
以降のコマンドでは、毎回--profile express-setupを付けて実行していきます。
Elementaryのレポートファイルを確認
Elementaryのレポートファイルの場所を確認しておきます。
私の環境では、以下のようにedr_target/配下にelementary_report.htmlとelementary_output.jsonが生成されていました。
edr_target/
├── elementary_report.html
└── elementary_output.json

試してみた
1. Databricks Apps用のディレクトリを作成
ローカルにDatabricks Apps用のディレクトリを作成し、Elementaryのレポートファイルをコピーします。
mkdir -p elementary-report-app/public
elementary_report.htmlはindex.htmlにリネームしてコピーします(HTTPサーバーのデフォルトドキュメントとして開かせるためです)。
cp edr_target/elementary_report.html elementary-report-app/public/index.html
cp edr_target/elementary_output.json elementary-report-app/public/elementary_output.json
コピー後の構成を確認します。
tree
以下のように表示されればOKです。
elementary-report-app
└── public
├── elementary_output.json
└── index.html
2. server.pyを作成
続いて、Databricks Apps上でHTTPサーバーを起動するserver.pyを作成します。
elementary-report-app/server.pyとして以下の内容で保存します。
import os
from functools import partial
from http.server import SimpleHTTPRequestHandler, ThreadingHTTPServer
def main():
port = int(os.environ["DATABRICKS_APP_PORT"])
handler = partial(SimpleHTTPRequestHandler, directory="public")
server = ThreadingHTTPServer(("0.0.0.0", port), handler)
print(f"Serving public directory on 0.0.0.0:{port}", flush=True)
server.serve_forever()
if __name__ == "__main__":
main()
ポイントは以下です。
DATABRICKS_APP_PORTをos.environから取得し、int()で数値に変換しています--directory public相当の挙動を、functools.partialでSimpleHTTPRequestHandlerにdirectory="public"を渡すことで実現しています0.0.0.0でListenし、Databricks Appsのリクエストを受けられるようにしています- 起動時のログを
print(..., flush=True)で標準出力に流すことで、Databricks Apps側のログに即時反映されるようにしています - 標準ライブラリのみを使うため、追加の依存関係(requirements.txtなど)は不要です
3. app.yamlを作成
続いて、Databricks Appsの起動設定となるapp.yamlを作成します。
elementary-report-app/app.yamlとして以下の内容で保存します。
command:
- python
- server.py
これにより、Databricks Appsの起動時にpython server.pyが実行され、Python側でDATABRICKS_APP_PORTを読み取った上でpublicディレクトリを静的配信する構成になります。
最終的なディレクトリ構成は以下のとおりです。
tree
elementary-report-app
├── app.yaml
├── server.py
└── public
├── elementary_output.json
└── index.html
4. ローカルで動作確認
Databricks Appsへデプロイする前に、server.pyが想定どおりにレポートを配信してくれるか、ローカル環境で軽く確認しておきます。
server.pyはDatabricks Apps上での実行を前提にDATABRICKS_APP_PORTを環境変数から読み取る実装にしているため、ローカル実行時は環境変数を一時的に渡せばOKです。
cd elementary-report-app
DATABRICKS_APP_PORT=8000 python3 server.py
ブラウザでhttp://localhost:8000にアクセスし、Elementaryのレポートが表示されればOKです。

確認できたら、Ctrl + CでHTTPサーバーを停止します。
5. Databricks Appを作成
続いてDatabricks Apps側にアプリを作成します。今回はアプリ名をelementary-report-appとしています。
databricks apps create elementary-report-app \
--description "Elementary report viewer" \
--profile express-setup
下図のようにログが流れるので、数分待ちます。

アプリの作成が完了すると、下図のようにログが表示されます。

6. Workspaceフォルダへアプリファイルを同期
Databricks AppsはWorkspaceフォルダにアップロードしたファイルをデプロイ元として利用できます。CLIを使う場合はdatabricks syncでローカルのファイルをWorkspaceフォルダに同期します。
同期先のWorkspaceパスを決めます。今回は例として以下のパスにします。
/Workspace/Users/<your-email>/elementary-report-app
<your-email>は、自分のDatabricksユーザー名(メールアドレス)に置き換えてください。
ローカルのelementary-report-appディレクトリに移動し、Workspaceフォルダへ同期します。例として、ユーザー名がsagara@example.comであれば以下のとおりです。
databricks sync . /Workspace/Users/sagara@example.com/elementary-report-app \
--profile express-setup

同期後、DatabricksのUIからWorkspaceを開き、対象フォルダ配下にapp.yamlとserver.pyとpublicディレクトリがアップロードされていることを確認します。

7. Databricks Appsへデプロイ
作成したDatabricks Appに対してデプロイを実行します。
databricks apps deploy elementary-report-app \
--source-code-path /Workspace/Users/sagara@example.com/elementary-report-app \
--profile express-setup
デプロイが進むと、CLI上にデプロイ進行状況と完了メッセージが表示されます。完了後は、app.yamlに定義したcommandに従ってアプリが起動します。

8. アプリのURLを確認してレポートを表示
デプロイ完了後、アプリの情報を取得します。
databricks apps get elementary-report-app \
--profile express-setup \
--output json
出力されるJSONの中にアプリのURLが含まれているため、そのURLにブラウザでアクセスします。

または、DatabricksのUI上のDatabricks Appsの画面から、対象のアプリ(elementary-report-app)のリンクを開いてもOKです。

上記いずれかの方法でURLを確認して、ブラウザでElementaryのレポートが表示されれば成功です!

(補足)レポートを更新したい場合
今回の構成では、配信しているElementaryのレポートはデプロイ時点の静的ファイルです。レポートを更新したい場合は、以下の流れで再デプロイします。
CLIで実行できるので、CI/CDパイプラインやdbtの処理の実行後などでこれらのコマンドを実行するようにし、レポートを自動更新するのも良いと思います。
# Elementaryのレポートを再生成した後、ファイルをコピー
cp edr_target/elementary_report.html elementary-report-app/public/index.html
cp edr_target/elementary_output.json elementary-report-app/public/elementary_output.json
# Databricks Apps用ディレクトリに移動
cd elementary-report-app
# Workspaceへ同期
databricks sync . /Workspace/Users/<your-email>/elementary-report-app \
--profile express-setup
# 再デプロイ
databricks apps deploy elementary-report-app \
--source-code-path /Workspace/Users/<your-email>/elementary-report-app \
--profile express-setup
他のユーザーにもアプリを見せたい場合
ここまでの手順だと、デプロイしたユーザーしかアプリにアクセスできない状態です。作成したDatabricks Appを他のユーザーにも見せたい場合は、Databricks Apps側で権限を付与します。
Databricks Appsの権限レベルは主に以下の2種類です。
| 権限 | 内容 |
|---|---|
CAN USE |
アプリを実行・操作できる。閲覧用途のユーザーには基本的にこちらを付与 |
CAN MANAGE |
アプリの設定変更・権限変更・編集・削除ができる。管理者向け |
Elementaryのレポートを見せたいだけであれば、対象ユーザーやグループにCAN USEを付与すればOKです。CAN MANAGEを持つユーザーだけがアプリの権限を付与・取り消しできる仕様のため、権限付与作業自体はCAN MANAGEを持っているユーザーで実施する必要があります。
UIから権限を付与する手順
DatabricksのUIから設定する場合は、以下の流れです。
- DatabricksのWeb UIで対象のアプリ(今回の例だと
elementary-report-app)を開く - アプリの概要タブで右上の
Shareを押す - 表示されたダイアログで、ユーザー・グループ・サービスプリンシパルから対象を選択
- 権限レベルとして
CAN USEを選択し、Addを押す - 末尾の
Saveを押して確定する

試す中でうまくいかなかったこと
app.yamlのcommand内でDATABRICKS_APP_PORTが文字列のまま渡されてしまう
最初はserver.pyを作らずに、app.yamlのcommand配列内でpython -m http.serverに直接DATABRICKS_APP_PORTを渡す構成で試していました。
command:
- python
- -m
- http.server
- DATABRICKS_APP_PORT
- --bind
- 0.0.0.0
- --directory
- public
ところが、この構成でDatabricks Appsへデプロイすると、DATABRICKS_APP_PORTが環境変数として展開されず、文字列のままhttp.serverへ渡ってしまい、以下のエラーでアプリが起動しませんでした。
server.py: error: argument port: invalid int value: 'DATABRICKS_APP_PORT'
そのため、本記事の手順では server.pyを経由してPython側でos.environ["DATABRICKS_APP_PORT"]から読み取る構成に切り替えています。Pythonコード側で明示的に環境変数を取得する形にすれば、Databricks Apps側で実ポートが環境変数に注入されている限り、確実にHTTPサーバーが起動します。
同じくapp.yamlから直接外部コマンドへ環境変数を渡したいケースでは、いったん起動スクリプト経由にしてしまうのが安全だと感じました。
最後に
Databricks Appsを使って、ElementaryのレポートをWebで閲覧できる構成を試してみました。
Dockerイメージを作らずとも、Python標準ライブラリのhttp.serverと最小限のserver.py / app.yamlだけで静的レポートを配信できるのは、かなり手軽だと感じました!
dbtのドキュメント(dbt docs generateの出力)など、他の静的サイト系のレポート配信にも同じ構成で応用できますので、ぜひご活用ください。







