Dagsterとdbt CoreをECS on Fargateで構築する

Dagsterとdbt CoreをECS on Fargateで構築する

Clock Icon2025.06.29

こんにちは、データ事業本部のキタガワです。
今回はDagsterとdbt Coreの構成をECS on Fargateの構成で動かすサンプルを作っていきたいと思います。

前回Dockerコンテナ上で構築した記事の続きとして、ECS on Fargateの構成で動かすサンプルを作っていきます。
続きとは言っても、この記事を読むだけでECS on FargateでDagsterとdbtを動かすことができるように書いていくつもりです。

(参考)
https://dev.classmethod.jp/articles/dagster-dbt-docker-setup/

この記事でもdbtのサンプルプロジェクトとして jaffle_shop を使います。
また前回同様に実装は公式リポジトリ https://github.com/dagster-io/dagster を参考に進めていきます。

https://github.com/dagster-io/dagster/tree/master/examples/deploy_ecs にECSを使った具体的な例があるんですが、この手順の中で使用されている docker context create ecs2023年11月に廃止 されています。
したがって現在はECS周りのリソースも併せて作成する必要がありました。
そこについてもこの記事で扱っていきます。

今回作りたい構成はこんな感じです。

alt text

ポイントとしては

  • コンテナの構成は前回と同じ
    • Dagster Webserver・Dagster Daemon・Code Server
    • それぞれのビルド済みイメージはECRに登録する
  • 実行履歴やログの格納にはRDS(PostgreSQL)を使用
  • WebserverにはALB経由でインターネットからアクセス
  • dbtがビルドするモデルはSnowflakeに保存
  • 各種認証情報はSecrets Managerに保存

です!

Snowflakeは事前に設定済みのものを使用します。
もしアカウントのセットアップが必要な場合は以下ページからトライアルアカウントが作成できます。

https://signup.snowflake.com/?owner=classmethodlead&plan=enterprise&cloud=aws&region=ap-northeast-1&utm_source=dev.classmethod.jp&utm_medium=banner&utm_content=snowflake&utm_campaign=single_article_foot_ads

またdbtとSnowflakeの接続にはキーペア認証を使用します。
キーペア認証については以下ページを参考にしてください。

https://dev.classmethod.jp/articles/dbt-cloud-snowflake-connection-service-user-key-pair/

また前提としてAWS CLIとTerraform、Dockerは使用可能な状態にしておいてください。

プロジェクトの作成

まずはプロジェクトを作成します。
dbtのプロジェクトをDagsterのアセットとして取り込むところまでは前回行ったことと重複するので、手順だけ簡単に記載します。
uv を使用しているところは適宜お使いのツールに読み替えてください。

# プロジェクトの作成
uv init dagster-dbt-ecs-sample --bare --python 3.12
cd dagster-dbt-ecs-sample

# gitでバージョン管理したいので初期化
git init
git add .
git commit -m "Initial commit"

# dbtのプロジェクトをクローン(ここではgitのサブツリーとして取り込む)
git subtree add --prefix=jaffle_shop https://github.com/dbt-labs/jaffle_shop_duckdb.git duckdb --squash

# 仮想環境にライブラリを追加
uv add dagster-dbt dagster-webserver

# Dagsterのプロジェクトを作成
uv run dagster-dbt project scaffold --project-name dagster_project --dbt-project-dir jaffle_shop

dagster dev でローカルのDagster Webserverが起動できたら準備OKです。

次に必要なファイルを作成します。

dbtの設定

ここでは jaffle_shop/profiles.yml という設定ファイルを編集します。
gitからクローンしてきた段階ではDuckDBを使用する設定になっているので、これをSnowflake用のものに変更します。

