Amazon MWAA + Step Functions (+ Snowflake × dbt) による大規模データパイプライン構築事例紹介


Loading...


KADOKAWA デジタル戦略局 グループデータマネジメント部(出向)の中野 (takamoto) です。 足掛け2年半の ADR 活用事例紹介 〜 ADR から始める設計ドキュメント改善 - KADOKAWA Connected Engineering Blog などの過去記事から所属は変化していますが、変わらずデータプラットフォーム上のデータパイプラインの開発・運用を主に担当しています。

私の所属しているチームでは データプラットフォーム統合プロジェクトの紹介 - KADOKAWA Connected Engineering Blog で紹介している Snowflake 環境上に構築されたデータウェアハウスを開発・保守しています。これまでこのデータウェアハウス向けに、 self-hosted Airflow on Kubernetes (+ 主に AWS Glue) の構成で 400 を超えるデータ加工ジョブを管理していました。ですが、少し前にこの構成を一新して Amazon MWAA + Step Functions (+ 主に dbt) という構成に移行しました。現在、 Snowflake 以外のデータプラットフォームからのデータ移行などもあり、新構成で管理しているデータ加工ジョブの総数は 600 程度と移行前の1.5倍に増えていますが、問題なく稼働しています。

MWAA と Step Functions を両方採用したデータパイプラインの事例はあまり見られないかと思いますので、本記事では何故そのような構成を取る判断を行ったのかについて触れつつ、構成を紹介していこうと思います。

移行前のデータパイプライン

まず、移行前の構成にはどのような特徴があり、またどのような問題が発生していたのかについて触れていきます。

全体像

移行前のインフラ構成全体像

移行前の構成では、上の図のようにオンプレ環境上の Kubernetes クラスタで動作する Airflow サーバから、 KubernetesPodOperator を利用して Pod を起動する構成を取っていました。この Pod は、以下のようなデータ加工ワークフローを構成する小さなステップに対応する処理(以降、本記事では Task と呼びます)毎に、作成と停止を繰り返す構成となっていました。

  • Scala で実装された Glue ジョブの起動
  • 内製のデータヘルス管理 API (REST API) へのアクセス
  • Snowflake クエリの実行

なお、 Task ごとに Pod を起動してはいましたが、 Pod に対応するコンテナイメージやコードベースは Task ごとに分離されておらず、ソースコードは DAG ファイル1と同じ Python プロジェクトにひとまとめにして管理していました2

一方で、 Glue ジョブは歴史的経緯から Python ではなく Scala で実装されており、異なるコードベース上で実装が管理されていました。また、 Snowflake 移行当時に発生していたパフォーマンスと費用面の問題3から、 Glue ジョブによるデータ加工処理の結果は JDBC 経由では Snowflake には書き込まず、以下の流れで取り込む構成となっていました。

  1. Glue ジョブによるデータ加工処理の結果を一時ファイルとして S3 に出力
  2. Glue ジョブ外で COPY INTO などのクエリを実行することによって、一時ファイルを Snowflake に取り込む。

移行前のワークフロー全体像

上の図は、本構成で管理していた DAG の全体像です。この図のように、管理していた DAG は大きく分けると以下の2種類存在していました。

  • 各データ加工ジョブ間の依存関係を表す DAG
    • 以降、本記事では Global Workflow と呼びます。
    • 毎日0時に定期実行されます。
  • 個別のデータ加工ジョブを表す DAG
    • 以降、本記事では Local Workflow と呼びます。
    • 定期実行はされず、  TriggerDagRunOperator を利用して Global Workflow から起動されます。

特徴

