BI LAB データ活用研究所 - INSIGHT LAB

【dbt Cloud】CI/CD環境を構築!持続可能なデータ基盤でデータ利活用を加速させる

作成者: uta|2024年6月28日

はじめに

データ基盤の運用において、CI/CDはアジャイル開発のスピードを加速させ、提供するデータの品質も向上させます。dbt用のCI/CD環境を構築する手段として「Github Actions」を用いることが一般的かと思いますが、経験のないエンジニアにとっては導入と運用のハードルが高いと思います。

dbt Cloudを使用すると、dbt Core×Github ActionsによるCI/CDの構築よりも遥かに簡単に実装することができます。本記事では、dbt CloudのCI/CDジョブ機能とEnvironmentについておさらいし、実装の流れをお見せします。

 

こんな方向け

  • データ基盤のデータ変換ツールとしてdbt Cloudを採用している・しようとしている方
  • 開発~運用のサイクルのリードタイムに課題を感じている方
  • Github Actionsを使ったCI/CDの実装は難しいと感じている方

 

CI/CDとは

CI/CDのあるデータ基盤は、開発~検証~リリースまでにかかる時間が格段に減り、誤操作やケアレスミスによるリカバリ作業も限りなく0に近づけることができます。エンジニアもミスを恐れず開発作業に専念することができ、開発内容の質の向上も期待できます。

 

【CI】
開発者がコードをリポジトリにマージするたびに、自動的にビルド、テスト、およびコードの品質チェックが行われる仕組みです。開発メンバー全員の開発内容はリリース前に必ず実行テストが行われるため、問題を素早く発見し潜在的なエラー・問題を検知できるようになります。

【CD】
mainブランチにマージされた変更内容が自動的に本番環境にデプロイされます。手動によるリリースは、操作ミスやリリース作業忘れなどのリスクがありますが、本番環境へ変更が自動的に実行されるため、これらのリスクを低減することが期待できます。

【Slim CI/CD】
Slim CI/CDは、直近の変更のあったモデルとそれに関連するモデルのみを実行させることができる機能です。CI/CDの実行にかかる処理時間を短縮し処理コストを大幅に削減することができます。

 

dbt Cloudの場合、「Environment」と「Job」という機能を用いてCI/CD環境を構築します。

【Environment】
DWHでは、開発環境と本番環境を分けて運用することが一般的かと思います。Environmentは、DWH上の実行環境を動的に切り替えるための概念です。Environmentを作成する際、設定項目の中に「Environment Type」と「Deployment Type」があります。


↑Environmentの概要図

 

Environment Type 用途
Development IDE上でのコマンドを実行する開発環境。(削除・追加 不可)
Deployment 定期実行やCI/CDでコマンドを実行するデプロイ環境(削除・追加 可)

Deployment Type 用途
General 一般的な環境
Staging ステージング用の環境
Production 本番実行用の環境

 


【Job】
手動によるIDE上のコマンド実行以外で、コマンドを実行したい場合、ジョブを作成することで、時間や特定のアクションをトリガーとして設定したコマンドを実行させることができます。


↑Jobの概要図

Job Type 用途
Deploy job 手動またはスケジュールをトリガーに実行するジョブ
Continuous integration job プルリクエストの作成をトリガーに実行するジョブ
Merge job マージの実行をトリガーに実行するジョブ

 

 

前提

本記事で構築するCI/CD環境の前提条件は以下になります。

  • dbt Cloud

    • DWH:Snowflake
    • リポジトリ:Github
    • プラン:Developer
    • バージョン:1.7
  • 環境

    • DB_PROD_UTA(データベース)
      • dbt(スキーマ)
    • DB_DEV_UTA(データベース)
      • dbt(スキーマ)
  • データパイプライン

    • sources
      • raw_salesheader
      • raw_salesdetail
    • refs
      • stg_salesheader
      • stg_salesdetail
      • fct_sales

 

準備

始めに、CICDを導入していないパイプラインの状態を再現します。

本番用のEnvironmentを作成します。

 

続いて、接続設定は本番用の内容に設定します。

 

バッチ更新用のジョブを作成します。

 

作成後、手動実行します。(スケジュールが設定され定期実行する想定)

 

これで定期的にデータパイプラインが稼働している状態を再現できました。

 

CI

ここからは既存データ基盤にCIを導入します。開発作業を終えて変更内容をコミット、プルリクエストを作成すると検証環境に変更内容に関連する処理が自動で実行され、エラー有無が確認できます。

 

CIの実装

CI環境を構築するためには、はじめにCI用のジョブを作成します。

ジョブの作成から「Continuous integration job」をクリックします。

 

CI用のジョブ設定を行っていきます。

 

state:modified+を設定したコマンドを登録します。
※このコマンドは直近の実行と変更内容の差分をチェックし、差分のあるモデルと後続を実行

※deferralは、前回実行との差分をチェックする対象のEnvironmentを指定

 

CIの動作確認

