GitHub Actions × Databricks Asset BundlesでCI/CDを構築する ― 検証・デプロイの自動化

今回の記事は、Databricks Asset Bundles(以下DAB)のデプロイをGitHub Actionsで自動化する方法についてご紹介します。DABを使えばジョブやNotebookをYAMLで定義しコマンドでデプロイできますが、そのコマンド実行自体を手動で行っていては運用の属人化が残ります。本記事では、stg/prdの2段階ブランチ運用によるCI/CDパイプラインの構築について解説します。

導入の背景

DABを導入すると、ジョブの定義や環境ごとの設定をYAMLでコード管理できるようになります。しかし、デプロイが開発者の手元で databricks bundle deploy を実行する運用のままでは、課題が残ります。

この状態では「誰がいつデプロイしたのか」がわかりにくく、デプロイ忘れやコマンドの打ち間違いといったヒューマンエラーのリスクも残ります。そこで、GitHub Actionsを導入し、ブランチ運用と連動したCI/CDパイプラインを構築しました。

前提条件

本記事の内容は以下の環境を前提としています。

  • Databricks CLI(v0.200以上)がインストールされていること
  • DABによるプロジェクト構成が完了していること
  • GitHubリポジトリでの開発フローが確立されていること
  • Databricksワークスペースにサービスプリンシパルが作成済みであること

パイプラインとジョブの違い

DABの文脈ではパイプラインとジョブの両方を扱うことができますが、それぞれ異なる概念です。ここで簡単に整理しておきます。

ジョブ(Lakeflow Jobs) は、Notebook・dbtタスク・Pythonスクリプトなどの複数タスクを組み合わせて実行するワークフローの単位です。スケジュール実行やファイルアライバルトリガーなど、柔軟な起動条件を設定できます。AutoLoader + dbtのような構成はこちらに該当します。

パイプライン(Lakeflow Declarative Pipelines) は、旧称Delta Live Tables(DLT)として知られるもので、データの取り込みから変換までを宣言的に定義する仕組みです。テーブル間の依存関係を自動で解決し、増分処理やデータ品質チェックを組み込むことができます。

本記事で扱うCI/CDは ジョブのデプロイ自動化 を対象としています。DABのCLIコマンドはどちらにも対応していますが、bundle run のオプションなど一部の挙動が異なる点に注意してください。

ブランチ戦略の全体像

私たちのチームでは、以下のブランチ戦略でCI/CDを運用しています。

