Dagsterとdbt CoreをDockerコンテナ上に構築する

Dagsterとdbt CoreをDockerコンテナ上に構築する

Clock Icon2025.05.27

こんにちは、データ事業本部のキタガワです。
今回はDagsterとdbtの構成をDockerコンテナ上で動かすサンプルをサクッと作っていきたいと思います。
公式のチュートリアルで使われているdbtのサンプルリポジトリがアーカイブ化されていたりして、そのままでは動かないところがあったので、新しいサンプルリポジトリを用いて試してみた記録として残します。

Dagsterとは

Dagsterはデータエンジニアのためのツールです。
いわゆるオーケストレーションを行うためのツールですがデータアセットに焦点を当てているところが特徴です。
中心にはSDA(Software-Defined Assets)という概念があり、データパイプラインにおいて実行されるタスクではなく、生成される永続的なデータ(データベースのテーブル、S3のファイル、機械学習モデルなど)を宣言的に定義する手法をとっています。

https://docs.dagster.io/getting-started/concepts
https://dagster.io/glossary/software-defined-assets

またDagster自身がAirflowを強く意識しており、以下のような課題を解決できるとしています。

  • ローカル環境での開発とテスト
  • デバッグ
  • データリネージとアセットの管理
  • スケーラビリティと分離
  • CI/CD

詳しくは以下の記事をご覧ください。

https://dagster.io/blog/dagster-airflow

DagsterにはOSS版のDagsterと有償版のDagster+があります。
この記事ではOSS版を扱っていきます。

dbtとは

dbtは言わずと知れたETLの「T」を担うデータエンジニアリングのための強力なツールです。
ここでわざわざ語らずとも、弊社の先人が積み重ねたブログの数々をご覧いただければ良いと思います。

https://dev.classmethod.jp/tags/dbt/
https://dev.classmethod.jp/articles/dbt-overview-2023/

dbtにもOSS版のdbt Coreと有償版のdbt Cloudがありますが、この記事ではOSS版を扱っていきます。

なぜDagsterとdbtを組み合わせるのか?

dbt以外のツールなどと連携させてオーケストレーションすることができます。
また前述の通りDagsterはデータアセットを中心とするコンセプトのもとに開発されており、dbtのモデル中心の考え方と相性が良いです。
実際、dbtと連携する場合には manifest.json を通じて非常に簡単に取り込めるようになっています。

やってみる

dbtのサンプルプロジェクトとして jaffle shop を使います。
このチュートリアルやインターネット上のブログなどでは jaffle_shop を使っているものが多いですが、このリポジトリは現在アーカイブされ、jaffle_shop_duckdb を使用するように案内されています。
よってこのブログでも jaffle_shop_duckdb を使用します。

Pythonの初期設定

Pythonが必要になります。
ここでは uv を使ってバッケージの管理を行います。
また main.py はいらないので消しておきます。

uv init dagster-dbt-docker-sample --python 3.12
cd dagster-dbt-docker-sample
uv add dagster-dbt dbt-duckdb
rm main.py

Dagsterプロジェクトの作成

ありがたいことにDagster公式がさまざまなツールと連携したサンプルを用意してくれています。

https://github.com/dagster-io/dagster

今回はこの中の examples/deploy_docker を元に進めていきます。
まずはこのリポジトリをクローンします。

git clone https://github.com/dagster-io/dagster.git

dbtプロジェクトの作成

次に jaffle_shop_duckdb を公式のリポジトリからクローンします。

git clone https://github.com/dbt-labs/jaffle_shop_duckdb.git

dbtのモデルをDagsterのアセットとして読み込む

dagster-dbt パッケージを使うことで、dbtのモデルをDagsterのアセットとして読み込むことができます。
dbt_project.yml があるディレクトリを指定して以下のコマンドを実行します。

❯ uv run dagster-dbt project scaffold --project-name dagster_project --dbt-project-dir jaffle_shop_duckdb

Running with dagster-dbt version: 0.26.17.
Initializing Dagster project dagster_project in the current working directory for dbt project directory 
/Users/user/dagster-dbt-docker-sample/jaffle_shop_duckdb.
Using profiles.yml found in /Users/user/dagster-dbt-docker-sample/jaffle_shop_duckdb/profiles.yml.
Your Dagster project has been initialized. To view your dbt project in Dagster, run the following commands:

 cd '/Users/user/dagster-dbt-docker-sample/dagster_project'                                         
 dagster dev

成功すれば dagster_project/ という名前のDagsterのコードが格納されたディレクトリが作成されます。
試しにアウトプットにあるように dagster_project/ に移動して dagster dev を実行してみます。
この際 dagster-webserver をインストールしていないとエラーが出るので注意してください。
uvをお使いの方は以下のように実行できます。

cd dagster_project
❯ uv run --extra dev  dagster dev