jaffle_shop/profiles.yml
jaffle_shop:
  target: dev
  outputs:
    dev:
      type: snowflake
      account: "{{ env_var('DBT_ENV_SECRET_SNOWFLAKE_ACCOUNT', 'dummy') }}"
      user: "{{ env_var('DBT_ENV_SECRET_SNOWFLAKE_USER', 'dummy') }}"
      private_key: "{{ env_var('DBT_ENV_SECRET_SNOWFLAKE_PRIVATE_KEY', 'dummy') }}"
      private_key_passphrase: "{{ env_var('DBT_ENV_SECRET_SNOWFLAKE_PRIVATE_KEY_PASSPHRASE', 'dummy') }}"
      role: SYSADMIN
      warehouse: X_SMALL_WH
      database: KITAGAWA_TEST_DB
      schema: DAGSTER_DBT_SAMPLE
      threads: 1
      client_session_keep_alive: False
      query_tag: cm_kitagawa_dagster

ここでは DBT_ENV_SECRET_SNOWFLAKE_ACCOUNT などの環境変数を使用しています。
これらは後ほどSecrets Managerに保存します。
roledatabase は事前に作成済みのものを使用します。
こういった値もSecrets ManagerやSSMのパラメータストアなどで管理してもいいですが、ここではハードコードしています。
また env_var() にデフォルト値を設定することで、環境変数を設定せずとも dbt parse を実行できるようにしています。
これは次の項目で dagster-dbt project prepare-and-package を実行する際に必要になります。

Dagsterの設定

dbtのパッケージの作成

dagster-dbt project prepare-and-package コマンドを実行して、dbtのパッケージを作成します。
--fileproject.py のパスを指定してください。

uv run dagster-dbt project prepare-and-package --file dagster_project/dagster_project/project.py

これで dagster_project/dbt-project にパッケージが作成されます。
このパッケージはdbtプロジェクトを dbt deps dbt parse で最新化した上で丸っとコピーしてきたものです。
今回はこれをコンテナにコピーして使用します。

次に dagster_project/dagster_project/project.py を編集します。
環境変数 DAGSTER_ENV を使用して、AWS環境ではパッケージ化されたプロジェクトを使用、開発環境では元のプロジェクトを使用するようにします。
こうすることでDagsterとdbt双方の開発を分離して行えるようになることを期待してこのような実装にしています。

dagster_project/dagster_project/project.py
import os
from pathlib import Path

from dagster_dbt import DbtProject

# AWS環境ではパッケージ化されたプロジェクトを使用、開発環境では元のプロジェクトを使用
is_aws = os.getenv("DAGSTER_ENV") == "AWS"
print(f"is_aws: {is_aws}")

if is_aws:
    # AWS環境: packaged_project_dirをproject_dirとして使用
    project_dir = Path(__file__).joinpath("..", "..", "dbt-project").resolve()
    packaged_project_dir = project_dir
else:
    # ローカル環境: ローカルではjaffle_shopを使用
    project_dir = Path(__file__).joinpath("..", "..", "..", "jaffle_shop").resolve()
    packaged_project_dir = Path(__file__).joinpath("..", "..", "dbt-project").resolve()

jaffle_shop_project = DbtProject(
    project_dir=project_dir,
    packaged_project_dir=packaged_project_dir,
)
jaffle_shop_project.prepare_if_dev()

必要なファイルの作成

以下のファイルを作成していきます。

  • dagster_project/docker-compose.yml
  • dagster_project/Dockerfile_dagster
  • dagster_project/Dockerfile_user_code
  • dagster_project/dagster.yaml
  • dagster_project/workspace.yaml

docker-compose.yml

各コンテナをビルドするのに使います。
platform はECS上で動かすため、linux/amd64 を指定します。
今回はローカルで docker compose up することはないので、イメージのビルドに必要な最低限の設定のみ記述しています。

docker-compose.yml
services:
  dagster_ecs_core:
    platform: linux/amd64
    build:
      context: .
      dockerfile: ./Dockerfile_dagster

  dagster_ecs_user_code:
    platform: linux/amd64
    build:
      context: .
      dockerfile: ./Dockerfile_user_code

Dockerfile_dagster

Dagster WebserverとDagster Daemonを実行するためのイメージです。
必要なライブラリのインストールと、Dagsterの設定ファイルをコピーしています。