カラム名をsales_qtyからqtyに変更して変更をコミットします。
※モデルstg_salesdetailから見たらカラム名の変更は特に問題ありません(伏線)

 

Github側でプルリクエストが作成されると、CIジョブによるコマンド実行が行われます。

 

CIジョブの実行による結果はエラーとなります。
※モデルfct_salesではカラム名が変更されていないため、実際はエラーとなる変更でした(回収)

 

クエリ履歴を見ると、CI用に作成されたスキーマ上で変更のあったモデルが実行されています。

 

また、今回の変更と関係ないテーブルは本番のデータが使用されます。= Slim CI

 

CIの効果

このように、開発過程ではエラーとならない変更でも、関連するモデルに影響を及ぼす変更である可能性は十分にあり得ます。データ基盤を詳しく知る人間であれば気付けたエラーかもしれませんし、後続のモデルも実行するような開発ルールを定めておくことでも防げたエラーです。

しかし、直近でアサインされた人間が開発していたり、ルールを無視した開発を行っていた場合エラーに気付くことができず、本番での実行で初めてエラーが顕在化します。

CIが導入されていれば、全ての開発作業はマージ前に、変更したモデルとその後続のモデルが実行され、エラーのある変更か否かをリリース前に検知することができます。

 

CD

CIによって、開発内容の検証実行が自動化されました。続いて、CDジョブを作成しプルリクエストがmainブランチにマージされたとき、変更内容を自動で本番環境に反映されるようにします。

 

CDの実装

ジョブの作成から「Merge job」をクリックします。

 

CD用のジョブを作成します。

 

CIと同様、指定した環境と差分のあるモデルを実行するコマンドを登録しジョブを保存。

 

CDの動作確認

CIジョブでのエラーの原因を修正して、プルリクエストを更新します。

 

プルリクエストが更新されると再度CIジョブが実行され、成功します。

 

問題なく動作することが確認できたらプルリクエストをマージします。

 

マージ後、CDジョブが実行されます。
※warningは無視してください(data_testの書き換え漏れです。。)

 

DWH側では元のスキーマに向けて、変更のあったモデルのクエリが実行されます。

 

CDの効果

CIによって本番環境での実行の正当性が保証されても、本番環境上でのリリース操作でミスや実行忘れがあれば本番環境でエラーとなりデータ利用者に影響を与えます。

こうしたリスクを最低限に抑えるため、CDジョブによってリリース作業を自動化することで、リリースにかかる工数を削減しつつリリースミスを減らすことができます。

 

本番環境とは異なる環境で検証したいが。。。

今回の内容だと、CIによる実行は本番環境上で行われることになります。セキュリティ要件上、本番環境にアクセスさせたくないケースが想定されます。

新たな Environmentを作成し、本番環境とは別環境で実行を行うことになりますが、CIジョブの仕様上、Production環境の実行差分を検証するため、別のDeployment環境を設定すると差分が残っておらず全てのモデルが実行対象となってしまいます。

こうしたケースでは、新しく追加されたDeployment Typeの「STG(ステージング)」を使用することで、実稼働環境のデータへのアクセスを制限しつつ、Slim CI/CD環境を構築することが可能になります。

 

課題

シンプルにCI/CD環境を構築しただけでは、いくつか課題があります。

1:CI用に作成されたスキーマが残り続ける

CIジョブが実行されると、プルリクエストごとにスキーマが作成されてクエリが実行されます。しかし、作成されたスキーマは残り続けるため、視認性が下がりストレージ料金も嵩みます。

Snowflakeのタスクやマクロなどで定期的にクリーンナップする処理を追加を検討する必要があります。

 

2:全データで検証が行われる

Slim CIのおかげで、更新対象が関係するモデルのみに絞られますが、クエリは本番と同量のデータでモデル実行が行われます。変更による影響範囲が広範囲に及ぶ場合、検証実行が全件更新で行われると1回の検証に大幅な処理コストがかかります。

CIジョブの設定でTarget nameに任意の名称(例:ci)を設定し、モデル内にJinjaでtargetによってWhere句を動的に切り替える処理を記述することで、CI実行の場合のみ参照するデータを直近データに制限するなどの対策があります。

 

おわりに

dbt Coreをメインで使用する場合、CI/CDおよびSlim CI/CDを実装するために0から仕組みを構築する必要があります。dbt Cloudを使用すれば、本記事のようにEnvironmentとJobの設定だけでCI/CD環境を構築することができます。

CI/CD環境のないデータ基盤の開発は、ヒューマンエラーや環境差異による潜在的なエラーのリスクを抱えながら運用することになります。データ品質が下がりデータ提供が遅れ続けると、データの価値と信用が失われてしまいます。

CI/CD環境のあるデータ基盤の開発は、エンジニアだけでなくアナリストでもデータ基盤開発に参加できるようになります。データの品質はCIによる実行とレビューによって最低限保証され、たくさんの人をデータ基盤に巻き込むことが容易になります。

もし、こうした課題を抱えている方はぜひCI/CDの導入を検討してみはいかかでしょうか?