Installed 20 packages in 45ms
2025-05-26 21:16:26 +0900 - dagster - INFO - Using temporary directory /Users/user/dagster-dbt-docker-sample/dagster_project/.tmp_dagster_home_n74eclil for storage. This will be removed when dagster dev exits.
2025-05-26 21:16:26 +0900 - dagster - INFO - To persist information across sessions, set the environment variable DAGSTER_HOME to a directory to use.
2025-05-26 21:16:28 +0900 - dagster - INFO - Launching Dagster services...
INFO:dagster.builtin:Running dbt command: `dbt parse --quiet`.
INFO:dagster.builtin:Finished dbt command: `dbt parse --quiet`.
INFO:dagster.code_server:Started Dagster code server for module dagster_project.definitions in process 69057
2025-05-26 21:16:36 +0900 - dagster.daemon - INFO - Instance is configured with the following daemons: ['AssetDaemon', 'BackfillDaemon', 'QueuedRunCoordinatorDaemon', 'SchedulerDaemon', 'SensorDaemon']
2025-05-26 21:16:36 +0900 - dagster-webserver - INFO - Serving dagster-webserver on http://127.0.0.1:3000 in process 69082

正常に実行できるとDagsterのwebserverが立ち上がります。
表示されている http://127.0.0.1:3000 にWebブラウザでアクセスすると次のようなUIが表示されます。

alt text

右上の Materialize all ボタンをクリックしてアセットのマテリアライズを実行できます。
実際に実行してみるとRunsのタブから実行中のジョブを確認できます。

alt text

ここまで確認できたらwebserverはCtrl+Cで終了しておきましょう。

Dockerコンテナ上で動かす

引き続きこれをそのままDockerコンテナ上で動かすところまでやっていきます。
先ほどまでDuckDBを使っていましたが、ここからはPostgreSQLに乗り換えます。

まずは今から作るアーキテクチャの公式の概要図を載せておきます。
こちらの図はKubernetes上で動かす場合のものですが、Dockerコンテナ上で動かす場合もほぼ同じです。

alt text
https://docs.dagster.io/guides/deploy/oss-deployment-architecture

必要となるコンテナは以下の4つです。

  • Dagster webserver
  • Dagster daemon
  • Code Location
  • Database

それぞれのコンテナの大まかな役割は以下の通りです。

  • Dagster webserver: Dagsterのwebserver。DagsterのUIを表示する。
  • Dagster daemon: Dagsterのdaemon。ジョブを実行したり管理したりする。
  • Code Location: Dagsterの定義に関するメタデータを提供したりする。
  • PostgreSQL: データベース。ログやメタデータを保存する。マテリアライズしたアセットの保存場所にもなる(分けることも可能)。

では先ほどクローンした dagster リポジトリから必要なファイルをコピーします。

cd ..
cp dagster/examples/deploy_docker/dagster.yaml ./dagster_project/
cp dagster/examples/deploy_docker/workspace.yaml ./dagster_project/
cp dagster/examples/deploy_docker/docker-compose.yml ./
cp dagster/examples/deploy_docker/Dockerfile_dagster ./
cp dagster/examples/deploy_docker/Dockerfile_user_code ./

次にDockerfileを現状に合わせて修正します。
修正するのは次の4ファイルです。

  • dagster-dbt-docker-sample/Dockerfile_dagster
  • dagster-dbt-docker-sample/Dockerfile_user_code
  • dagster-dbt-docker-sample/jaffle_shop_duckdb/profiles.yml
  • dagster-dbt-docker-sample/dagster_project/dagster_project/definitions.py

Dagsterイメージはほとんとそのままで大丈夫ですが、Pythonのバージョンを3.12に変更し、COPY文をディレクトリに合わせて修正しました。
Code Locationのイメージは追加のライブラリとDagsterおよびdbtのフォルダを含める必要があります。

Dockerfile_dagster
@@ -1,7 +1,7 @@
 # Dagster libraries to run both dagster-webserver and the dagster-daemon. Does not
 # need to have access to any pipeline code.

-FROM python:3.10-slim
+FROM python:3.12-slim

 RUN pip install \
     dagster \
@@ -15,6 +15,6 @@ ENV DAGSTER_HOME=/opt/dagster/dagster_home/

 RUN mkdir -p $DAGSTER_HOME

-COPY dagster.yaml workspace.yaml $DAGSTER_HOME
+COPY dagster_project/dagster.yaml dagster_project/workspace.yaml $DAGSTER_HOME

 WORKDIR $DAGSTER_HOME
Dockerfile_user_code
@@ -1,4 +1,4 @@
-FROM python:3.10-slim
+FROM python:3.12-slim

# Checkout and install dagster libraries needed to run the gRPC server
# exposing your repository to dagster-webserver and dagster-daemon, and to load the DagsterInstance
@@ -6,16 +6,23 @@ FROM python:3.10-slim
RUN pip install \
    dagster \
    dagster-postgres \
-    dagster-docker
+    dagster-docker \
+    dagster-dbt \
+    dbt-postgres

# Add repository code

WORKDIR /opt/dagster/app

-COPY definitions.py /opt/dagster/app
+COPY dagster_project/ ./dagster_project/
+COPY jaffle_shop_duckdb/ ./jaffle_shop_duckdb/
+
+RUN dagster-dbt project prepare-and-package --file dagster_project/dagster_project/project.py