Dockerfile_dagster
# Dagster libraries to run both dagster-webserver and the dagster-daemon. Does not
# need to have access to any pipeline code.
FROM python:3.12-slim

RUN pip install \
    dagster \
    dagster-graphql \
    dagster-webserver \
    dagster-postgres \
    dagster-aws

# Set $DAGSTER_HOME and copy dagster instance and workspace YAML there
ENV DAGSTER_HOME=/opt/dagster/dagster_home/

RUN mkdir -p $DAGSTER_HOME

COPY dagster.yaml workspace.yaml $DAGSTER_HOME

WORKDIR $DAGSTER_HOME

Dockerfile_user_code

ユーザーコードを実行するためのイメージです。
Dagsterとdbt両方のプロジェクトをコピーする必要があります。

前回の記事では dagster api grpc を使用していましたが、今回は dagster code-server start を使用します。
こちらを使用することでDagster全体のシステムを再起動することなく、ユーザーコードの変更を反映できます。

Dockerfile_user_code
FROM python:3.12-slim

# Install system dependencies

RUN apt-get update && apt-get upgrade -yqq
RUN apt-get install git -y

# 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

RUN pip install \
    dagster \
    dagster-postgres \
    dagster-docker \
    dagster-dbt \
    dbt-snowflake

# Add repository code

WORKDIR /opt/dagster/app

COPY dagster_project/ ./dagster_project/
COPY dbt-project/ ./dbt-project/

# Set environment variable
ENV DAGSTER_ENV=AWS

# Run dagster gRPC server on port 4000

EXPOSE 4000

CMD ["dagster", "code-server", "start", "-h", "0.0.0.0", "-p", "4000", "--module-name", "dagster_project.definitions"]

dagster.yaml

Dagsterの設定ファイルです。
いろいろな設定があるので、詳しくは公式ドキュメントを参照してください。

https://docs.dagster.io/deployment/oss/dagster-yaml

ここでは examples/deploy_ecs/dagster.yaml を元に、少し修正したものを使います。

dagster.yaml
scheduler:
  module: dagster.core.scheduler
  class: DagsterDaemonScheduler

run_coordinator:
  module: dagster.core.run_coordinator
  class: QueuedRunCoordinator

run_launcher:
  module: dagster_aws.ecs
  class: EcsRunLauncher

run_storage:
  module: dagster_postgres.run_storage
  class: PostgresRunStorage
  config:
    postgres_db:
      hostname:
        env: DAGSTER_POSTGRES_HOST
      username:
        env: DAGSTER_POSTGRES_USER
      password:
        env: DAGSTER_POSTGRES_PASSWORD
      db_name:
        env: DAGSTER_POSTGRES_DB
      port: 5432

schedule_storage:
  module: dagster_postgres.schedule_storage
  class: PostgresScheduleStorage
  config:
    postgres_db:
      hostname:
        env: DAGSTER_POSTGRES_HOST
      username:
        env: DAGSTER_POSTGRES_USER
      password:
        env: DAGSTER_POSTGRES_PASSWORD
      db_name:
        env: DAGSTER_POSTGRES_DB
      port: 5432

event_log_storage:
  module: dagster_postgres.event_log
  class: PostgresEventLogStorage
  config:
    postgres_db:
      hostname:
        env: DAGSTER_POSTGRES_HOST
      username:
        env: DAGSTER_POSTGRES_USER
      password:
        env: DAGSTER_POSTGRES_PASSWORD
      db_name:
        env: DAGSTER_POSTGRES_DB
      port: 5432

telemetry:
  enabled: false

workspace.yaml

コードロケーション用の設定ファイルです。
Dagsterにコードサーバーの読み込み方法を教えてあげるためのファイルです。

https://docs.dagster.io/deployment/code-locations/workspace-yaml

ECSでのコンテナ間通信には サービス検出 を使用します。
hostにはサービス名を指定します。

workspace.yaml
load_from:
  - grpc_server:
      host: user-code.cm-kitagawa-dagster-ecs.internal
      port: 4000
      location_name: "dagster-ecs-user-code"

