
Dagsterとdbt CoreをDockerコンテナ上に構築する
こんにちは、データ事業本部のキタガワです。
今回はDagsterとdbtの構成をDockerコンテナ上で動かすサンプルをサクッと作っていきたいと思います。
公式のチュートリアルで使われているdbtのサンプルリポジトリがアーカイブ化されていたりして、そのままでは動かないところがあったので、新しいサンプルリポジトリを用いて試してみた記録として残します。
Dagsterとは
Dagsterはデータエンジニアのためのツールです。
いわゆるオーケストレーションを行うためのツールですがデータアセットに焦点を当てているところが特徴です。
中心にはSDA(Software-Defined Assets)という概念があり、データパイプラインにおいて実行されるタスクではなく、生成される永続的なデータ(データベースのテーブル、S3のファイル、機械学習モデルなど)を宣言的に定義する手法をとっています。
またDagster自身がAirflowを強く意識しており、以下のような課題を解決できるとしています。
- ローカル環境での開発とテスト
- デバッグ
- データリネージとアセットの管理
- スケーラビリティと分離
- CI/CD
詳しくは以下の記事をご覧ください。
DagsterにはOSS版のDagsterと有償版のDagster+があります。
この記事ではOSS版を扱っていきます。
dbtとは
dbtは言わずと知れたETLの「T」を担うデータエンジニアリングのための強力なツールです。
ここでわざわざ語らずとも、弊社の先人が積み重ねたブログの数々をご覧いただければ良いと思います。
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公式がさまざまなツールと連携したサンプルを用意してくれています。
今回はこの中の 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が表示されます。
右上の Materialize all
ボタンをクリックしてアセットのマテリアライズを実行できます。
実際に実行してみるとRunsのタブから実行中のジョブを確認できます。
ここまで確認できたらwebserverはCtrl+Cで終了しておきましょう。
Dockerコンテナ上で動かす
引き続きこれをそのままDockerコンテナ上で動かすところまでやっていきます。
先ほどまでDuckDBを使っていましたが、ここからはPostgreSQLに乗り換えます。
まずは今から作るアーキテクチャの公式の概要図を載せておきます。
こちらの図はKubernetes上で動かす場合のものですが、Dockerコンテナ上で動かす場合もほぼ同じです。
必要となるコンテナは以下の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のフォルダを含める必要があります。
@@ -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
@@ -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
を修正して接続情報を設定する必要があります。
@@ -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
を修正します。
@@ -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
ボタンをクリックするとジョブの実行ができます。
このように全てのアセットが緑色になると正常にマテリアライズされたことになります。
結果は 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ベースの構成に作り変えたものを紹介したいと思います。
それではまた次回の記事でお会いしましょう!