Amazon MWAAでdbt Coreをサクッと使ってみたかった
この記事はdbtアドベントカレンダーの23日目です。(すみません!遅刻しました!)
はじめに
dbtのプロジェクトやモデルをジョブスケジューリングして実行するには、いくつかの選択肢がありますが、特にdbt Coreを使われている場合はApache Airflowを利用されていることが多いように思います。
AirflowはOSSのワークフロー管理ツールで、Pythonによる容易なワークフロー(DAG)の定義とGUIによる管理のしやすさにより、データエンジニアリング界隈で大変人気があります。実行環境としてもDockerコンテナによる分散実行が可能であり、そのスケーラビリティが魅力的です。
ただ、OSSであるため、スケーラブルな環境を自力で構築するのは多少手間がかかってしまいます。そのため、ちょっとした操作でAirflow環境をシュッと立ちあげてくれるマネージドサービスが重宝されます。GCPの「Google Cloud Composer」やAWSの「Amazon Managed Workflows for Apache Airflow(MWAA)」がそうです。
今回はAWSのMWAAを使って、dbt Coreをサクッと動かしてみたいと思います。
・・・・・・が!この「サクッと」がかなり大変だったので、ちょっと路線変更して、dbt CoreをMWAA上でなぜサクッと動かせないのか、それならどうするべきなのか、ということを書いてみたいと思います。(この見通しの甘さが遅刻の原因・・・)
MWAAのアーキテクチャ
MWAAのアーキテクチャとしては公式ドキュメントの以下の図が分かりやすいです。
引用:AWSドキュメント Amazon Managed Workflows for Apache Airflow (MWAA) とは
管理画面をホストするWebサーバとメタデータDBはAWSのサービスVPCによって管理されており、特に設定や設計をする必要はありません。
一方で、スケジューラやワーカは顧客側のVPC内にFargateによってコンテナが立ち上がり、設定によって自在にオートスケールします。スケジューラだけでなくワーカも自動的にFargateとしてデプロイしてくれるため、PythonやBashのコードであれば、その実行環境を自ら準備する必要はありません。
当初の目論見
実はAWSの公式ドキュメントでそのままのタイトル「Amazon MWAAでdbtを使う」というチュートリアルがあります。これ、そのままやってみたら良いのでは?というのが当初の目論見でした。
このドキュメントでは、Airflowもdbtも両方Pythonで動作しているということを利用し、MWAAに直接dbtのライブラリをインストールすることでMWAAでdbtを動かそうとしています。
MWAAにはもともと、Airflow本体が依存しているライブラリと、MWAAに必要なAWS関連のライブラリがインストールされています。さらに、requirements.txtをユーザ側で用意して起動時に読み込ませることによってそれ以外のライブラリを追加することが可能です。
そのため、requirements.txtにdbtのライブラリを書いてやれば、MWAAがdbtをインストールした状態で起動してくれるので、BashOperatorでそのままdbt CLIが使える!というわけです。
前述のとおりMWAAはワーカ自体がオートスケール可能なコンテナとして起動してくれるので、dbt CLIを使うにはちょうど良いですよね!これは便利!
依存関係にハマる
ところが、これをやってみようとしてだいぶハマってしまいました・・・。結論として、この手法はPythonライブラリの依存関係の競合が起こりやすく、かなり微妙でした。
公式ドキュメントでも、Airflow 2.2.2とdbt-core 0.21.1やdbt-redshift 0.21.1との依存関係の解決にかなり苦労している様が見受けられます。
dbtの0.21.1はかなり古いバージョンなので、今やるならできれば最新のバージョン1.3系で、対象のDWHによってdbt-snowflakeも入れたいな、などと考えると、それぞれ別のパッケージの競合が起こり、起動に失敗してしまします。
バージョンによっては完全にダメなわけでもなく、私の実験した範囲では、dbt-core 1.2.0およびdbt-postgres 1.2.0は競合なく起動可能でしたが、dbt-snowflake1.2.0は起動不可。dbt-core 1.3.0は起動不可で、当然それに依存したdbt-postgresもdbt-snowflakeも起動不可でした。
このライブラリ競合は、aws-mwaa-local-runnerというMWAAをローカルでシミュレーションできるツールを使って、一つずつ依存関係を紐解き、解決していく必要があるようです。[1]
ただ、dbtとMWAAの双方がバージョンアップするたびにPythonの依存関係を解いていくのは全然本質的な作業ではなく、さすがにちょっとつらそうです。
ではどうするのか
dbtとMWAAを同居させるとPythonの依存関係が複雑になってしまうので、環境を分離させなければならないことが分かりました。
Airflowには、このようにPythonのライブラリが競合することを避けるためにPythonVirtualenvOperatorというオペレータが存在し、タスクの中だけで有効なPython仮想環境を定義して実行することが可能なようです。[2]
しかし、今回動かしたいのはPythonのコードそのものではなく、dbt CLIというPython製のBash CLIツールであるため、あくまでも使いたいのはBashOperatorです。PythonVirtualenvOperatorを使うのは難しそうです。
より根本的に環境を分離させる解決策として、ワーカ上で直接dbtモデルを動かすのではなく、dbtモデルはコンテナイメージとしてビルドしておき、ECSOperatorを使って起動するという方法があります。
この方法はすでにYohei Onishiさんがすでにブログにされてます。(というか今回私がハマったバージョン衝突の問題点もさらっと指摘されていますね!)
この記事ではCI/CDの仕組みまで整っていますが、MWAAでdbt Coreを動かすには、少なくともECSの利用は必要なようです。
こうなってくるともはや「サクッと使う」感じではなくなってきますね・・・。おとなしくdbt Cloudを使ったほうがサクッと始められそうです。
おわりに
ということで、AWS公式ドキュメントの「Amazon MWAAでdbtを使う」をやってみた記事にしようと思いきや、いろいろと模索しているうちにこれはあまり現実的な選択肢ではない、ということに気づいたブログでした。
サンプルとしてはあまり有用な記事にはなりませんでしたが、私と同じように公式ドキュメントに則ってやってみようとしてハマっている(またはハマりそうになってしまっている)方にとってなんらかの示唆となれば幸いです。
-
AWSドキュメント:Python 依存関係のインストール ↩︎
-
こちらのブログが参考になりました:Airflowのタスク実行環境を分離する ↩︎
Snowlfake データクラウドのユーザ会 SnowVillage のメンバーで運営しています。 Publication参加方法はこちらをご参照ください。 zenn.dev/dataheroes/articles/db5da0959b4bdd
Discussion