hostは後ほど作成するECSサービスの「サービス検出」から確認することもできます。
もしWebserverやDaemonがコードサーバーを認識できていなかったらここを確認して設定し直すことをお勧めします。

alt text

AWSリソースの作成

あとはAWSリソースの作成が必要です。
リソース作成にはTerraformを使用します。
ECRなどの事前作成が必要なリソースを先に作成し、必要な設定を行った後に残りのリソースを作成していきます。

Terraformは事前に作成が必要なリソース(foundation)とアプリケーション用のリソース(application)に分けてテンプレートを作っています。
それぞれの構成は以下の通りです。

  • foundation/ (基盤リソース)

    • VPC・ネットワーク: VPC、サブネット、IGW、NAT Gateway、ルートテーブル
    • セキュリティグループ: 全てのSG定義
    • RDS: PostgreSQLデータベース
    • ECR: Dockerレジストリ
    • IAM: 全てのロール・ポリシー
    • Secrets Manager: DB認証情報、Snowflake認証情報
  • application/ (アプリケーションリソース)

    • ALB: ロードバランサー、ターゲットグループ、リスナー
    • ECS: クラスター、タスク定義、サービス
    • CloudWatch: ログ群
    • Service Discovery: Cloud Map設定

代表的なリソースを抜粋して説明を行いますが、ソースコードについてはGitHubを参照してください。

https://github.com/cm-kitagawa-zempei/dagster-dbt-ecs-sample

またリソースの設定はあくまで検証用のものであり、本番運用にはセキュリティや可用性を考慮し、適切に設定してください。

terraform/foundation/ - 基盤リソース

まず基盤となるリソースから見ていきます。

ネットワーク構成

terraform/foundation/main.tf(抜粋)
# VPC
resource "aws_vpc" "main" {
    cidr_block = var.vpc_cidr
    enable_dns_support = true
    enable_dns_hostnames = true
}

# Public Subnets
resource "aws_subnet" "public" {
    count = length(var.public_subnet_cidrs)
    vpc_id = aws_vpc.main.id
    cidr_block = var.public_subnet_cidrs[count.index]
    map_public_ip_on_launch = true
    availability_zone = data.aws_availability_zones.available.names[count.index]
}

# Private Subnets
resource "aws_subnet" "private" {
    count = length(var.private_subnet_cidrs)
    vpc_id = aws_vpc.main.id
    cidr_block = var.private_subnet_cidrs[count.index]
    availability_zone = data.aws_availability_zones.available.names[count.index]
}

VPCは典型的な2AZ構成で、パブリックサブネットとプライベートサブネットを2つずつ作成しています。
パブリックサブネットにはALBを配置し、プライベートサブネットにはECSタスクとRDSを配置します。

セキュリティグループ

terraform/foundation/main.tf(抜粋)
# ALB用セキュリティグループ
resource "aws_security_group" "alb" {
    name = "${var.prefix}-dagster-ecs-alb-sg"
    description = "Allow HTTP/HTTPS traffic to ALB"
    vpc_id = aws_vpc.main.id

    ingress {
        from_port = 80
        to_port = 80
        protocol = "tcp"
        prefix_list_ids = var.prefix_list_ids
    }

    egress {
        from_port = 0
        to_port = 0
        protocol = "-1"
        cidr_blocks = ["0.0.0.0/0"]
    }
}

# Webserver用セキュリティグループ
resource "aws_security_group" "web" {
    name = "${var.prefix}-dagster-ecs-web-sg"
    description = "Allow HTTP/HTTPS traffic from ALB"
    vpc_id = aws_vpc.main.id

    ingress {
        from_port = 3000
        to_port = 3000
        protocol = "tcp"
        security_groups = [aws_security_group.alb.id]
    }

    egress {
        from_port = 0
        to_port = 0
        protocol = "-1"
        cidr_blocks = ["0.0.0.0/0"]
    }
}