ここまで2つの図を用いて構成について紹介してきましたが、図からは見えない特筆すべき特徴としては、以下の項目があります。

  • デプロイ=リリース

    本構成では、ワークフローのデプロイがそのままワークフローのリリースを意味する構成になっていました。言い換えると、 Airflow への DAG ファイルのデプロイがそのままリリース作業となっていました。また、そのデプロイと同じタイミングで、必要に応じて Glue ジョブのような Airflow 以外の構成要素のデプロイ(=リリース)も行うデプロイフローとなっていました。

    Airflow 自体には(他の多くのワークフローエンジンと同様)ワークフローのデプロイとリリースを分離できる仕組みは存在しないため、素朴にデプロイフローを構築するとこのような構成になるのではないかと思います。

  • 似たデータ加工処理が多い

    本構成で扱うデータ加工処理は、 Raw Layer から Standardized layer4 へのデータ加工処理(以降、この記事では 標準化処理 と呼びます)が全体の多くを占めています。また、この標準化処理の多くは処理が似通っています。

    そのような背景から、本構成では標準化処理を行う Glue ジョブを共通化することで、 Glue ジョブ起動時に与える引数を変えるだけで(Glue ジョブを新規実装せずに)新しいデータに対応した標準化処理を実現できるようにしていました。

  • 多くの Snowflake テーブルが日付でパーティショニングされている

    元々 Hadoop + Hive 構成だったテーブルを Snowflake に移行してきた歴史的経緯もあり、日付ベースでパーティショニングされているテーブルが全体の多くを占めており、テーブルの更新もこのパーティションの粒度で行われています。この性質は、 DAG Run によって論理的な実行日付 (Logical Date) ごとに実行状況を管理できる Airflow の特性とマッチしていました。

    dt というデータに対応する日付を表すカラムでパーティショニングされるテーブル と、テーブル に対応する Local Workflow の例です。 Local Workflow の Logical Date が 2024-12-01 の DAG Run では、 dt カラムの値が ’20241201’ のレコードを差し替えるような処理を行うことが示されています。

  • データ間の依存関係を日付ベースのパーティション粒度で管理

    前述のようにパーティションの粒度でデータ更新を行っている関係で、データ間の依存関係もこのパーティションの粒度で(内製のデータヘルス管理 API により)管理を行っています。

    これにより、「テーブル X のパーティション dt=’20241202’ に対応するデータを生成するためには、テーブル Y のパーティション dt='20241201' が利用できる状態である必要がある」といった日を跨いだ条件も正しく判定できる状態になっており、「データ加工処理の入力データが利用できる状態になるまで、加工処理の実行を待機する」といった処理を行っていました。

  • 少数だが Reverse ETL 処理も存在する

    Local Workflow のほとんどは Snowflake 上のテーブルを更新する処理に対応するものです。ですが、(簡略化のために前述の全体像では記載を省略していましたが)一部 Snowflake 外部にデータを送信する処理も存在しています。

  • 複数システムを跨いでデータが利活用されている

    1つの事業に多くのシステムが内包されており、かつ、それらのシステムを跨いでデータが利活用されている関係で、データの依存関係グラフの連結成分が巨大になっています。そのため、 Global Workflow をシステム単位などで分割はせず、中央管理的な Global Workflow を1つのみ用意していました。

    全体像の節で、本構成で管理している DAG は Global Workflow と Local Workflow の二段構成になっていることを紹介しましたが、この構成は、この中央管理的な Global Workflow が複雑になりすぎないようにするためのものでした。

  • DAG は設定ファイルを元に自動生成している

    Local Workflow の多くは 入力データのヘルスチェック → Glue 実行 → Snowflake への取り込み → 出力データのヘルス更新 という処理で構成されており似通っていた為、以下のようなコードによって Local Workflow を Airflow 環境上で動的に生成する構成を取っていました5。これにより、データ加工ジョブに対応する設定ファイルを記述するだけで、 Local Workflow を追加できる状態が実現されていました。

    # データ加工ジョブに対応する設定ファイルを元に Local Workflow を自動生成
    for setting in local_workflow_settings:
        local_workflow: DAG = generate_local_workflow(setting)
        globals()[local_workflow.dag_id] = local_workflow
    
    ---
    # あるデータ加工ジョブに対応する設定ファイルの例
    # (実際に運用していたフォーマットとは異なります)
    name: local-workflow-1
    glue_job_name: standardization
    glue_job_args: [...]
    upstreams:  # 入力データ
      # 同日のパーティションに依存
      - name: local-workflow-2
        partition_offsets: [0]
      # 前日のパーティションに依存
      - name: local-workflow-3
        partition_offsets: [-1]
    

    また、 Global Workflow も Local Workflow 間の依存関係を表現するだけなので、データ加工ジョブに対応する設定ファイル中の upstreams を元に自動生成する構成を取っていました。

問題点

