
はじめに
こんにちは、CCCMKホールディングスAIエンジニアの三浦です。先日東京に雪が降りました。雪が降ると、いつもの見慣れた景色が全然違って見えて不思議な気持ちになりました。
最近社内向けのアプリをDatabricks Appsで提供する、といったことに取り組んでいました。それと並行してAI Agentを導入した開発体制にも着手しています。プロジェクトやイシュー、ソースコードの管理、CI/CDパイプラインの構築などです。そのような中で"Databricks Asset Bundles"というツールを使うとアプリを動かすのに必要なリソースやテスト用や本番用の環境の定義をYAMLで管理することが出来、YAMLに従ってアプリをデプロイすることが出来ることを知りました。これをAzure PipelinesやGithub Actionsに組み込めばDatabricks Appsへのアプリの自動的なリリースが実現できそうです。
今回はFoundation Model APIを内部で呼び出す簡単なチャットアプリを開発してDatabricks Asset Bundlesでデプロイするところまで試してみました。
検証環境
今回の検証はWindows 11, Databricks Free Editionで行いました(私のプライベートな開発環境です)。Databricks Free Editionは主に学習用途で公開されているDatabricksの無料版の環境です。
以前からFree Editionでどこまで出来るんだろう、と気になっていて試してみたのですが、一部のFoundation Model API(databricks-meta-llama-3-1-8b-instruct,databricks-meta-llama-3-3-70b-instructなど)が使えたり、Databricks Appsでアプリを1つ動かせることが確認出来ました。プライベートでDatabricksについて学習したい、という目的であれば十分すぎるほどの機能が提供されていると思います。
Databricks Asset Bundlesとは
DatabricksでデータやAIを使ったアプリやシステムを開発する場合、どのリソースをどういった設定で動かすのか、開発と本番でどのWorkspaceを使うのかなどを決める必要があります。これらをYAML形式で定義することが出来るのがDatabricks Asset Bundlesです。
databricks.ymlでbundleの定義をしておけば、databricks bundle deploy --target devのようにCLIのコマンド一発で対象の環境にリソースを展開できるようになります。
参考にしたもの
Databricks Asset Bundlesはドキュメントもあるのですが、公式のサンプルを見ると参考になることが多かったです。
アプリについて
アプリはPythonのFastAPIで動かし、アプリのUIはhtmxを使って書きました。htmxはJavascriptを使わずに動的なWebページを作成できるライブラリです。
チャットアプリを作る時これまではStreamlitを使うことが多かったのですが、もうちょっと色々カスタマイズしたりデザインも凝ってみたいな、と思うことが増えてきており、最近はhtmxで実装するのにチャレンジしています。
たとえば次のようなindex.htmlをテンプレートで書いておき、
<!DOCTYPE html> <html> <head> <meta charset="utf-8" /> <title>チャットアプリ</title> <script src="https://unpkg.com/htmx.org@1.9.10"></script> </head> <body> <main class="container"> <div id="chat-area"></div> <form hx-post="/chat" hx-target="#chat-area" hx-swap="beforeend" hx-on::after-request="this.reset()"> <input type="text" name="message" /> <button type="submit">Send</button> </form> </main> </body> </html>
FastAPIで/chatにリクエストが来た時のレスポンスを次のように書いておくだけで動的にindex.htmlのchat-areaに応答を描画することが出来ます。
@app.post("/chat", response_class=HTMLResponse) def chat(message: str = Form(...)): """Foundation Model APIにアクセスし応答を取得してindex.htmlのchat-areaに返す""" user_input = html.escape(message) try: reply = get_llm_client().chat([{"role": "user", "content": message}]) except DatabricksLLMError as exc: reply = f"Error: {exc}" reply = html.escape(reply) return f""" <article class="user"> <strong>You:</strong> <p>{user_input}</p> </article> <article class="assistant"> <strong>Assistant</strong> <p>{reply}</p> </article> """
また、ローカルの開発環境はuvで構築しています。
プロジェクトの構成
プロジェクトの構成は次のようになりました。
dab-chat-app/
.env
.gitignore
.python-version
.vscode/
settings.json
app.yml
databricks.yml
docs/
memo.md
pyproject.toml
README.md
requirements.txt
resources/
chat-app.yml
src/
__init__.py
llm_client.py
main.py
templates/
index.html
uv.lock
この中でDatabricks Asset Bundlesに特に関連するファイルがdatabricks.ymlとresources/chat-app.yml, app.ymlです。それぞれの中身の詳細を見ていきます。
databricks.yml
このプロジェクトに必要なリソースや環境を定義するファイルです。今回私が作成した内容は以下の通りです。
bundle: name: databricks-asset-bundle-chat-app include: - resources/*.yml sync: exclude: - "**/.ruff_cache" - "**/.venv" - "**/.vscode" - "**/docs" - ".gitignore" - ".env" - "pyproject.toml" - "README.md" - "uv.lock" - ".python-version" - "bundle_config_schema.json" # Define deployment targets targets: dev: default: true workspace: host: "https://dbc-xxxxxxxx.cloud.databricks.com" prod: workspace: host: "https://dbc-xxxxxxxx-4bbc.cloud.databricks.com"
それぞれの設定は次の通りです。
bundle.name
このbundleの名前です。
include
このbundleに含めるリソースを定義したYAMLファイルを指定します。今回はresources/chat-app.ymlというファイルだけが対象になります。
sync.exclude
Workspaceにデプロイするときに除外したいファイルを指定することが出来ます。個人的にこれがとても便利だと思いました。これまでは必要なファイルをコピーしてまとめるシェルスクリプトを書いていたのですが、この設定で十分対応出来るからです。
targets
デプロイする先を定義しています。今回はdevとprodの2つで、それぞれ異なるWorkspaceを指定することが出来ます。targetsに指定した環境に対し、databricks bundle deploy --target prodのようにdeployを実行することが出来るようになります。
resources/chat-app.yml
リソースの1つであるDatabricks Appsを定義するYAMLファイルです。次のように作りました。今回のアプリはとてもシンプルなので、アプリの名前(resources.apps.chat-app.name)とソースコードのパス(resources.apps.chat-app.source_code_path)のみで構成しています。ソースコードの相対パスはdatabricks.ymlの場所がベースになっています。
resources: apps: chat-app: name: "chat-app" source_code_path: "."
app.yml
Databricks Appsの起動に関連する設定を書きます。resources/chat-app.ymlで指定したソースコードのパスの直下に格納しておきます。起動コマンドや環境変数などを設定しています。
name: chat-app command: ["uvicorn", "src.main:app", "--port", "8000"] env: - name: DATABRICKS_ENDPOINT_NAME value: databricks-meta-llama-3-1-70b-instruct
deploy手順
必要なファイルを書いたら、deployをする前に内容を検証することが出来ます。
databricks bundle validate
もし不正な内容があれば、警告やエラーを出してくれます。
Warning: unknown field: variables at resources.apps.chat-app in resources/chat-app.yml:7:7
検証が通れば、以下のコマンドでデプロイします。--targetの指定を省いている場合はdatabricks.ymlのtargetでdefault: trueに指定した環境が対象になります。
databricks bundle deploy
気づいたこと
bundle deployはWorkspaceにAppsに必要なファイル一式を配置してくれます。併せてAppsの新規作成も行いますが、展開したソースコードとAppsとの紐づけは行ってくれないようです。
なので初回deploy時は一度DatabricksのWebUIで対象のアプリの設定を確認し、ソースコードの紐づけや使用するFoundation Model APIの許可設定などを行う必要があります。
また、以降もbundle deployだけではアプリに変更内容が反映されないようなので、
databricks bundle deploy databricks apps deploy chat-app
のようにAppsに対するdeployコマンドも打つ必要がありました。
まとめ
ということで今回はDatabricks Asset Bundlesを使ったDatabricks Appsのデプロイ方法について調べてみたことをまとめてみました。先にも触れたように、Databricks Asset Bundlesを使うと対象のファイルをdatabricks.ymlで指定出来て、かなり便利だと感じました。
今度はこれをAzure Pipelinesに組み込んでCI/CDの実現にトライしてみたいと思います。