セキュリティグループは役割別に分けて作成します。
ALBは特定のIPアドレスからのアクセスを許可し、WebserverはALBからのアクセスのみを許可するように設定しています。
prefix_list_idsは必要な場合 terraform/foundation/variables.tfvars で指定してください。

RDS

terraform/foundation/main.tf(抜粋)
resource "aws_db_instance" "main" {
    identifier = "${var.prefix}-dagster-ecs-db"
    db_name = var.dagster_postgres_db
    engine = "postgres"
    engine_version = "17.2"
    instance_class = "db.m5.large"
    allocated_storage = 20
    username = var.dagster_postgres_user
    password = var.dagster_postgres_password
    port = 5432
    db_subnet_group_name = aws_db_subnet_group.main.name
    vpc_security_group_ids = [aws_security_group.rds.id]
    skip_final_snapshot = true
    publicly_accessible = false
    multi_az = false
    storage_encrypted = true
    deletion_protection = false
    tags = {
        "cm-daily-stop" = "true"
    }
}

RDSはPostgreSQL 17.2を使用しています。
検証用なので skip_final_snapshot = true deletion_protection = false としていますが、本番運用では適切に設定してください。
またこちらの検証環境用に cm-daily-stop タグを付けることで、スケジュールによる自動停止の対象にしています。

IAMロール

ECSタスクには2つのロールが必要です。

terraform/foundation/main.tf(抜粋)
# タスクロール(実行時に使用)
resource "aws_iam_role" "task" {
    name_prefix = "${var.prefix}-dagster-ecs-task-"
    description = "Role for Dagster ECS tasks"

    assume_role_policy = jsonencode({
        Version = "2012-10-17",
        Statement = [
            {
                Effect = "Allow",
                Principal = {Service = "ecs-tasks.amazonaws.com"},
                Action = "sts:AssumeRole"
            }
        ]
    })
}

# 実行ロール(コンテナ起動時に使用)
resource "aws_iam_role" "execution" {
    name_prefix = "${var.prefix}-dagster-ecs-execution-"
    description = "Role for ECS task execution"

    assume_role_policy = jsonencode({
        Version = "2012-10-17",
        Statement = [
            {
                Effect = "Allow",
                Principal = {
                    Service = "ecs-tasks.amazonaws.com"
                },
                Action = "sts:AssumeRole"
            }
        ]
    })
}

タスクロールはDagsterのEcsRunLauncherがジョブ実行時に新しいタスクを起動するために必要な権限を持ちます。
実行ロールはECRからのイメージ取得やSecrets Managerからの値取得に使用されます。

Secrets Manager

terraform/foundation/main.tf(抜粋)
resource "aws_secretsmanager_secret" "dbt_env_secret_snowflake" {
    name = "${var.prefix}-dbt_env_secret_snowflake"
}

resource "aws_secretsmanager_secret_version" "dbt_env_secret_snowflake" {
    secret_id = aws_secretsmanager_secret.dbt_env_secret_snowflake.id
    secret_string = jsonencode({
        account = var.dbt_env_secret_snowflake_account
        user = var.dbt_env_secret_snowflake_user
        private_key = var.dbt_env_secret_snowflake_private_key
        private_key_passphrase = var.dbt_env_secret_snowflake_private_key_passphrase
    })
}

Snowflakeの認証情報とPostgreSQLの認証情報をそれぞれSecrets Managerで管理します。
これらの値はECSタスクの環境変数として自動的に注入されます。

terraform/application/ - アプリケーションリソース

続いてアプリケーション側のリソースです。

データソース連携

terraform/application/main.tf(抜粋)
data "terraform_remote_state" "foundation" {
    backend = "local"
    config = {
        path = "../foundation/terraform.tfstate"
    }
}

applicationディレクトリではfoundationで作成したリソースの情報を terraform_remote_state で参照しています。

ALB

terraform/application/main.tf(抜粋)
resource "aws_lb" "main" {
    name = "${var.prefix}-dagster-ecs-alb"
    internal = false
    load_balancer_type = "application"
    security_groups = [data.terraform_remote_state.foundation.outputs.alb_security_group_id]
    subnets = data.terraform_remote_state.foundation.outputs.public_subnet_ids
}