feature/* ──→ stg(Pull Request)──→ main(Pull Request)
               │                     │
               ├─ PR時: validate      ├─ PR時: validate
               └─ マージ時: deploy stg └─ マージ時: deploy prd

開発者はfeatureブランチで作業し、まずstgブランチにPull Requestを作成します。PR時点で bundle validateが自動実行され、設定に問題がなければマージ可能になります。マージされるとstg環境へのデプロイが自動で走ります。

stgでの動作確認が完了したら、stgからmainブランチへのPull Requestを作成します。同様にvalidateが実行され、マージ後にprd環境へデプロイされます。

ローカルでの検証・実行確認

CI/CDに乗せる前に、開発者が手元で一通り確認する流れを紹介します。DABでは以下の3つのコマンドを順に実行します。

# 1. YAML構文・参照の検証
databricks bundle validate -t dev

# 2. dev環境にデプロイ
databricks bundle deploy -t dev

# 3. ジョブを実行して動作確認
databricks bundle run -t dev daily_batch

validateで設定ファイルの構文エラーや変数の参照ミスを検出し、deployでdev環境にリソースを反映、runで実際にジョブを実行します。この一連の流れをローカルで確認した上でfeatureブランチをPushする、という開発サイクルになります。

stgブランチのワークフロー

stgブランチに対するGitHub Actionsのワークフローは以下のようになります。

name: ci-cd-stg

on:
  pull_request:
    branches: [stg]
  push:
    branches: [stg]

jobs:
  validate:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: databricks/setup-cli@main
      - run: databricks bundle validate -t stg
        env:
          DATABRICKS_HOST: ${{ secrets.DATABRICKS_HOST }}
          DATABRICKS_CLIENT_ID: ${{ secrets.DATABRICKS_CLIENT_ID }}
          DATABRICKS_CLIENT_SECRET: ${{ secrets.DATABRICKS_CLIENT_SECRET }}

  deploy:
    if: github.event_name == 'push'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: databricks/setup-cli@main
      - run: databricks bundle deploy -t stg
        env:
          DATABRICKS_HOST: ${{ secrets.DATABRICKS_HOST }}
          DATABRICKS_CLIENT_ID: ${{ secrets.DATABRICKS_CLIENT_ID }}
          DATABRICKS_CLIENT_SECRET: ${{ secrets.DATABRICKS_CLIENT_SECRET }}

Pull Request作成時にはvalidateのみが実行されます。設定ファイルに問題があればCIが失敗し、マージがブロックされます。stgブランチへのマージ(push)が行われると、deployジョブが実行されてstg環境にリソースが反映されます。

mainブランチのワークフロー

mainブランチのワークフローもstgとほぼ同じ構成です。ターゲットをprdに変更するだけで対応できます。

name: ci-cd-prd

on:
  pull_request:
    branches: [main]
  push:
    branches: [main]

jobs:
  validate:
    if: github.event_name == 'pull_request'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: databricks/setup-cli@main
      - run: databricks bundle validate -t prd
        env:
          DATABRICKS_HOST: ${{ secrets.DATABRICKS_HOST }}
          DATABRICKS_CLIENT_ID: ${{ secrets.DATABRICKS_CLIENT_ID }}
          DATABRICKS_CLIENT_SECRET: ${{ secrets.DATABRICKS_CLIENT_SECRET }}

  deploy:
    if: github.event_name == 'push'
    runs-on: ubuntu-latest
    steps:
      - uses: actions/checkout@v4
      - uses: databricks/setup-cli@main
      - run: databricks bundle deploy -t prd
        env:
          DATABRICKS_HOST: ${{ secrets.DATABRICKS_HOST }}
          DATABRICKS_CLIENT_ID: ${{ secrets.DATABRICKS_CLIENT_ID }}
          DATABRICKS_CLIENT_SECRET: ${{ secrets.DATABRICKS_CLIENT_SECRET }}

stgとmainで別ファイルに分けていますが、ワークフローの構造は同一です。環境ごとにSecretsを分けたい場合は、GitHub EnvironmentsやSecret名のサフィックス(例:DATABRICKS_CLIENT_ID_STG/DATABRICKS_CLIENT_ID_PRD)で対応できます。

サービスプリンシパルの認証設定

GitHub ActionsからDatabricksに接続するために、サービスプリンシパルのクレデンシャルをGitHub Secretsに登録します。

登録するSecretは以下の3つです。

  • DATABRICKS_HOST:ワークスペースのURL
  • DATABRICKS_CLIENT_ID:サービスプリンシパルのクライアントID
  • DATABRICKS_CLIENT_SECRET:サービスプリンシパルのクライアントシークレット

GitHub Actionsのワークフロー内で環境変数として渡すことで、Databricks CLIが自動的にOAuth認証を行います。トークンをコードに埋め込む必要がなく、Secretsによって安全に管理できます。

なお、ローカル開発時は .databrickscfg のプロファイルを使用し、CI/CDではGitHub Secretsを使用する、という形で認証方法を使い分けています。

まとめ

GitHub Actionsを導入したことで、DABのデプロイが完全に自動化されました。開発者はfeatureブランチでの作業とPull Requestの作成に集中するだけで、validateによる事前検証とデプロイが自動的に実行されます。

stg → prdの2段階デプロイにより、本番環境への変更は必ずstgでの検証を経る仕組みが担保されています。ヒューマンエラーのリスクが大幅に減り、デプロイの履歴もGitHubのコミットログとして残るため、いつ誰がどの変更をデプロイしたかが明確になりました。

DABによるコード管理とGitHub Actionsによるデプロイ自動化を組み合わせることで、データパイプラインのインフラ管理が格段に安定したと感じています。本記事が参考になれば幸いです。

CTA
  • URLをコピーしました!
  • URLをコピーしました!
この記事を書いた人

データドリブンに関するお悩みはまずはSiNCEにご相談ください

目次