上記の構成はそれなりにスケールして数年間の運用に耐えていましたが、運用を続ける中で以下のような問題があることがわかってきました。

  • Airflow on Kubernetes 自体の運用がきつい

    本構成は、構築当時はオンプレ環境上に存在する Hadoop クラスタを対象としていたため、オンプレ環境上にセルフホストする形で構築されました。ですが、他の事例紹介記事でもよく言及されるように Airflow 環境自体の運用コストは重く、運用上のペインポイントとなっていました。

  • チームのスケールアウトが難しい

    特徴の節で言及したように、扱っているデータの依存関係グラフの連結成分は巨大です。ですが、分割可能な境界面が全くないわけではありません。例えば、異なる事業間をまたいだデータ活用は相対的に少ないので、そこを境界面とすることが考えられます。今後も扱う領域・データは増えていくことが想定されることから、そのような境界面で Global Workflow (とそれに合わせてチーム)を適度に分割していくことで、チームサイズが大きくなりすぎないように努める必要がありました6

    ですが、Airflow は Python コードでワークフローを記述できる柔軟性と引き換えに、(少なくとも2024年現在は)厳密なマルチテナント構成を実現することができません7。要は、複数チームで1つの Airflow 環境を共用すると、誤って別チームが管理している DAG に影響を及ぼしてしまう可能性があります。このリスクを許容するのは難しかった一方で、チームごとに Airflow 環境を分けるのは、上述のように Airflow 環境自体の運用が重いため、選択肢としてあまり現実的ではありませんでした。

  • リリース作業が重い

    デプロイ=リリース は素朴なデプロイ戦略ですが、デプロイ対象となる構成要素が増えるにつれてリリース作業が重くなり、問題発生時の切り戻しに時間がかかるといった問題が出てきます。実際、 Glue ジョブ用の JAR ファイルのビルドに時間がかかったり、同時にデプロイ作業を行う必要のある GitHub リポジトリが複数に増えてデプロイ作業が複雑化するなど、段々と問題が顕在化してきていました。

  • Glue ジョブの開発・保守コストが無駄に重い

    現在行っている標準化処理は、 Hadoop クラスタ時代ならともかく Snowflake 環境であれば SQL だけで十分に実現可能な処理で、 Apache Spark on Scala の学習コストが無駄にのしかかっている状態となっていました。また、ドメインエキスパートとのコミュニケーションは Snowflake の SQL で行われるにもかかわらず、そこから Apache Spark に翻訳するといった無駄も発生していました。

    また、特徴の節で述べたように標準化処理を行う Glue ジョブは共通化していましたが、(下記の Local Workflow と同様に)たまに生まれる処理のバリエーションに対応していくことで、その実装が徐々に複雑化してきていました。

  • データ加工処理の動作確認が行いづらい

    全体像の節で言及していたように、パフォーマンスや費用面の問題から Glue ジョブだけではデータ加工処理が完結しない構成となっています。そのため、日付ベースのパーティション粒度でテーブル更新するといったテーブル更新処理が、 Task 側に漏れ出る形となってしまっていました。全体像の節で述べたように、 Task の処理は DAG ファイルと同じ Python プロジェクトで管理されていた為、 加工処理の動作確認をするには2つのコードベースを組み合わせる必要があり、その結果、開発メンバーの個人開発環境上での動作確認が行いづらくなっていました。

  • Local Workflow + Task の修正が大変

    Local Workflow の多くは似通った処理ではありましたが、完全には一致せず微妙に処理が異なる複数のバリエーションが発生していました。このバリエーションに対応していくことで、設定ファイルから Local Workflow を自動生成する処理の実装が複雑になってきていました。また、上述のように Task に加工処理が漏れ出していることや、 Local Workflow と Task が明確に分離されておらず処理の流れと加工処理本体の境界が曖昧になってしまっていたことも、実装の見通しの悪さに拍車をかけていました。

    また、 Local Workflow + Task を開発メンバーの個人開発環境上で動作確認ができるようにするには、 Glue や Snowflake にアクセスできる Airflow 環境を準備する必要があり、やたら手間がかかる状態となっていました。本番用ではない共用 Airflow 環境も存在しましたがこれはステージング環境に近いもので、 Pull Request が Approve されたもののみ投入される環境となっていた為、開発時の動作確認としては利用しづらいものでした。よりフランクに利用できる共用 Airflow 環境を新たに用意する方針も考えられましたが、前述のように Airflow 環境自体の運用が重いため、二の足を踏んでいる状態でした。

    普段の開発では設定ファイルしか記述せず、設定ファイルを元に生成される Local Workflow が確認できるのは Airflow 環境上であるため、 Local Workflow の自動生成処理がチームメンバーの間で徐々にブラックボックス化したことも、 Local Workflow の修正が難しくなっていったことの1つの原因だったように感じています。

    更に、 Airflow 環境上にデプロイされているコードが複雑になっていくのに伴って、 Airflow 自体のバージョンアップも難しくなっていった点も、大きな問題点でした。