resource "aws_lb_target_group" "web" {
    name = "${var.prefix}-dagster-ecs-alb-tg"
    port = 3000
    protocol = "HTTP"
    vpc_id = data.terraform_remote_state.foundation.outputs.vpc_id
    target_type = "ip"
    health_check {
        path = "/"
        protocol = "HTTP"
        matcher = "200-399"
        interval = 30
        timeout = 5
        healthy_threshold = 2
        unhealthy_threshold = 2
    }
}

ALBはDagster Webserverへの外部アクセスを提供します。
ターゲットタイプは ip を指定し、Fargateタスクと連携します。

ECSタスク定義

Dagster WebserverとDaemonのタスク定義では、環境変数とシークレットの設定が重要です。

terraform/application/main.tf(抜粋)
container_definitions = jsonencode([
    {
        name = "${var.prefix}-dagster-ecs-web"
        image = "${data.terraform_remote_state.foundation.outputs.dagster_ecr_repository_url}:latest"
        entryPoint = ["dagster-webserver", "-h", "0.0.0.0", "-p", "3000"]
        
        environment = [
            {
                name = "DAGSTER_POSTGRES_HOST"
                value = data.terraform_remote_state.foundation.outputs.rds_endpoint
            }
        ]
        secrets = [
            {
                name = "DAGSTER_POSTGRES_DB"
                valueFrom = "${data.terraform_remote_state.foundation.outputs.dagster_postgres_secret_arn}:db_name::"
            },
            {
                name = "DAGSTER_POSTGRES_USER"
                valueFrom = "${data.terraform_remote_state.foundation.outputs.dagster_postgres_secret_arn}:username::"
            },
            {
                name = "DAGSTER_POSTGRES_PASSWORD"
                valueFrom = "${data.terraform_remote_state.foundation.outputs.dagster_postgres_secret_arn}:password::"
            }
        ]
    }
])

PostgreSQLの接続情報は、ホスト名は環境変数で、ユーザー名・パスワード・データベース名はSecrets Managerから自動取得するように設定しています。

Service Discovery

terraform/application/main.tf(抜粋)
resource "aws_service_discovery_private_dns_namespace" "main" {
    name = "${var.prefix}-dagster-ecs.internal"
    description = "Dagster Cloud Map Namespace"
    vpc = data.terraform_remote_state.foundation.outputs.vpc_id
}

resource "aws_service_discovery_service" "user_code" {
    name = "user-code"
    dns_config {
        namespace_id = aws_service_discovery_private_dns_namespace.main.id
        dns_records {
            type = "A"
            ttl = 10
        }
        routing_policy = "MULTIVALUE"
    }
}

ECSサービス間の通信にはAWS Cloud Mapによるサービスディスカバリを使用します。
これにより、WebserverとDaemonがUser Codeサーバーに user-code.{prefix}-dagster-ecs.internal:4000 でアクセスできるようになります。

実行手順

Terraformの実行は必ず foundation → application の順で行います。

1. AWS認証設定

export AWS_PROFILE=your-profile-name

2. 変数ファイルの準備

# foundation用変数ファイル作成
cp terraform/foundation/terraform.tfvars.example terraform/foundation/terraform.tfvars
# 必要な値を編集

# application用変数ファイル作成
cp terraform/application/terraform.tfvars.example terraform/application/terraform.tfvars
# 必要な値を編集

foundation/で必要な変数:

  • prefix: リソース名プレフィックス
  • dagster_postgres_db: PostgreSQLデータベース名
  • dagster_postgres_user: PostgreSQLユーザー名
  • dagster_postgres_password: PostgreSQLパスワード
  • dbt_env_secret_snowflake_account: Snowflakeアカウント
  • dbt_env_secret_snowflake_user: Snowflakeサービスユーザー
  • dbt_env_secret_snowflake_private_key: 秘密鍵
  • dbt_env_secret_snowflake_private_key_passphrase: 秘密鍵パスフレーズ