# Run dagster gRPC server on port 4000

+WORKDIR /opt/dagster/app/dagster_project/
+
EXPOSE 4000

-CMD ["dagster", "api", "grpc", "-h", "0.0.0.0", "-p", "4000", "-f", "definitions.py"]
+CMD ["dagster", "api", "grpc", "--module-name", "dagster_project.definitions", "--host", "0.0.0.0", "--port", "4000"]

ここではPostgreSQLを使用するため、 profiles.yml を修正して接続情報を設定する必要があります。

profiles.yml
@@ -3,6 +3,11 @@ jaffle_shop:
   target: dev
   outputs:
     dev:
-      type: duckdb
-      path: 'jaffle_shop.duckdb'
+      type: postgres
+      host: docker_example_postgresql
+      port: 5432
+      user: postgres_user
+      password: postgres_password
+      dbname: postgres_db
+      schema: jaffle_shop
       threads: 24

また dagster-dbt project prepare-and-package コマンドでパッケージングしたdbtプロジェクトを読み込みたいため、 definitions.py を修正します。

definitions.py
@@ -8,6 +8,9 @@ defs = Definitions(
     assets=[jaffle_shop_dbt_assets],
     schedules=schedules,
     resources={
-        "dbt": DbtCliResource(project_dir=jaffle_shop_project),
+        "dbt": DbtCliResource(
+            project_dir=jaffle_shop_project,
+            packaged_project_dir=jaffle_shop_project.packaged_project_dir
+        ),
     },
 )

それではコンテナを立ち上げていきましょう。
docker-compose.yml があるディレクトリで以下コマンドを実行します。

docker compose build
docker compose up

これでコンテナ群が立ち上がります。
webserberが正常に起動した後 http://0.0.0.0:3000 にアクセスすると先ほどと同じようにDagsterのUIが表示されます。
同じように Materialize all ボタンをクリックするとジョブの実行ができます。

alt text

このように全てのアセットが緑色になると正常にマテリアライズされたことになります。
結果は profiles.yml で指定したデータベースに保存されます。

試しにローカルのコンテナで動作しているPostgreSQLに接続してみます。

docker exec -it docker_example_postgresql psql -U postgres_user -d postgres_db

psql (11.16 (Debian 11.16-1.pgdg90+1))
Type "help" for help.

postgres_db=# \dt jaffle_shop.*
                  List of relations
   Schema    |     Name      | Type  |     Owner     
-------------+---------------+-------+---------------
 jaffle_shop | customers     | table | postgres_user
 jaffle_shop | orders        | table | postgres_user
 jaffle_shop | raw_customers | table | postgres_user
 jaffle_shop | raw_orders    | table | postgres_user
 jaffle_shop | raw_payments  | table | postgres_user
(5 rows)

postgres_db=# \dv jaffle_shop.*
                 List of relations
   Schema    |     Name      | Type |     Owner     
-------------+---------------+------+---------------
 jaffle_shop | stg_customers | view | postgres_user
 jaffle_shop | stg_orders    | view | postgres_user
 jaffle_shop | stg_payments  | view | postgres_user
 (3 rows)

postgres_db=# select * from jaffle_shop.customers limit 10;
 customer_id | first_name | last_name | first_order | most_recent_order | number_of_orders | customer_lifetime_value 
-------------+------------+-----------+-------------+-------------------+------------------+-------------------------
           1 | Michael    | P.        | 2018-01-01  | 2018-02-10        |                2 |                      33
           2 | Shawn      | M.        | 2018-01-11  | 2018-01-11        |                1 |                      23
           3 | Kathleen   | P.        | 2018-01-02  | 2018-03-11        |                3 |                      65
           4 | Jimmy      | C.        |             |                   |                  |                        
           5 | Katherine  | R.        |             |                   |                  |                        
           6 | Sarah      | R.        | 2018-02-19  | 2018-02-19        |                1 |                       8
           7 | Martin     | M.        | 2018-01-14  | 2018-01-14        |                1 |                      26
           8 | Frank      | R.        | 2018-01-29  | 2018-03-12        |                2 |                      45
           9 | Jennifer   | F.        | 2018-03-17  | 2018-03-17        |                1 |                      30
          10 | Henry      | W.        |             |                   |                  |                        
(10 rows)

いいですね!
結果もきちんと格納されています。

まとめ

Dagsterとdbtの公式サンプルを駆使しながらDockerコンテナ上でDagsterとdbtを動かす方法を紹介しました。
Dagsterもdbtもデータエンジニアリングの観点から開発されているため、それぞれのツールの特徴を理解しながら連携することでより効率的なデータパイプラインを構築できるのではないかと思います。

今回はとにかく既存のものを使用してシンプルに構築することを目指しました。
次回はこの構成をさらに発展させより実践的で、AWS ECSベースの構成に作り変えたものを紹介したいと思います。

それではまた次回の記事でお会いしましょう!

参考

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.