移行後のデータパイプライン

2023年度上期頃、(ここまで述べてきた背景とは別に) AWS Glue で行っていた標準化処理を Snowflake SQL に移植することでコストメリットがあることや、オンプレ環境上の Kubernetes クラスタが将来利用できなくなることが分かってきました。それに伴い、前述の問題も合わせて解消する構成に一新する計画が立ち上がりました。

ここからは、移行後の構成の全体像やコアとなるアイデア、各製品の採用理由、そして実際に利用してみた感想について述べていきます。

コアとなるアイデア

新構成に採用する製品選定を始める前に、前述の問題を解消するにはどのようなアイデアをベースに検討する必要があるかについて、以下のように整理しました。

  • 可能な限り、セルフホストはしない

    セルフホストしても特に競争優位性は生まれないので、極力マネージドサービスを利用するものとしました。

  • ELT 処理以外も行える、汎用性の高い構成にする

    特徴の節で述べたように、少数ではあるものの Reverse ETL 処理のような通常の ELT 処理に収まらない処理も扱っています。今後もそのような処理が増える可能性は高く、 ELT 処理に特化した構成は避ける必要がありました。

    また、内製のデータヘルス管理 API は REST API (かつ Snowflake 経由でアクセスできない構成)なので、たとえ ELT 処理に特化させても「dbt に依存解決など含めすべてを任せることでシンプルな構成を実現できる」とはならず、あまり ELT 処理に特化させるメリットが享受できない状況であったため、汎用性の高い構成を目指すこととしました。

  • Global Workflow, Local Workflow, Task の3レイヤー構成の厳格化

    「複雑さを抑えるために Global Workflow と Local Workflow の二段階構成にする」というアイデアは、移行前から上手く機能しているように感じていた為、このアイデアは維持するものとしました。むしろ、 Global Workflow と Local Workflow は以下のように特性や求められる機能が異なることから、(移行前のように同じ Airflow 環境に載せるのではなく)完全に分離して、それぞれをより適した別の仕組みに載せることを検討したほうが、より望ましい構成になるのではと考えました。

    • Global Workflow の特性/求められる機能
      • データ加工ジョブの種類によって、処理のバリエーションが生まれづらい(処理を一般化しやすい)。
      • 複雑かつ巨大な依存関係を表現可能。
      • 一部分のみ再実行を行うなど、ワークフローに対して高度な操作が可能。
      • 日付粒度で実行状態が管理可能。
    • Local Workflow の特性/求められる機能
      • データ加工ジョブの種類によって、処理のバリエーションが生まれやすい。
      • ワークフロー内の依存関係は比較的シンプル。
      • ワークフローに対して、高度な操作はできなくても良い(ワークフロー起動時にパラメタが渡す機能さえあればそれで十分)。
      • 日付粒度で実行状態を管理できる必要はない(Global Workflow 側で担保されていれば、なんとかなるので)。

    また、 Local Workflow と Task に関しても、実装を分離していなかったことで処理の流れと加工処理本体との境界が曖昧になるという問題が発生していたため、より厳格に分離したほうが良いだろうと考えました。

  • デプロイとリリースを分離できるようにする(バージョニングの導入)

    The Twelve-Factor App ではビルドとリリースを分離することを推奨していますが、 この発想はデータパイプラインを構築する上でも有用であると感じていました。特に、もし Local Workflow のデプロイとリリースを分離することができれば、 Local Workflow の動作確認を気軽に行えるようになり、開発体験が大きく改善することが予想される点は重要だと感じていました。

    また、「汎用性の高い構成」や「3レイヤー構成の厳格化」を目指せば目指すほど、ワークフローの構成要素は増えることが想像されます。そしてデプロイとリリースを分離しない場合、構成要素が増えるほど、デプロイ時間は長く、そして複雑な手順になることが想像されます。

  • 自動生成される標準化処理や Local Workflow を、コード管理できるようにする

    「標準化処理や Local Workflow は都度実装するのではなく、実装を共通化したうえで設定ファイルで表現する」というアイデアは、移行前から開発速度の向上に繋がっているのを感じていたため、維持するものとしました。

    一方で、問題点の節で述べたブラックボックス化は、共通化した実装と普段触る箇所のギャップを大きくしすぎたことに起因すると感じました。「普段は Markdown を書いており、 HTML ファイルを直接編集する機会はあまり無い」という人は多いかと思いますが、必要とあらば Markdown から生成された HTML ファイルを読んだり、直接編集したりする可能性は考えられると思います。それと同様に、共通化した実装と設定ファイルを組み合わせることで、個別の実装コードが生成されるようにして必要とあらば実装を読んだり編集したりすることが可能な構成にすれば、上記のギャップを小さくする事ができるのではないかと考えました。