application/で必要な変数:

  • prefix: リソース名プレフィックス

3. 基盤リソースの作成

Terraformのfoundationディレクトリに移動して以下コマンドを実行してください。

cd terraform/foundation
terraform init
terraform plan
terraform apply

4. コンテナイメージのビルド・プッシュ

Dagsterの設定の項で作成したDockerfileをビルドしてECRにプッシュします。
基盤リソースの作成を行うとoutputからECRのリポジトリURLが取得できるので、それを参考にして以下の手順を修正してください。
dagster_ecr_repository_urluser_code_ecr_repository_url が該当します。

Dockerfileのあるdagster_projectディレクトリに移動して以下コマンドを実行してください。

cd ../../dagster_project

# コンテナイメージのビルド
docker compose build

# ECRのURLを環境変数に設定
# <AWS_ACCOUNT_ID> と <AWS_REGION> は適宜変更してください。
export ECR_REGISTRY="<AWS_ACCOUNT_ID>.dkr.ecr.<AWS_REGION>.amazonaws.com"

# ECRにログイン
aws ecr get-login-password | docker login --username AWS --password-stdin ${ECR_REGISTRY}

# Dagsterのコンテナイメージのタグ付けとプッシュ
docker tag dagster_project-dagster_ecs_core:latest ${ECR_REGISTRY}/cm-kitagawa-dagster_ecs_core:latest
docker push ${ECR_REGISTRY}/cm-kitagawa-dagster_ecs_core:latest

# ユーザーコードのコンテナイメージのタグ付けとプッシュ
docker tag dagster_project-dagster_ecs_user_code:latest ${ECR_REGISTRY}/cm-kitagawa-dagster_ecs_user_code:latest
docker push ${ECR_REGISTRY}/cm-kitagawa-dagster_ecs_user_code:latest

5. アプリケーションリソースの作成

Terraformのapplicationディレクトリに移動して以下コマンドを実行してください。

cd ../terraform/application
terraform init
terraform plan
terraform apply

DagsterのWebserverにアクセス

上記までの操作が完了したらECSクラスターにサービスが3つ起動しているはずです。
添付の画像のように3つとも完了表示になっていると成功です。

alt text

それではDagsterのUIを開いてみましょう。
Terraformのapplicationディレクトリで以下コマンドを実行してください。

terraform output -raw dagster_url

これでDagsterのURLが取得できるので、それをブラウザで開くとDagsterのWebserverにアクセスできます。
次のような画面が表示されます。

alt text

これはDagsterのアセットの一覧が表示されている画面です。
dbtで定義したモデルが表示されていることがわかります。

試しに右上①の Materialize All ボタンを押して、そのあと表示される②の View ボタンを押してみましょう。

alt text

この画面では実行したジョブの詳細を確認することができます。
すべてのアセットのマテリアライズが完了すると画像のように緑色になり、成功したことがわかります。

また先ほどのアセットの画面に戻ってみましょう。
左上の Assets タブを押し、右側の View lineage を押すとアセットのリネージ画面に戻れます。

alt text

alt text

この画面でもすべてのアセットが正常にマテリアライズされていることがわかりますね。
またdbtで定義したテストも Asset checks という形で表示され、それらが通っていることも確認できます。

Snowflake側も見てみましょう。
指定したDBをみるとスキーマとその下にテーブルやビューが作成されていることがわかります。
またテーブルの更新履歴からも直前の実行によりテーブルにデータが書き込まれていることがわかります。

alt text

まとめ

今回はDagsterをECS on Fargateの構成で動かす方法を紹介しました。
dbtプロジェクトをDagsterのアセットとして管理し、ECSで実際に動かすことで、スケーラブルなデータパイプラインが構築できました。
前回のDocker構築記事と合わせて読んでもらえれば、AWSにデプロイするまでの一連の流れが掴めるはずです。
ぜひ試してみてください。

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

Share this article

facebook logohatena logotwitter logo

© Classmethod, Inc. All rights reserved.