dbt CloudでDev/QA/Prodで環境分離した開発プロセスを考えてみた

dbt CloudでDev/QA/Prodで環境分離した開発プロセスを考えてみた

Clock Icon2025.03.04

さがらです。

dbt CloudでDev/QA/Prodで環境分離した開発プロセスを考えてみたので、本記事でまとめてみます。

前提条件

まず、Dev/QA/Prodという環境分離を行って、どのようなユースケースにデータを使いどのように環境を使い分けるのか、前提を定義しておきます。(あくまで本記事を書く上での一例です。)

  • このデータのユースケース
    • データアプリ上でこのデータを用いて可視化しており、外部ユーザーに提供している
  • 各環境の用途
    • Dev
      • 各ユーザーが新しいデータを開発する環境
      • データアプリと繋いでの可視化検証まで行いたい場合は、ローカルのDocker等でアプリを立ち上げて検証する。この際、Dev用のスキーマにも全テーブル・ビューの用意が必要
    • QA
      • ローカル環境だと検証が難しい負荷試験や脆弱性診断などを行う環境。アプリはAWS等のクラウド上で動作しているため、アプリから参照させるためにQA用のスキーマにも全テーブル・ビューの用意が必要
    • Prod
      • 実際に外部ユーザーに参照させる本番環境

また、データベースとスキーマの構成は下記のように考えるとします。

  • 使用するDWH
    • Snowflake
  • データベース構成:以下の2つのデータベースを用意
    • dbt用のデータベース
    • Rawデータ管理用のデータベース
  • dbt用データベースのスキーマ構成:以下の構成でスキーマを用意
    • prod_(staging/dwh/mart)_(データ種別など)
      • 実際に外部ユーザーに参照させる本番環境
    • qa_(staging/dwh/mart)_(データ種別など)
      • データアプリのQA環境と紐づけて、QA環境での各検証・試験を行う
    • dbt_(各ユーザー名)
      • dbt CloudのIDEで開発した各ユーザーのビルドしたテーブルなどを保持する

generate_schema_nameマクロとdbt_project.ymlの構成

先に、これらの構成を実現するためのdbt_project.ymlとgenerate_schema_nameマクロの構成について記します。

generate_schema_nameマクロ

-- Dev/QA/Prodの3環境で考える場合
-- 以下、dbt Cloud上で設定をするdefault_schema
-- Devのdefault_schema:dbt_<ユーザー名>
-- QAのdefault_schema:invalid_schema
-- Prodのdefault_schema:invalid_schema