全体像

移行後のインフラ構成全体像

上記のアイデアを元に、上の図のように、 MWAA から Step Functions のステートマシンを実行し、さらにステートマシン実行から ECS タスクを実行する構成を採用しました。また、データ加工処理には dbt を採用し、 dbt プロジェクトは ECR イメージに含めずに S3 上に圧縮ファイルとして管理し、 ECS タスク実行時にダウンロードしてくる構成を取りました。

移行後のワークフロー全体像

上の図は、 Global Workflow と Local Workflow に注目してその関係性を図示したものになっています。 Global Workflow と Local Workflow はそれぞれ MWAA 上の DAG と、 Step Functions のステートマシンとして実現されています。

また、 Global Workflow 内の「データ加工ジョブ」は、 StepFunctionStartExecutionOperator の後に StepFunctionExecutionSensor に遷移するようなタスクグループとして実現されています。

ステートマシンの各 Step では arn:aws:states:::ecs:runTask.syncarn:aws:states:::ecs:runTask.waitForTaskToken を利用して ECS タスクを起動する構成を取っています。なお、この ECS タスクは Task に対応します。

選定理由

この節では、上に示した移行後の構成の各要素それぞれの選定理由について述べていきます。

  • MWAA

    • 移行前から Airflow を利用しており、 UI に慣れ親しんでいる。
    • 柔軟にワークフローを実装可能で、「設定ファイルを元に Global Workflow を生成する」という処理を実現しやすい。
      • Global Workflow の責務は「Local Workflow の実行」と「Local Workflow 間の依存関係の表現」と非常に限定的であり、「コアとなるアイデア」の節で述べたように、複数チーム間で処理の一般化も現実的。そのため、 Airflow の用途を Global Workflow に限定することで、 Airflow のマルチテナント化も現実的になる。
    • バージョニング機能はないが、 Global Workflow のみに責務が限定されているのであれば、デプロイ作業は軽いので妥協可能。
  • Step Functions

    • YAML ファイルとして記述することが可能で、 自動生成される Local Workflow のコード管理 が実現しやすい。
    • バージョニング機能が存在している。
    • マネージドサービスなのでサーバ管理は不要。
    • IAM による権限管理で、複数チームでの利用も実現可能。
  • ECS + ECR

    • Lambda のような実行時間の制約が無い。
    • Task ごとに実行環境の分離が可能。
    • バージョニング機能が存在している。
    • Fargate を利用する場合、サーバ管理は不要。
    • IAM による権限管理で、複数チームでの利用も実現可能。
  • dbt

    • ELT 処理においてデファクトスタンダードとなっている。
    • Materializations によりパーティション粒度での更新が dbt 単体で簡単に実現でき、 ECS + ECR 側にデータ加工処理のロジックが漏れない。
    • YAML ファイルと Jinja テンプレート(メタ dbt モデル)から、 dbt モデルを自動生成する仕組みを用意することで、 自動生成される標準化処理のコード管理 が実現可能。
    • dbt プロジェクトを圧縮したファイルを S3 上で管理することで、バージョニング可能8

新構成を運用してみて

移行前に挙がっていた問題点に関しては、概ね解消しているように感じます。一方で、汎用的な構成にした分、 ELT 処理の開発フローとしては重い構成になってしまったとも感じています。この点に関しては、今後 dbt 単体で対応可能な範囲を広げていく9ことで、 ELT 処理に特化した構成を用意する旨味がある状態に持っていくことが必要だと感じています。

