はじめまして、株式会社ナウキャストでデータエンジニアをしている高橋です。弊社では、Snowflakeのデータ変換ツールとして、dbt-coreを利用しています。dbt-coreはオープンソースで無料にもかかわらず、データ変換やモデリング、テスト、ドキュメント生成など、データ基盤の運用に役立つ多くの機能が揃っており、とても便利なツールです。2025年6月時点では、dbt project on Snowflakeの機能がPuPrされており、Snowflake上でdbtの開発・運用ができるようになることが想定されます。
しかし、dbt-coreは無料で便利な反面、dbt Cloudのような統合管理機能はありません。そのため、プロジェクト数が増えてくると、それぞれのdbt projectごとにdbtドキュメントが生成され、管理や閲覧が煩雑になってしまいます。各プロジェクトで個別に生成されたdbtドキュメントを一つ一つ見に行くのは、思った以上に手間がかかります。
そこで、このdbtドキュメントをSnowflake内で管理し、ユーザーが一つのページから複数のdbtドキュメントを簡単に閲覧できるアプリを構築してみました。
今回は、Snowflake内でdbtドキュメントを公開する方法として、「Streamlit in Snowflake(SiS)」と「Snowpark Container Service(SPCS)」の2種類のアプローチでアプリを構築し、それぞれの特徴や使い勝手を比較してみました。
今回構築したコードは以下で公開しています。本稿では詳細なアプリケーションの構築方法については割愛させていただきます。(SPCSのインフラ構築については後述で簡単に紹介しています)
Snowflakeインフラの準備(SPCS)
1. SPCS(Compute Pool, Image Repository, Stage)の作成
create compute pool if not exists dbt_docs_pool
min_nodes = 1
max_nodes = 1
instance_family = CPU_X64_XS
auto_suspend_secs = 300
auto_resume = true
comment = 'dbt-docs application用のコンピュートプール'
;
create image repository if not exists dbt_docs_repository
comment = 'dbt-docs application用のイメージリポジトリ'
;
create stage if not exists dbt_docs_stage
directory = ( enable = true )
comment = 'dbt-docs application用のステージ'
;
2. イメージのプッシュ
Streamlitアプリケーションのデプロイ時に必要になるため、以下のクエリ実行結果のrepository url
を確認します
-- repository urlの確認
show image repositories;
repository url
を確認することができたら、spec.yaml
を修正します
今回は、Streamlitの実行ユーザーの認証方法位にはPATを採用しています
spec:
containers:
- name: >
image: />:>
env:
SERVER_PORT: 8501
SNOWFLAKE_ROLE: >
SNOWFLAKE_WAREHOUSE: >
readinessProbe:
port: 8501
secrets:
- snowflakeSecret: >.>.>
secretKeyRef: PASSWORD
envVarName: SNOWFLAKE_PASSWORD
- snowflakeSecret: >.>.>
secretKeyRef: USERNAME
envVarName: SNOWFLAKE_USER
endpoints:
- name: >
port: 8501
public: true
networkPolicyConfig:
allowInternetEgress: true
spec.yaml
の修正が完了したら、アプリケーションのdocker imageをpushします。
snow stage copy spec.yaml @dbt_docs_stage --overwrite
docker build . -t repository url>:tag> --no-cache --platform linux/amd64
snow spcs image-registry login
docker push repository url>:tag>
3. サービスの作成
image repositoryの更新が完了したら以下のクエリを実行し、SERVICEを作成します。
create service dbt_docs_application_service
in compute pool dbt_docs_pool
from @dbt_docs_stage
specification_file = 'spec.yaml'
min_instances = 1
max_instances = 1
;
以下のクエリ実行結果のingress_url
からStreamlitアプリケーションにアクセスすることができます。
-- サービスエンドポイントの確認
show endpoints in service dbt_docs_application_service;
4. dbtドキュメントの更新
dbtドキュメントの保管場所はSnowflakeの内部ステージに保管することを想定しています。dbtプロジェクトの変更時にCICD経由でHTMLファイルを更新し常に最新のdbtドキュメントを取得できることを想定しました。
以下のコマンドでdbtドキュメントの生成および更新を実行することができます
dbt docs generate --static
snow stage copy source_path> destination_path> --overwrite
5. streamlitアプリのデプロイ
SiSのデプロイには以下のコマンドを実行します
uv run snow streamlit deploy --replace
SPCSのデプロイには以下のコマンドを実行します
docker push repository url>:tag>
snow spcs service upgrade SERVICE_NAME> --spec-path spec.yaml
内部ステージの中身に以下のオブジェクトが格納されていれば、エンドポイントから
streamlitアプリの画面を参照することができるはずです。
@DBT_DOCS_STAGE
├─ statics
│ ├─ dbt-docs-A.html
│ ├─ dbt-docs-B.html
│ └─ dbt-docs-C.html
├─ dbt_docs
│ ├─ statics
│ │ └─ .gitkeep
│ ├─ .streamlit
│ │ └─ config.toml
│ ├─ common
│ │ └─ snowflake_connection.py
│ ├─ streamlit_app.py
│ └─ envrionment.yml
└─ spec.yaml
SiSで表示される画面
SPCSで表示される画面
Streamlitアプリケーションの詳細
dbtドキュメントの読み込み
Streamlitアプリケーションからdbtドキュメントの読み込みは以下の部分で行なっています。Snowpark Python APIを使って内部ステージに対して、LISTクエリおよびGETコマンドを実行し、HTMLファイルを取得します。
snowflake.snowpark.Sessionの取得
今回の構成の場合、Streamlitアプリケーションは実行環境ごとにsnowflake.snowpark.Sessionの取得方法が異なるため、以下のようにlocal, streamlit, spcsそれぞれの取得メソッドを作成しました。
消費クレジットの比較
SPCSにかかるコスト
SPCSのコストは以下のカテゴリに分類されます:
-
コンピューティングプールコスト:
- 仮想マシン (VM) ノードの集合体にかかる費用。
- ノードの数とタイプ (インスタンスファミリー) によって消費クレジットが決定。
- IDLE (アイドル状態) でも課金が発生するが、
AUTO_SUSPEND
機能で最適化可能。 - コンピューティングプールインスタンスファミリーごとのクレジット消費量
- CPUインスタンスタイプ:
CPU_X64_XS
(0.06クレジット/時) からCPU_X64_L
(0.83クレジット/時)。 - 高メモリインスタンスタイプ:
HIGHMEM_X64_S
(0.28クレジット/時) からHIGHMEM_X64_L
(4.44クレジット/時)。 - GPUインスタンスタイプ:
GPU_NV_XS
(0.25クレジット/時) からGPU_NV_SL
(13.50クレジット/時)。
- CPUインスタンスタイプ:
-
ストレージコスト:
- イメージリポジトリ、ログストレージ、ボリュームマウント、ブロックストレージなど。
-
データ転送コスト:
- 外部へのデータ移動 (アウトバウンド) や内部データ転送にかかる費用。
-
ブロックストレージ料金:
- 例: AWS US East (Northern Virginia) では81.92 USD/TB/月。
-
データ転送料金:
- 例: AWS US East (Northern Virginia) からインターネットへのデータ転送は90.00 USD/TB。
SiSにかかるコスト
Streamlitのコストは主に以下に依存します:
-
仮想ウェアハウスのコンピューティングコスト:
- アプリの実行やSQLクエリに必要なウェアハウスの利用。
- WebSocket接続がアクティブな間は課金が継続。
-
AUTO_SUSPEND
やウェブページを閉じることでアイドルコストを削減可能 - streamlitSleepTimeoutMinutesの設定
-
仮想ウェアハウスのクレジット消費量:
- Standard Warehouse:
XS
(1クレジット/時) からL
(8クレジット/時)。 - Gen 2 Warehouse:
XS
(1.35クレジット/時)。 - Snowpark Optimized Warehouses:
XS
(1.00クレジット/時)。
- Standard Warehouse:
コンピューティングコストの比較
項目 | SPCS | Streamlit in Snowflake |
---|---|---|
最小単位のコスト | 最小インスタンス (CPU_X64_XS ): 0.06クレジット/時 |
最小ウェアハウス (XS ): 1クレジット/時 (Standard Warehouse) |
高性能オプション | GPUや高メモリインスタンスは高価 (GPU_NV_SL : 13.50クレジット/時) |
高性能オプションはなし |
最低課金時間 | 5分 | 1分 |
アイドルコスト | IDLE状態でも課金されるが、AUTO_SUSPEND で最適化可能 |
WebSocket接続が切れるまでデフォルトで約15分間課金が続く(手動で接続を切ることは可能) |
ストレージコストの比較
項目 | SPCS | Streamlit in Snowflake |
---|---|---|
基本ストレージコスト | Snowflakeステージを利用するため共通 | Snowflakeステージを利用するため共通 |
追加ストレージコスト | コンテナイメージやブロックストレージの追加コストが発生 | なし |
データ転送コストの比較
項目 | SPCS | Streamlit in Snowflake |
---|---|---|
外部データ転送 | 両者とも外部へのデータ転送には料金が発生 | 両者とも外部へのデータ転送には料金が発生 |
内部データ転送 | コンピューティングプール間やウェアハウス間の内部データ転送にコストが発生する場合あり | 内部データ転送のコストは通常意識されない |
今回の構成における料金シミュレーション
- 条件
- dbtユーザーがdocsを閲覧する時間:5分/回
- 1日6回時間帯の重複なく閲覧される
- 1ヶ月30日で計算する
- dbtユーザーがdocsを閲覧する時間:5分/回
- SPCS
- アプリ起動時間 = 5分/回 × 6回/日 = 30分/日
- アイドル時間 = 5分/回(1回の稼働ごとに最大5分のアイドル時間が発生) × 6回/日 = 30分/日
- 合計稼働時間 = 30分/日(アプリ起動時間)+ 30分/日(アイドル時間)= 60分/日(30時間)
- 消費クレジット = 30時間 × 0.06クレジット/時 = 1.8クレジット。
- SiS
- アプリ起動時間 = 5分/回 × 6回/日 = 30分/日
- アイドル時間 = 5分/回(1回の稼働ごとに最大5分のアイドル時間が発生) × 6回/日 = 30分/日
- 合計稼働時間 = 30分/日(アプリ起動時間)+ 30分/日(アイドル時間)= 60分/日(30時間)
- 消費クレジット = 30時間 × 1クレジット/時 = 30クレジット
項目 | SPCS (CPU_X64_XS ) |
SiS (X-Small ) |
---|---|---|
アプリ起動時間 | 30分/日 | 30分/日 |
アイドル時間 | 30分/日 | 30分/日 |
1か月の合計稼働時間 | 30時間 | 30時間 |
消費クレジット | 1.8クレジット | 30クレジット |
実際に消費されたクレジットを確認するには以下のクエリを実行し確認することができます
select
start_time,
end_time,
datadiff (second, start_time, end_time) as duration,
credits_used
from
snowflake.account_usage.snowpark_container_service_history
where
compute_pool_name = your_compute_pool_name>
order by start_time desc
;
使い分けの考え方
SPCSが最適となるケース
- カスタムアプリケーションのホスティング: WebサービスやAPIを長時間稼働させる場合。
- GPUを必要とするML/AIワークロード: 高度な計算処理を行う場合。
- 多様な言語やライブラリの利用: Python以外の言語や特定のライブラリを必要とする場合。
- バッチ処理や非同期ジョブ: 必要な時だけ起動するジョブを実行する場合。
Streamlit in Snowflakeが最適となるケース
- インタラクティブなダッシュボード/データアプリケーション: データ分析者が迅速に構築・共有したい場合。
- 開発の容易性と迅速なフィードバック: 開発効率を重視する場合。
- 小規模なワークロード: 小規模なウェアハウスで十分な場合。
複数のdbt ドキュメントの参照アプリ
今回のように、SiSとSPCSを採用することで、S3などにHTMLファイルを管理し、ホスティング+ユーザー認証を行うシステムをSnowflake外で構築しなくていいのは嬉しいポイントです。
簡単にプロジェクトを横断したdbt ドキュメントのアプリケーションを構築したい場合はご参考にしていただければと思います。
複数のdbt projectのドキュメントアプリについては、dbt project on Snowflakeやdbt-loomなど様々なサービスがもあるので、いつかプロジェクトを横断したdbt ドキュメントの参照の悩みは解決されるかもしれないので、引き続きチェックしていきたいです。
SiS vs SPCSについて
SPCS は、高性能なカスタムコンテナアプリケーションやGPUを必要とするML/AIワークロードに適しており、適切なインスタンス選択と運用最適化で高いコスト効率を発揮します。一方、Streamlit in Snowflake は、インタラクティブなダッシュボードやデータアプリケーションを迅速に構築・展開するのに優れていますが、大規模なデータ処理やアイドル時間の課金には注意が必要になりそうです。
個人的には、SPCSについてTerraformの対応やSnowflake CLIの機能が充実してきているため、構築作業は以前に比べて楽になってきていると思います。料金コストについてもWarehouseの稼働単価よりCompute Poolの稼働単価の方が安価になりそうです。(ただ、Webページを閉じないとauto_suspendされないので、実際利用してみるとシミュレーション通りにはいかないかもしれません)
SiSの方はやはり簡単に構築ができるため、インタラクティブなアプリ開発には向いていると思います。この長所・短所を念頭に選択して行けたらいいと思いました。
Snowflake上でデータアプリを開発するときの参考にしていただけたら幸いです。
Views: 0