{% macro generate_schema_name(custom_schema_name, node) %}

    {% set default_schema = target.schema %}

    {# targetが「prod」か「qa」の場合、「prod」か「qa」をprefixにつけた「custom_schema」に #}
    {% if target.name in ['prod','qa'] and custom_schema_name is not none %}
        {{ target.name }}_{{ custom_schema_name | trim }}    

    {# custom_schemaの定義なしの場合、「default_schema」に #}
    {% elif custom_schema_name is none %}
        {{ default_schema }}

    {# 上述の条件に合致しない(targetが「prod」でも「qa」でないがcustom_schemaの定義あり、など)の場合、「default_schema」に #}
    {% else %}
        {{ default_schema }}
    {% endif %}

{% endmacro %}

dbt_project.yml ※seedsとmodelsのみ

seeds:
  dbt_4layer_datastack_test:
    +database: sagara_4layer_test_onedb
    +schema: seed_data
models:
  dbt_4layer_datastack_test:
    +database: sagara_4layer_test_onedb
    +materialized: view # 下記以外のフォルダでModelを定義してしまった場合に、テーブルを作らないように
    staging:
      +materialized: view
      jaffle_shop:
        +schema: stg_jaffle_shop
    dwh:
      +materialized: table
      finance:
        +schema: dwh_finance
    mart:
      +materialized: table
      finance:
        +schema: mart_finance
      intermediate: 
        +materialized: ephemeral

各Environmentとジョブの設定

次に、各Environmentとジョブの設定をしていきます。

ProdのEnvironment

ProdのEnvironmentについてですが、以下の2点に注意して設定します。

  • Set deployment typeProduction
  • Deployment credentialsSchemainvalid_schema
    • 基本カスタムスキーマで出力先を定義するため、カスタムスキーマを定義していない場合は不適切なスキーマであることが明示的なinvalid_schemaスキーマに格納されるようにする

2025-03-03_10h46_55

2025-03-03_10h48_05

Prodのジョブ(定期実行してProd環境のデータを最新にするためDeploy job)

Prodのジョブについてですが、以下の2点に注意して設定します。このProdのジョブは、「Prod環境に定期的なスケジュールでデプロイする」という前提のジョブとなります。

  • 作成するジョブの種類:Deploy job
  • Execution settingsdbt buildを行う
  • Target nameprod

2025-03-03_18h37_09

2025-03-03_18h36_15

Prodのジョブ(プルリクエストをマージした際のMerge job)

Prodのジョブについてもう1つ別のジョブを、以下の3点に注意して設定します。このジョブは、「Prod環境のスキーマへ開発したデータをデプロイする」という前提のジョブとなります。そのため、スケジュール実行の設定は不要で、mainブランチへマージが行われた際に実行出来れば良いジョブとなります。

  • 作成するジョブの種類:Merge job
  • Execution settingsdbt build --select state:modified+を行う
  • Compare changes against an environmentProdに設定したEnvironment
  • Target nameprod

2025-03-03_18h43_36

2025-03-03_18h44_45

QAのブランチ作成

QA環境に該当するqaブランチをGitHub上で作成しておきます。

2025-03-03_18h16_03

QAのEnvironment

QAのEnvironmentについてですが、以下の3点に注意して設定します。

  • Set deployment typeStaging
  • Custom branchqa
  • Deployment credentialsSchemainvalid_schema
    • 基本カスタムスキーマで出力先を定義するため、カスタムスキーマを定義していない場合は不適切なスキーマであることが明示的なinvalid_schemaスキーマに格納されるようにする

2025-03-03_10h21_55

2025-03-03_10h27_55

QAのジョブ(プルリクエストをマージした際のMerge job)

QAのジョブについてですが、以下の3点に注意して設定します。このQAのジョブは、「QA環境のスキーマへ開発したデータをテストするためデプロイする」という前提のジョブとなります。そのため、スケジュール実行の設定は不要で、qaブランチへマージが行われた際に実行出来れば良いジョブとなります。

  • 作成するジョブの種類:Merge job
  • Execution settingsdbt clone --full-refreshのあとにdbt build --select state:modified+を行う
    • --full-refreshを入れることで、対象のテーブル・ビューが存在した場合でも、上書きしてcloneを行う事ができます。(公式ドキュメントより)
    • dbt cloneの挙動についてはこちらの記事も参考になると思います。
  • Compare changes against an environmentProdに設定したEnvironment
  • Target nameqa

2025-03-03_18h39_20

2025-03-03_18h06_01

QAのジョブ(Prod EnvironmentをCloneするDeploy Job)

QAのジョブについてもう1つ別のジョブを、以下6点に注意して設定します。

  • 作成するジョブの種類:Deploy job
  • Environment:QAに設定したEnvironment
  • Execution settingsdbt clone --full-refresh
    • --full-refreshを入れることで、対象のテーブル・ビューが存在した場合でも、上書きしてcloneを行う事ができます。(公式ドキュメントより)
  • Target nameqa
  • Compare changes against an environmentProdに設定したEnvironment
  • オプション設定
    • Job completion:後述する理由から、Prod Environmentの「定期実行してProd環境のデータを最新にするためDeploy job」の後にこのcloneのジョブが動くようにすると、Staging Environmentのデータを自動で最新にすることが出来ます

2025-03-03_16h30_08

2025-03-03_16h30_40

2025-03-04_17h07_52

このジョブが必要な理由は以下2点です。

  • IDEの開発でDefer to staging/productionを設定してdbt cloneを行うと、Staging Environmentのデータを最初に見てcloneする仕様となっているため、IDEで開発する際のデータが古くなってしまうリスクがある
  • 初期設定として、QA Environmentでも一度ジョブを実行してstateを作成しておかないと、IDEでの開発でDefer to staging/productionを設定してdbt cloneなどのstate比較が必要なコマンドを実行したときにエラーとなる。(下図はQA Environmentでジョブを一度も実行していない場合の、IDEでのdbt cloneコマンド実行時のエラー例)

2025-03-03_11h14_38

※余談:このジョブは本来必要のないジョブだと私は考えているため、QA EnvironmentのstateがないとエラーになるというIDEのDefer to staging/productionの仕様についてはdbt Labs社にも問い合わせております。

QAのジョブ(プルリクエスト発行時のCI job) ※任意

今回は割愛しますが、QA環境に対してはプルリクエスト発行時のCI jobを設定しても良いと思います。QA環境上でも各種テストをしますが、「そもそもdbtの各Modelは問題ないよね」ということを事前に確認するためにCIとしてビルド・テストを行うイメージです。

上述した「プルリクエストをマージした際のMerge job」と同じように、dbt clone --full-refreshのあとにdbt build --select state:modified+を行うようにすれば基本的には問題ないと思います。

CI jobの設定については下記のブログが参考になると思います。

https://dev.classmethod.jp/articles/dbt-cloud-new-ci-job/

実際の開発の流れを試してみた

事前準備:Prod Environmentで「定期実行してProd環境のデータを最新にするためDeploy job」を実行

実際に開発の流れを試す前に、一度Prod Environmentで「定期実行してProd環境のデータを最新にするためDeploy job」を実行しておきます。この理由は、既にProd環境にデータが存在する前提で開発の流れを試したいからです。

一度ジョブを実行すると、下図のようにPROD_のprefix付きで、seed・staging・dwh・martの各スキーマとテーブル・ビューが作られました。

2025-03-03_11h00_28

事前準備:QA Environmentで「Prod EnvironmentをCloneするDeploy Job」を実行

QA Environmentでも一度「Prod EnvironmentをCloneするDeploy Job」を実行しておきます。

これにより、下図のようにクエリが実行され、QA環境のスキーマが作られます。これでdbt CloudのIDEでdbt cloneなどを行う際も、問題なくclone出来るようになります。

2025-03-03_16h39_22

2025-03-03_16h28_00

IDEでブランチを切って開発

実際にブランチを切ってIDEで開発をしてみます。

ブランチを切った後に、dbt cloneを実行することで、QA環境のスキーマに存在する各テーブル・ビューを自分専用のスキーマにクローンすることが出来ます。

2025-03-03_16h45_11

2025-03-03_16h33_22

あとは通常通りの開発を行います。今回は既存のModelであるstg_customers_tmp2.sqlを少し書き換えて、IDE上でdbt build --select state:modified+を実行します。

2025-03-03_16h48_24

この後、自分専用のスキーマを参照させて、データアプリからの挙動確認も可能です。

プルリクエストを発行しQAブランチにマージ

次に、コミットしてQAブランチに対するプルリクエストを発行して、マージします。

2025-03-03_18h22_22

すると、QA Environmentで設定したMerge jobが実行されます。Prod EnvironmentのスキーマのCloneを行って、差分があるModelだけがQA Environmentのスキーマにビルドされます。

2025-03-03_18h28_37

2025-03-03_18h30_39

この後、QA EnvironmentのスキーマをデータアプリのQA環境から参照させて、各種検証を行います。

QAブランチからプルリクエストを発行しmainブランチにマージ

QA Environmentでの検証を終えたら最後に、QAブランチからプルリクエストを発行しmainブランチにマージします。

2025-03-04_17h24_20

すると、Prod Environmentで設定したMerge jobが実行されます。新しく開発した差分があるModelだけがProd Environmentのスキーマにビルドされます。

2025-03-04_17h25_26

2025-03-04_17h26_14

これで、一通りの開発は完了です!

最後に

dbt CloudでDev/QA/Prodで環境分離した開発プロセスを考えてみたので、その内容をまとめてみました。

今回のユースケース上、「各環境のスキーマに全テーブル・ビューの用意が必要」という要件を追加していたこともあり、少し込み入った手順になってしまったかもしれません。

もっと上手いやり方があるのでは…?とも正直感じているため、何か気づきがあればぜひXなどで教えて頂きたいです…!

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.