以下は、新構成を運用して感じた良かった点と、良くなかった点になります。

  • 良かった点

    • dbt によってデータ加工処理の実装や動作確認が容易になった。
    • Local Workflow の動作確認が容易になった。
    • リリース時の作業が Global Workflow に対応する設定ファイルのデプロイのみになり、簡素化された。
    • MWAA 環境をマルチテナントで利用することができ、その分だけインフラ費用が圧縮できた10
  • 良くなかった点

    • リリースまでのステップが多いので、変更を高頻度で行いたいユースケースには不向き。
    • dbt は ref 関数によってクエリ実行順序を自動解決してくれるが、それとは別に Global Workflow 側でも実行順序を設定する必要があり、 dbt のポテンシャルを活かしきれていない。
    • Global Workflow の実現方法として DAG の適していない点はそのまま残っている。
    • 楽になったとはいえ、依然 Local Workflow の実装コストはそれなりにある。
      • Step Functions に存在する関数はかなり貧弱で、ちょっとしたパラメタ加工用途にも力不足です。そのため、以下のように「引数に渡された Jinja テンプレートを用いてパラメタの加工を行う汎用 ECS タスクを、ステートマシンの先頭部分に配置する」といった工夫が求められました。

        StartAt: DefineParameterTemplate
        States:
          # ステートマシン実行時のパラメタを original に格納。
          DefineParameterTemplate:
            Type: Pass
            Next: RenderParameters
            Parameters:
              original.$: $
              parameter_template: |  # Jinja テンプレート化されたJSON
                {
                  ...
                }
          # patameter_template を original でレンダリングした結果を rendered に格納。
          RenderParameters:
            Type: Task
            Resource: arn:aws:states:::ecs:runTask.waitForTaskToken
            ResultPath: $.rendered
            Parameters:
              Overrides:
                ContainerOverrides:
                  - Command.$: States.Array(States.JsonToString($.original), $.parameter_template)
                    ...
              ...
            ...
        

まとめ

話を簡単にするために省略しましたが、実際の移行後のデータパイプラインには、標準化処理以外のデータ加工処理を行う Glue ジョブがまだ一部残っています。こちらについても Glue ジョブから Snowflake SQL への移行を検討しており、今後また事例を紹介する機会がやってくるかもしれません。また、標準化処理を AWS Glue から dbt へ如何に移行したのかについて本記事では触れませんでしたが、こちらについても記事にできそうな箇所はあるので、いつかご紹介できればと考えています。

今回紹介した構成は、一般的なユースケースでは恐らくあまり良い構成ではなく、もっと軽い開発フローが実現できる構成が望ましい場合が多いでしょう。ですが、多くのデータ加工ジョブから成る、複雑な依存関係を持つデータパイプラインであれば、今回の構成は一つの選択肢になると感じています。

本記事が、データパイプライン構築時の一助となれば幸いです。


  1. Airflow におけるワークフロー定義ファイルのこと。また、ワークフローのことは DAG と呼び、ワークフローの実行インスタンスは DAG Run と呼びます(参考: DAGs — Airflow Documentation)。
  2. Celery Executor ではなく Local Executor を利用していた関係で、 Airflow スケジューラの処理負荷を外出しする目的で KubernetesPodOperator 利用しており、実行環境分離の必要性は強く意識してはいませんでした。……当初は。
  3. JDBC 経由で大量の細かい Insert 文が発行されてしまい、 Cloud Services Compute のクレジット大量消費に繋がるという問題を2021年当時踏みました。ただし、 Sparkコネクターの概要 | Snowflake Documentation を見ると透過的に内部ステージ経由で書き込みできる様になっているようなので、現在はそのような問題を踏むことは無いかもしれません。
  4. Modern data architecture layers deep-dive - Modern Data Architecture Rationales on AWS から用語を借用しています。
  5. digdag などを利用されている方にはあまり馴染みがないかもしれませんが、 Airflow 環境上で DAG を自動生成するのは Airflow では割と一般的な手法です(参考: Dynamically generate DAGs in Airflow | Astronomer Documentation)。
  6. 関連: 2 枚のピザチーム - AWS での DevOps の概要
  7. AIP-67 Multi-team deployment of Airflow components などを見るに、検討は進められているようです。
  8. 「dbt プロジェクトを ECR イメージに含めてしまい、 dbt プロジェクトを更新する際は ECR イメージごと更新する」という方針も考えられますが、 dbt プロジェクトはデプロイやリリースする機会がほかと比較して圧倒的に多いことが想像されるので、別でデプロイできるようにしました。
  9. 例えば「データヘルス管理 API を Snowflake 経由で扱えるようにすることで、 dbt のpre_hook や post_hook 経由でデータヘルスのチェックや更新を行えるようにする」といったことが考えられます。
  10. MWAA はインスタンスを立ち上げるだけで最低 300 USD/月 ほどかかるので、マネージドではあるものの、チームごとにインスタンスを用意するのは可能であれば避けたいと考えていました。