DatabricksアセットバンドルによるInfrastructure as Code

こちらの機能の存在は知っていたのですが、触ったことがなかったので触ります。

https://docs.databricks.com/ja/dev-tools/bundles/index.html

:::note info
**プレビュー**
本機能は[パブリックプレビュー](https://docs.databricks.com/release-notes/release-types.html)です。
:::

# Databricksアセットバンドルとは

マニュアルにはいろいろ書いてありますが、私の理解はこちらです。

- Databricksのノートブックのみならず、クラスターやジョブ、モデルレジストリの構成などもコードで管理してDatabricksワークスペースにデプロイする仕組み。
- これによって、ノートブック(ソースコード)やクラスターやジョブの構成もGitHubなどのバージョン管理ツールで管理できるようになる。これがすなわち、Infrastructure as Code(IaC)。
- [Terraform](https://docs.databricks.com/ja/dev-tools/terraform/index.html)はインフラの管理が対象ですが、こちらではソースコードも一緒にGitHubで管理できるとのこと。

# 動かしてみる

触ってみます。以下のチュートリアルの方がデプロイまでカバーしていますのでこちらを。

https://docs.databricks.com/ja/workflows/jobs/how-to/use-bundles-with-jobs.html

## Databricks CLIのインストール

アセットバンドルの作成、デプロイなどは[Databricks CLI](https://docs.databricks.com/ja/dev-tools/cli/install.html)から行います。最新のバージョンになっていなければアップグレードします。

```sh
databricks -v
```

Databricks CLI バージョン 0.205が必要なので要件を満たしています。

```
Databricks CLI v0.212.3
```

## 認証設定

開発マシンからDatabricksワークスペースに接続するために認証を行います。

```sh
databricks auth login --host https://<ワークスペースのホスト名>
```

上を実行すると、ブラウザが開くのでDatabricksワークスペースにログインします。ログインに成功すると以下のような画面が表示されます。
![Screenshot 2024-02-06 at 19.14.52.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/893ab7ab-ad71-92ad-b51b-82554c3aee3a.png)

CLIのプロファイルとして保存されます。

```
✔ Databricks Profile Name: <プロファイル名>
Profile <プロファイル> was successfully saved
```

## バンドルの作成

テンプレートが用意されているとのことなので、そちらを使います。

```sh
databricks bundle init
```

カーソルを上下されることでテンプレートを選択します。`default-python`
を選びます。
![Screenshot 2024-02-06 at 19.16.32.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/e9bee42c-61d4-20bc-76de-11179cf0e9a7.png)

プロジェクト名はデフォルトのままにします。
![Screenshot 2024-02-06 at 19.16.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/59a8f804-8692-6b81-4a60-f071b89a1b01.png)

サンプルノートブックのみを作るので、yes -> no -> noと答えます。

```sh
Unique name for this project [my_project]: 
Include a stub (sample) notebook in 'my_project/src': yes
Include a stub (sample) Delta Live Tables pipeline in 'my_project/src': no
Include a stub (sample) Python package in 'my_project/src': no
Workspace to use (auto-detected, edit in 'my_project/databricks.yml'): https://<ワークスペースホスト名>

✨ Your new project has been created in the 'my_project' directory!

```

:::note
**注意**
上で`Workspace to use`が自動検知されますが、使いたいワークスペースではない場合は`'my_project/databricks.yml`を編集する必要があります。CLIの`DEFAULT`プロファイルが選択されます。
:::

私の場合はワークスペースのURLを切り替えたかったので、`databricks.yml`の`host`を変更しました。

![Screenshot 2024-02-06 at 19.57.06.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/7976c084-4c63-c93c-d318-df9b78b8b91f.png)

```yaml:databricks.yml
# This is a Databricks asset bundle definition for my_project.
# See https://docs.databricks.com/dev-tools/bundles/index.html for documentation.
bundle:
  name: my_project

include:
  - resources/*.yml

targets:
  # The 'dev' target, for development purposes. This target is the default.
  dev:
    # We use 'mode: development' to indicate this is a personal development copy:
    # - Deployed resources get prefixed with '[dev my_user_name]'
    # - Any job schedules and triggers are paused by default
    # - The 'development' mode is used for Delta Live Tables pipelines
    mode: development
    default: true
    workspace:
      host: https://<ワークスペースのホスト名>

  ## Optionally, there could be a 'staging' target here.
  ## (See Databricks docs on CI/CD at https://docs.databricks.com/dev-tools/bundles/index.html.)
  #
  # staging:
  #   workspace:
  #     host: https://<ワークスペースのホスト名>

  # The 'prod' target, used for production deployment.
  prod:
    # We use 'mode: production' to indicate this is a production deployment.
    # Doing so enables strict verification of the settings below.
    mode: production
    workspace:
      host: https://<ワークスペースのホスト名>
      # We always use /Users/takaaki.yayoi@databricks.com for all resources to make sure we only have a single copy.
      # If this path results in an error, please make sure you have a recent version of the CLI installed.
      root_path: /Users/takaaki.yayoi@databricks.com/.bundle/${bundle.name}/${bundle.target}
    run_as:
      # This runs as takaaki.yayoi@databricks.com in production. We could also use a service principal here,
      # see https://docs.databricks.com/dev-tools/bundles/permissions.html.
      user_name: takaaki.yayoi@databricks.com
```

テンプレートを検証します。デフォルトではプロファイル`DEFAULT`が使用されるので、私は明示的に使いたいプロファイルを指定しています。

```sh
cd my_project
databricks bundle validate --profile <プロファイル名>
```

```json
{
  "bundle": {
    "name": "my_project",
    "target": "dev",
    "environment": "dev",
    "terraform": {
      "exec_path": "/Users/takaaki.yayoi/my_project/.databricks/bundle/dev/bin/terraform"
    },
    "lock": {},
    "git": {
      "bundle_root_path": "."
    },
    "mode": "development"
  },
  "include": [
    "resources/my_project_job.yml"
  ],
  "workspace": {
    "host": ...略...
  },
  "sync": {}
}                                                           
```

って、上見たらデプロイにはterraform使ってますね。

## ローカルプロジェクトをDatabricksワークスペースにデプロイ

その前にデプロイ先がAWSのDatabricksの場合には修正が必要です。上のテンプレートではジョブクラスターを作成するのですがその際のインスタンス指定が`Standard_D3_v2`となっており、Azure前提となっています。

以下のように`node_type_id`を`i3.xlarge`に変更します。ローカルプロジェクトのディレクトリ構造を見ていると何をデプロイするのかが分かってきます。

```yaml:resources/my_project_job.yml
# The main job for my_project.
resources:
  jobs:
    my_project_job:
      name: my_project_job

      schedule:
        # Run every day at 8:37 AM
        quartz_cron_expression: '44 37 8 * * ?'
        timezone_id: Europe/Amsterdam

      email_notifications:
        on_failure:
          - takaaki.yayoi@databricks.com

      tasks:
        - task_key: notebook_task
          job_cluster_key: job_cluster
          notebook_task:
            notebook_path: ../src/notebook.ipynb
        
      job_clusters:
        - job_cluster_key: job_cluster
          new_cluster:
            spark_version: 13.3.x-scala2.12
            node_type_id: i3.xlarge
            autoscale:
                min_workers: 1
                max_workers: 4
```

デプロイします。`-t`スイッチでターゲットのワークスペースを指定しています。すなわち、これを切り替えることで開発環境へのデプロイやプロダクション環境へのデプロイを制御できるわけですね。

```sh
databricks bundle deploy -t dev --profile <プロファイル名>
```

:::note
**注意**
デプロイを行うユーザーは[認証設定](#認証設定)でログインに用いたユーザーが使用されます。
:::

```
Uploading bundle files to /Users/<ユーザー名>/.bundle/my_project/dev/files...
Deploying resources...
Updating deployment state...
Deployment complete!
```

ワークスペースを見るとリソースがデプロイされています。
![Screenshot 2024-02-06 at 20.09.02.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/dc2c6e8e-454f-4f29-dd5e-30995db80300.png)

ジョブも作成されています！
![Screenshot 2024-02-06 at 20.10.11.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/e817b745-2303-82ef-93f1-19d5c0ce9117.png)

## デプロイしたプロジェクトの実行

なんとローカルからジョブも実行できます。

```sh
databricks bundle run -t dev my_project_job --profile <プロファイル名>
```

ジョブが起動しました！
![Screenshot 2024-02-06 at 20.12.45.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/e16952b5-46c5-6b96-fa44-f6b63c04e8e0.png)

ジョブが完了しました！(うるさい)
![Screenshot 2024-02-06 at 20.17.55.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/176cc3e7-0f2b-1ff7-bc35-2e8c6c739dd9.png)

ローカル側でも進捗が表示されます。
```
Run URL: https://<ワークスペースホスト名>/?o=791148388305836#job/509846911203305/run/634811057107698

2024-02-06 20:12:37 "[dev ...] my_project_job" RUNNING 
2024-02-06 20:17:56 "[dev ...] my_project_job" TERMINATED SUCCESS 
```

## クリーンアップ

ワークスペースからデプロイしたバンドルを削除します。

```sh
databricks bundle destroy --profile <プロファイル名>
```

ジョブの削除確認メッセージが表示されますので、yを押します。
![Screenshot 2024-02-06 at 20.20.08.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/b162cdcd-e9ff-95e9-d562-397e2fdf8fce.png)

ワークスペース上のバンドル削除確認メッセージが出るのでyを押します。
![Screenshot 2024-02-06 at 20.21.13.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/1168882/52c8041c-a5a1-fab3-d8cf-6e9e28eb79ef.png)

これでクリーンアップされました。

```
Deleted snapshot file at /Users/takaaki.yayoi/my_project/.databricks/bundle/dev/sync-snapshots/f710b353e97d0b24.json
Successfully deleted files!
Destroy complete!
```

# その他のリソース

インフラだけでなくコンテンツたるソースコードやモデルなどもコントロールできるところがミソですかね。今後、他のサンプルも動かしてみます。

- [Databricks アセット バンドルとは何ですか? \|Databricks on AWS](https://docs.databricks.com/ja/dev-tools/bundles/index.html)
- [GitHubのバンドルサンプルリポジトリ](https://github.com/databricks/bundle-examples)


### はじめてのDatabricks

[はじめてのDatabricks](https://qiita.com/taka_yayoi/items/8dc72d083edb879a5e5d)

### Databricks無料トライアル

[Databricks無料トライアル](https://databricks.com/jp/try-databricks)