概要
この記事ではdbtのドキュメントを参考に、GitHub Actionsを用いてdbtプロジェクトのCI/CDを実装していきます。
実装するワークフローは以下の2つです。
-
コミットのpush時に自動実行されるワークフロー
処理内容:SQLFluffを用いてLintする -
pull requestがマージされた時に自動実行されるワークフロー
処理内容:dbt Cloud APIを呼び出してdbtのjobを実行する
※ この記事では既にdbtプロジェクトが存在し、dbtのjobも作成済みの状態を前提としています。
1. コミットのpush時に自動実行されるワークフロー
早速1つ目のCIワークフローから実装していきます。
dbtプロジェクトへの処理追加
まずプロジェクトのルートディレクトリに.github
フォルダを作成し、さらにその中にworkflows
フォルダを作成し、そこにlint_on_push.yml
というファイルを作成します。
my_project
├── .github
│ ├── workflows
│ │ └── lint_on_push.yml
lint_on_push.yml
ファイルの中身には以下を記述します。
name: lint dbt project on push
on:
push:
branches-ignore:
- 'main'
jobs:
# this job runs SQLFluff with a specific set of rules
# note the dialect is set to Snowflake, so make that specific to your setup
# details on linter rules: https://docs.sqlfluff.com/en/stable/rules.html
lint_project:
name: Run SQLFluff linter
runs-on: ubuntu-latest
steps:
- uses: "actions/checkout@v3"
- uses: "actions/setup-python@v2"
with:
python-version: "3.9"
- name: Install SQLFluff
run: "pip install sqlfluff==0.13.1"
- name: Lint project
run: "sqlfluff lint models --dialect snowflake --rules L019,L020,L021,L022"
ワークフロー実行
コードの説明の前にまず実行してみます。
上記の内容でファイルを作成したらコミットしてpushすることで、ワークフローが実行されます。
GitHub上でリポジトリのActionsタブを見てみると、ワークフローが実行され、Lintが成功していることが分かります。
コード説明
このワークフローでは、mainブランチ以外にpushされた時にSQLFluffというLinterを用いてLintを行っています。
※ Lint: ざっくり言うとコードのフォーマットなど、書き方に問題がないかチェックする処理
sqlfluff lint models
によってmodelsディレクトリ配下のSQLに対してLintを行います。
--dialect
オプションでベースとなるSQLとしてSnowflakeのSQLを指定していて、--rules
オプションでは以下4つのルールをチェックするように指定しています。
L019: カラムなどを複数指定するときにカンマの位置が行の末尾になっていること
L020: エイリアスでテーブル名を付けたり複数DBからテーブルを参照する時に、テーブル名が一意になっていること
L021: あるカラムに対してGROUP BYとDISTINCTをどちらとも指定してしまっていないこと
L022: CTEの閉じ括弧の後に空行があること
※ これらの4つのルールは例として指定しているだけなので、どのルールを設定するかはチーム毎に決める必要があります。
SQLFluffが他にどんなルールを指定できるかは、ドキュメントのルールに関するページを参照してください。
今回指定した4つのルールのいずれかを違反したSQLの記述があった場合はLintがエラーになります。
試しにCTEを使用している適当なモデルで、以下のようにCTEの閉じ括弧下の空行を削除してコミット&pushしてみます。
ワークフローの結果を確認してみると、Lintの実行がエラーになり、L022のルール(CTEの閉じ括弧の後に空行があること)を守れていないことが分かります。
Lintが成功するようにコードを戻したら2つ目のワークフロー作成に移ります。
2. pull requestがマージされた時に自動実行されるワークフロー
次は、mainブランチにpushされた時(= pull requestがマージされた時)にdbt Cloud APIを呼び出してdbtのjobを実行するワークフローを実装していきます。
dbt Cloud APIキーの取得
dbt Cloud APIを呼び出すためにAPIキーが必要なので、取得していきます。
まずdbt Cloudの画面で Account Settings ページにアクセスし、ページ下部にある Service Tokens の「New Token」ボタンを押します。
CICD Token
のような名前を入力し、「+Add」を押してJob Admin
の権限を選択し、saveします。
そうするとTokenが作成されるので、コピーして安全な場所で保管しておきます。
GitHubのsecretへの登録
次に、取得したTokenをGitHubリポジトリのsecretに保存していきます。
リポジトリの Settings の Secrets and Variables ドロップダウンにある Actions ページで、「New repository secret」ボタンを押します。
Name にはDBT_API_KEY
、Secrets には作成したTokenを入力し、「Add secret」ボタンを押せば完了です。
dbtプロジェクトへの処理追加
次はdbtプロジェクトの作業に入ります。
プロジェクトのルートディレクトリにpython
フォルダを作成し、run_and_monitor_dbt_job.py
というファイルを作成し、このgistの内容をコピペします。
このpythonファイルでは、渡されたjob IDなどの情報をもとにdbt Cloud APIを呼び出し、jobが成功したら正常終了、失敗したらエラーを投げるというような処理を行います。
では.github/workflows
配下にdbt_run_on_merge.yml
を作成します。
この記事で追加したファイルの最終的な構成は以下のようになります。
my_project
├── python
│ └── run_and_monitor_dbt_job.py
├── .github
│ ├── workflows
│ │ └── dbt_run_on_merge.yml
│ │ └── lint_on_push.yml
dbt_run_on_merge.yml
には以下の内容を記述します。
name: run dbt Cloud job on push
# This filter says only run this job when there is a push to the main branch
# This works off the assumption that you've restrictred this branch to only all PRs to push to the deafult branch
# Update the name to match the name of your default branch
on:
push:
branches:
- 'main'
jobs:
# the job calls the dbt Cloud API to run a job
run_dbt_cloud_job:
name: Run dbt Cloud Job
runs-on: ubuntu-latest
# Set the environment variables needed for the run
env:
DBT_ACCOUNT_ID: 00000 # enter your account id
DBT_PROJECT_ID: 00000 # enter your project id
DBT_PR_JOB_ID: 00000 # enter your job id
DBT_API_KEY: ${{ secrets.DBT_API_KEY }}
DBT_JOB_CAUSE: 'GitHub Pipeline CI Job'
DBT_JOB_BRANCH: ${{ github.ref_name }}
steps:
- uses: "actions/checkout@v3"
- uses: "actions/setup-python@v4"
with:
python-version: "3.9"
- name: Run dbt Cloud job
run: "python python/run_and_monitor_dbt_job.py"
DBT_ACCOUNT_ID
, DBT_PROJECT_ID
, DBT_PR_JOB_ID
には自分の状況にあったIDをそれぞれ入力します。
それぞれのIDはdbt CloudのURLから取得できるので、ブラウザでdbt Cloudのjobのページを開きURLの数字を見ると、左からアカウントID
・プロジェクトID
・ジョブID
に対応しています。
このワークフローでは、mainブランチにpushされた時(= pull requestがマージされた時)に各IDやTokenなどの情報を環境変数としてセットし、先ほど作成したdbt Cloud API呼び出し用のpythonファイルを実行します。
ワークフロー実行
ではコミット&push後、pull requestを作ってマージまで行ってみます。
マージ後にActionsタブを確認すると、作成したワークフローが実行され成功しています。
詳細を見てみると、作成したpythonファイルに記述された通りにログが表示され、dbt jobが成功していることも分かります。
dbt Cloudの方で実行されたjobを見ると、GitHubのCI Jobから実行されたことや、トリガーになったコミットなども分かります。
まとめ
この記事ではdbtのドキュメントを参考に以下のCI/CDを実装しました。
- push時にLintを行う
- pull requestのマージ時にdbt Cloud jobを実行する