GitHub Actions + DatabricksでCI/CDを実現してみる


# はじめに

前回「[databricks と pytest の integration を試してみる](https://qiita.com/maroon-db/items/ccafbaaeecab4d532355)」にて、pytestのリモート実行を可能にしたため、今回は一歩進めてgithub actionsを利用して、pushやpull request時に自動的にpytestが実行されるように設定してみたいと思います。

イメージはこんな感じ
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2206424/f23dac2f-fe3d-f274-1fc5-bac6bccb80c0.png)


# GitHub Actionsとは

GitHub上のリポジトリやイシューに対するさまざまな操作をトリガーとしてあらかじめ定義しておいた処理を実行できる機能で、今まで外部サービスとの連携が必要だった自動テストや自動ビルドなどがGitHubだけで実現できるようになります。しかもある程度までの規模であればフリーで利用できるというありがたいサービスです。従来よりも簡単にCI/CDを実現することが出来るようになります。

こちらのさくらナレッジさんの「[GitHubの新機能「GitHub Actions」で試すCI/CD](https://knowledge.sakura.ad.jp/23478/)」で使い方など分かりやすくまとめていただいております。

また[GitHub Learning Lab](https://lab.github.com/githubtraining/github-actions:-hello-world)で気軽に試すことができます。

# DatabricksとGitHub Actions

databricksはGitHub Actions用に以下の２つのワークフローを用意されてます。これによりノートブックの実行や、ファイルのアップロード手順が簡素化されます。今回は`upload-dbfs-temp`のActionを利用したいと思います。

・　databricks/run-notebook
・　databricks/upload-dbfs-temp

https://docs.databricks.com/dev-tools/ci-cd/ci-cd-github.html


# 1. リポジトリのFork

今回は、[前回利用したコード](https://github.com/amesar/databricks-tests)を利用して実装してみたいと思います。Github actionsを利用するためにはRepository Ownerになる必要があるため、一旦repositoryをforkしておきます。右上の Forkボタンをクリックして、自分のアカウント上に作成します。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2206424/16fe223c-1ee3-6928-b61b-73673b4bd3f5.png)

# 2. GitHub SecretsへDatabricks Tokenの登録

DatabricksのWorkspaceにアクセスするために、Tokenが必要になります。これらをGitHub Actionのワークフローに平文で書くのはセキュリティ上推奨されませんので、[GitHub Secrets](https://docs.github.com/ja/actions/security-guides/encrypted-secrets)を使って予め登録しておきます。

Databricksのアクセストークンは、Setting -> User Settings -> Access Token　にて生成することができます。[Databricks Access Tokenの生成](https://docs.microsoft.com/ja-jp/azure/databricks/dev-tools/api/latest/authentication#--generate-a-personal-access-token)

今回は、`dbToken`というキーで、登録しました。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2206424/7df7d7b6-5398-1941-151d-742a93e17215.png)

# 3. Databricks Job実行(Run Submit)用のjsonファイル作成

以前の[記事](https://qiita.com/maroon-db/items/ccafbaaeecab4d532355)でも作成しましたが、DatabriksのリモートJob実行のために、jsonファイルを用意しておきます。 
今回はこちらの[run submit.json](https://github.com/maroon-spec/databricks-tests/blob/main/example/run_submit.json)ファイルを用意しました。内容の詳細は以前の記事をご覧ください。

```json:run_submit.json
{
  "run_name": "jmaru_DatabricksTestsExample",
  "new_cluster": {
    "spark_version": "10.4.x-scala2.12",
    "node_type_id": "i3.xlarge",
    "num_workers": 1
  },
  "timeout_seconds": 3600,
  "libraries": [
    { "pypi": { "package": "pytest==5.3.5" } },
    { "whl": "dbfs:/tmp/jmaru/jobs/myapp/databricks_tests_example-0.0.1-py3-none-any.whl" }
  ],
  "spark_python_task": {
    "python_file": "dbfs:/tmp/jmaru/jobs/myapp/run_tests.py",
    "parameters": [ "--pyargs", "tests", "-s", "-v", "--junit-xml", "dbfs:/tmp/jmaru/jobs/myapp/junit.xml" ]
  }
}
```



# 4. GitHub Action Workflowの作成

Forkしたリポジトリ上にAction Workflowファイルを作成します。`.github/workflows/upload_wheel.yml` GitHub Actionsでは、./github/workflows ディレクトリにWorkflowファイルを作成するのがルールです。

今回は、新規のBranch上に作成し、Pull Requestを作成しておきます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2206424/3f64dc21-5687-b37f-27a6-5cb97f203ba0.png)

今回は以下のようなワークフローを作成しました。[upload_wheel.yml](https://github.com/maroon-spec/databricks-tests/blob/maroon-spec-patch-2/.github/workflows/upload_wheel.yml)

```yaml:upload_wheel.yml
name: Databricks Pytest Integration test.

on:　　　
  [pull_request]

env:
  DATABRICKS_HOST: https://xxxxxxx.cloud.databricks.com/  #(対象となるWorkspace URLを入力） 
  DATABRICKS_TOKEN: ${{ secrets.dbToken }}　　　 #先ほど登録したGitHub Secretsを呼び出す

jobs:
  build:
    runs-on: ubuntu-latest
    steps:
      - name: Checks out the repo
        uses: actions/checkout@v2
      
# run_tests.py をDBFS上にアップロード。databricksが提供している upload-dbfs-tempを活用
      - name: Upload main file
        uses: databricks/upload-dbfs-temp@v0
        id: upload_file
        with:
          local-path: test-harness/databricks_test_harness/run_tests.py
          dbfs-temp-dir: 'dbfs:/tmp/jmaru/jobs/myapp/'

# Wheelによるパッケージ化
      - name: Setup python
        uses: actions/setup-python@v2
      - name: Install wheel
        run: pip install wheel
      - name: Build wheel
        working-directory: ./example
        run:
          python setup.py bdist_wheel
          
# Wheel fileのアップロード
      - name: Upload Wheel
        uses: databricks/upload-dbfs-temp@v0
        id: upload_wheel
        with:
          local-path: example/dist/databricks_tests_example-0.0.1-py3-none-any.whl
          dbfs-temp-dir: 'dbfs:/tmp/jmaru/jobs/myapp/'

# databricks run submit実行のため、databricks-cli のインストール
      - name: install databricks cli
        run: pip install databricks-cli
       
# run submit(Job API)の実行
      - name: Trigger run submit
        working-directory: ./example
        run:
          databricks runs submit --json-file run_submit.json
```


databricks/uplpoad-dbfs-temp アクションで実行したものは、処理実行後にポスト処理でアップロードしたファイルが削除されるため注意。残したい場合は、copy処理を付け足したり、普通にdatabricks-cliの機能を使う方がベターかと。

# 5. 実行確認

上記ワークフローファイルをCommitし、Pull Requestが作成または更新されると、GitHub Action Workflowが実行されます。(今回はPull Requestをトリガーとしたため）実行ステータスもGitHub上から確認できます。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2206424/c04f370e-9ebe-35ea-60ae-e863715e4e6a.png)

DatabricksのJob UIでもJob Statusが確認できます。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2206424/236cb4e2-4a5e-cbd9-9331-052890462ce7.png)

これで、pull requestをもとにGitHub Actionによるワークフローが実行されて、databricks上でpytestが行われる連携ができました。
最後にDatabricksのGit連携を行い、コードをプッシュして確認したいと思います。

# 6. DatabricksとGit連携設定

こちらの[記事を参考にGit連携](https://qiita.com/taka_yayoi/items/b89f199ff0d3a4c16140)を行います。Repositoryは先ほどForkしたレポジトリーになります。

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2206424/b3ec0588-1db3-6292-4290-d2465cb22f96.png)

適当に新規のノートブック(github_test)を作成し、先ほどGitHub上で作成したBranchを選択しcommit&pushします。
（Commit&Pushだけだと、Pull Request作成されませんが、今回はPull Request中のBranchへの変更のためトリガーが発動します）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2206424/31afe4ed-9e49-d859-549a-6b45ca2255b8.png)


Job画面を見ると、新規のJobが実行されていることがわかります。
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2206424/ba45032b-9d0f-214b-1dab-955131e03f9e.png)


## python コードをノートブック形式で表示するには？

今回のオリジナルコードが、.py で作成されているため、Databricksノートブック上で表示するとシンプルなエディターになってしまいますが、pythonファイルの先頭に `## Databricks notebook source` を追加して、インポートするとノートブック形式で利用できます。
（一度インポートした後に修正すると、再インポートが必要になります）

![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/2206424/ce90661e-e983-4321-f15f-76fbc1327458.png)

# 最後に

このようにGitHub Actionsと連携すると、CI/CDが簡単に実現できそうです。他のDatabricks Workspace上でテスト実行するなども可能になります。是非お試しください。

# Workflowを含むリポジトリ

今回私がForkして、Workflowを作成したリポジトリはこちらです。

https://github.com/maroon-spec/databricks-tests