Google Cloud における SQL ベース ワークフローの本番運用
Google Cloud Japan Team
※この投稿は米国時間 2023 年 6 月 9 日に、Google Cloud blog に投稿されたものの抄訳です。
SQL スクリプトのリポジトリを管理、デプロイ、またはオーケストレートするための標準化されたプロセスが存在しないため、ビッグデータ分野でのその使い方や関連性にかかわらず、DevOps の見地から見ると SQL の管理は煩雑です。
Dataform は、チーム間で SQL ベースのパイプラインに関するコラボレーションを可能にするツールです。SQL データ変換を Configuration as Code と組み合わせることにより、複数のデータ エンジニアが単一のリポジトリ内でエンドツーエンドのワークフローを共同で作成できます。Dataform の概要については、一般提供開始についてお知らせしたこちらのブログ投稿をご覧ください。
この記事の目的は、Google Cloud で Dataform と Cloud Build を使用して再現可能かつスケーラブルな ELT パイプラインを設定する方法を具体的に紹介することです。ここで説明する全体的なアーキテクチャは環境を越えてスケールすることが可能で、複数のチームが協力して開発できるため、本番環境ですぐに使用できる合理化されたスケーラブルなパイプラインを確立できます。
サンプル ワークフロー
まず、単純な ELT ワークフローについて考えてみましょう。データ ウェアハウスの一部としてサブジェクト エリアを作成する必要がありますが、この例では、サンプルとして Account、Customer、Sales の 3 つのサブジェクト エリアがあります。このサンプル ワークフローはソーステーブルのデータに基づいてビューを作成するだけですが、必要に応じて実際の変換に拡張できます。
この例の Dataform コードを見るには、このブログに付属するサンプルコードをご覧ください。
3 つのサブジェクト エリアはタグで整理されており、このタグに基づいてサブジェクト エリアがリポジトリ内の別々のコード セクションに分離されます。Dataform CLI を使用すると、このワークフローを実行して個々のサブジェクト エリアをビルドするコマンドをローカルマシンで実行できます。
dataform run --tags=[SUBJECT_AREA]
このコマンドを実行すると、Dataform によってプロジェクトが SQL アクションの DAG にコンパイルされ、指定したタグが付いたアクションが実行されて、ワークフローを実行する BigQuery ジョブが作成されます。タグを付けることで、開発者チームが同じデータ ウェアハウスの各サブジェクト エリアまたは各ドメインを共同で構築できます。
GitHub(またはこれと同等のバージョン管理されたリポジトリ)を使用し、ローカルの Dataform CLI からタグを指定してコマンドを実行することにより、コード変更を他のサブジェクト エリアから切り離してテストできます。
Dataform には、広範な SQL パイプラインを構築できるように数多くのツールが用意されていますが、この記事ではそれらは取り上げません。こちらのドキュメントを読んで Dataform がどれだけ優れたツールであるかを学ぶことを強くおすすめします。
サンプル ワークフローの CI / CD の設定
前のセクションでは、チーム内で GitHub の Dataform プロジェクトをどのように共同で構築しテストできるかに焦点を当てました。次の問題は、これらのコード変更のデプロイと Dataform コードの CI / CD パイプラインの設定を簡単にする方法は何かです。ここで Cloud Build の出番となります。
Cloud Build を使用して、Dataform プロジェクトの CI / CD を設定できます。Cloud Build は、ワークロードに応じてスケールアップまたはスケールダウンできるサーバーレス プラットフォームで、他の GCP サービスと緊密に統合されています(この利便性は次のセクションを読むとわかります)。
サンプル ワークフローに戻りましょう。ここでは、任意のサブジェクト エリアの最新の SQLX ファイルをフェッチし、Dataform を実行して BigQuery のデータを更新する Cloud Build トリガーを設定できます。最初のサブジェクト エリア(Account)でこれがどのように機能するのかを見ていきます。
事前設定: IAM
まず、Dataform コードをビルドしてデプロイするために必要なすべてのロールと権限を含むサービス アカウントを用意します。これを行うためのカスタム サービス アカウント(例: 「dataform-deployer」)を作成し、このアカウントに以下のロールを割り当てることをおすすめします。
BigQuery 管理者
Pub/Sub パブリッシャー
ログライター
1. バージョン管理
すべてのコード変更を確実にバージョン管理するには、すべての変更を git リポジトリに格納することが重要です。この例については、付属の GitHub リポジトリをご覧ください。
適切なリポジトリをあらかじめ準備しておくと、DataOps プロセスが合理化され、デプロイが簡単になります。
2. 構築してデプロイする
このデータをローカルマシンで構築するために必要なことは、Dataform コマンドを実行して適切なタグを渡すことだけです。ただし、このステップを Cloud Build に任せるには、以下のファイルをソース リポジトリに追加する必要があります。
一般化された Dataform コマンドを含むシェル スクリプト(run.sh を参照)
単体テストを実行するための別のシェル スクリプト(run_tests.sh を参照)
サブジェクト エリア用の cloudbuild 構成ファイル(cloudbuild_account.yaml を参照)
次に、一般公開されているドキュメントの手順に沿って Cloud Build トリガーを作成する必要があります。まず、GitHub リポジトリを Cloud Build に接続すると、アカウントを認証し、目的のリポジトリを選択するよう求められます。
注: リポジトリのロケーションは非常に重要です。トリガーは、リポジトリを接続したのと同じリージョン内でのみ作成できます。
リポジトリが接続されたら、Dataform コードを実行するトリガーを作成できます。この例では、毎日実行するようスケジュールできる手動トリガーを作成しますが、Cloud Build には他にもいくつかのトリガー オプションがあり、特定のユースケースにより適したものを選択できます。
画面上の手順に沿ってトリガーを作成し、各フィールドにリポジトリの設定を正確に反映させます。サンプルコードについては、以下の構成をご覧ください。
サンプル プロジェクトを正常に実行するには、トリガーの作成時にプロジェクト ID とロケーション(US)を代入変数として入力する必要があります。
3. Dataform CLI を実行して BQ ジョブを実行する
トリガーの設定が終わったら、手動ビルドを開始してパイプラインの動作を確認できます。内部で Cloud Build が GitHub リポジトリに接続し、関連するすべてのファイルをフェッチします。
Cloud Build YAML ファイルには、ビルド構成(ビルドに含まれるステップや実行順序など)が含まれます。
YAML ファイルにシェル スクリプトの呼び出しが記述されています。このスクリプトにより、一般化されたバージョンの「dataform run」コマンドが実行されます。タグと変数を手動で渡す代わりに、これらを環境変数として Cloud Build 構成に設定できます。
シェル スクリプトが、呼び出されるたびに、関連する SQLX ファイルを取得し、Dataform を実行します。
これを受けて、Dataform が渡された SQLX ファイルを解釈し、それに応じて BigQuery ジョブをスピンアップします。
これで、Cloud Build を通じてワークフローの CI / CD が可能になりました。次回ビルドをトリガーしたときに、GitHub で加えたすべてのコード変更が直ちにパイプラインの実行に取り込まれます。
この処理を毎日や毎時間といった頻度で実行されるようオーケストレートするには、この手動トリガーを呼び出すスケジューラ ジョブを作成するだけです。これは Cloud Build で直接行うこともできます。
4. Pub/Sub で成功のメッセージをパブリッシュする
最後に、「dataform-deployments」という Pub/Sub トピックを作成する必要があります。サンプルの Cloud Build デプロイメントは、ビルドが成功するたびにこのトピックにメッセージをパブリッシュするよう構成されています(cloudbuild_account.yaml ファイルの最後のステップを参照)。これは、今のところは特に意味はありませんが、後でそのメリットがわかります。
これですべての設定が完了し、開発者チームは、コード変更の追跡やデプロイについて気にせずに、必要なだけ何度でもソースコードに変更を加えることができるようになりました。
Pub/Sub を介してビルドをリンクさせる
前のセクションでは、1 つのサブジェクト エリアをビルドする 1 つのトリガーを設定する方法について説明しました。次に、複数のサブジェクト エリアを一つずつ順に実行する必要があるユースケースを見ていきます。Cloud Build 構成ファイルを修正して各サブジェクト エリアを別々のステップでビルドすることもできますが、この方法には無視できない制限があります。それは、ビルドが途中で失敗した場合にビルド全体を再実行しなければならないことです(つまり、すでに正常に更新されたサブジェクト エリアも再ビルドすることになります)。
ここでは、Account、Customer、Sales をこの順にビルドするとします。Account のビルドは成功したものの、Customer のビルドが途中で失敗した場合、普通なら、エラーを解決した後に最後のステップ(つまり、Customer のビルド)からパイプラインを再開したいでしょう。
ここで、Cloud Build が GCP サービスと緊密に統合されているという点が生きてきます。Cloud Build は Pub/Sub とネイティブに通信し、トリガーの push サブスクリプションを作成できます。つまり、サブジェクト エリアごとに別々のビルドを作成し、Pub/Sub を介してそれらをリンクさせることができます。
この動作を確認するため、サンプル プロジェクトの cloudbuild_account.yaml 構成ファイルをもう一度見てみましょう。ビルドの最後のステップで、「SUCCESS」というメッセージが「dataform-deployments」トピックにパブリッシュされています。また、完了したサブジェクト エリアを明示する subjectArea 属性が指定されています。
これで、このシステムを利用して Cloud Build トリガーをリンクさせることができます。まず、Customer サブジェクト エリア用のトリガーを作成します。今回は手動トリガーではなく、Pub/Sub によって呼び出されるトリガーを作成し、それを「dataform-deployments」トピックにサブスクライブします。
残りの構成ステップは、以下の 3 つの点のみが Account トリガーとは異なります。
構成ファイルのフィールドで Customer 用の構成ファイル(cloudbuild_customer.yaml)を指定する必要があります。
Pub/Sub メッセージからのメタデータを格納する代入変数をもう一つ追加する必要があります。
このトリガーが、「account」サブジェクト エリアが完了したときにのみ呼び出されるようにするフィルタを追加する必要があります。これにより、メッセージが dataform-deployments トピックにパブリッシュされるたびに毎回このトリガーが発生することを防ぎます。
Customer 用のトリガーを設定したら、元の画面に戻って Account サブジェクト エリア用の手動トリガーを開始します。
Account トリガーが完了すると、Customer トリガーが自動的に呼び出されます。
すべてを連携させる: スケーラブルな ELT パイプラインを作成する
同じ手順に沿って、「Sales」サブジェクト エリア用の 3 つ目のビルドトリガーを設定できます。これは Customer のトリガーと同じように機能しますが、「Customer」の属性を持つ Pub/Sub メッセージが届くのを待つという点が異なります。
これで、パイプラインを形成するビルドのチェーンが完成しました。
このようにセットアップすることで、ワークフローのスケーリングをすばやく簡単に行うことができます。
特定のサブジェクト エリア用の SQLX ファイルの拡張
開発者は、ソース リポジトリにある SQLX を必要に応じて何度でも変更できます。追加のファイルを作成しても、デプロイまたはオーケストレーションのプロセスに影響することはありません。唯一の注意点は、新しいファイルにはその構成ブロックで適切なタグを割り当てる必要があることです。
このようにして、ソースコードをどれだけ変更しても、すべての変更が GitHub で追跡され、Cloud Build によって自動的に取得されます。
新しいサブジェクト エリアの作成
新しいサブジェクト エリアを作成することも単純明快なプロセスになります。新しいタグを対象のサブジェクト エリアに割り当てたら、あとは Dataform コードを記述してローカルでテストし、マスター ブランチに統合するだけです。この変更を Cloud Build に組み込むには、新しい構成ファイルとトリガーを作成する必要があります。ただし、構成の大部分は既存のビルドから流用できるので、手順は簡単です。
複数の環境向けのデプロイ戦略
環境を越えたスケーリング
これまでの作業はすべて、単一の GCP プロジェクトを前提としています。開発、QA、本番といった環境の垣根を越えてこのプロセスをスケールアウトしたいときはどうすればよいでしょうか。このシナリオにも同じプロセスを簡単に適用できます。必要なのは以下のステップだけです。
環境ごとに GCP プロジェクトをセットアップする。
リポジトリに環境ごとのブランチを作成する。
dataform.json ファイルで、各ブランチの正しいプロジェクトを指し示す。
各環境で同じビルドを設定する。ただし、ソース リポジトリの正しいブランチから pull するようにビルドを構成する。
このドキュメントに従って、各プロジェクトの特定のブランチを GCP の Dataform にリンクする。
これらを設定したら、あとはごくわずかな維持管理またはメンテナンスを行うだけで、開発者がコード変更をビルドしてテストし、本番環境にデプロイできます。必要なのは、Dataform コードでの適切なタグ付けプロトコルと、データをある環境から別の環境に移動する PR / 統合プロセスだけです。
VPC-SC に関する考慮事項
注意していただきたい点として、上記のセットアップは、Pub/Sub または Cloud Build のために VPC Service Controls を利用している GCP 環境では、そのままでは機能しない場合があります。以下の考慮事項に留意してください。
VPC のセキュリティ境界内で Cloud Build を実行するときは、プライベート プールの内部でビルドを実行する必要があります。また、セキュリティ境界内での Pub/Sub push サブスクリプションは、Cloud Run のデフォルトの run.app URL のみに対応しています。そのため、Cloud Build トリガーの push サブスクリプションを作成しようとすると、おそらく VPC エラーが発生します。
これを回避するには、関連するプロジェクトを境界の外側に移動して push サブスクリプションを作成してからプロジェクトを境界内に戻すか、または Webhook によって呼び出され、Pub/Sub に依存しないトリガーを使用します。
次のステップ
ここに示す方法を使用すると、データ エンジニアやアナリストからなる複数の大規模なチームが共同で単一のリポジトリからコードの開発、デプロイメントの作成、実行のオーケストレーションを行うことができます。この記事で説明した手順と付属の GitHub サンプル プロジェクトは、チームがクラウド上で ELT 用のスケーラブルなアーキテクチャを独自に設定できるようにすることを目標としています。
ワークロードに Dataform を取り入れる方法の詳細については、こちらの Google Cloud ドキュメントをご覧ください。