CCCMKホールディングス TECH LABの Tech Blog

TECH LABのエンジニアが技術情報を発信しています

ブログタイトル

Databricks Asset Bundlesを活用したDatabricks Apps開発

はじめに

こんにちは、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の無料版の環境です。

www.databricks.com

以前から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です。

docs.databricks.com

databricks.ymlでbundleの定義をしておけば、databricks bundle deploy --target devのようにCLIのコマンド一発で対象の環境にリソースを展開できるようになります。

参考にしたもの

Databricks Asset Bundlesはドキュメントもあるのですが、公式のサンプルを見ると参考になることが多かったです。

github.com

アプリについて

アプリはPythonのFastAPIで動かし、アプリのUIはhtmxを使って書きました。htmxはJavascriptを使わずに動的なWebページを作成できるライブラリです。

htmx.org

チャットアプリを作る時これまでは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.htmlchat-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.ymlresources/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

デプロイする先を定義しています。今回はdevprodの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.ymltargetdefault: 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の実現にトライしてみたいと思います。