Streamlit in Snowflake の CI/CD を GitHub Actions で構築する
Streamlit in Snowflake(以下 SiS)は、Snowflake上で手軽にダッシュボードや社内ツールを構築できる便利な機能です。
しかし、アプリのコードが増えてくると「誰がいつデプロイしたかわからない」「本番に反映するたびに手作業が発生する」といった課題が出てきます。
本記事では、GitHub Actions とSnowflake CLIを使ってSiSアプリのCI/CDパイプラインを構築した事例を紹介します。
OIDC(OpenID Connect)によるシークレットレスな認証も組み合わせ、セキュアかつ運用負荷の低い構成を実現しました。
目次
1.なぜ GitHub Actions+Snowflake CLIなのか
SiSのデプロイを自動化する方法は、大きく2つあります。
| 項目 | GitHub Actions+CLI | Native Git Integration |
|---|---|---|
| 用途 | CI/CD (推奨) | デプロイ自動化 |
| Lint/テスト | 可能 | 不可 |
| PR時の自動チェック | 可能 | 不可 |
| 承認フロー | GitHub Pull Request (ブランチ保護で必須化) | 別途実装が必要 |
| Streamlit対応 | snow streamlit deploy | CREATE STREAMLIT FROM |
SnowflakeにはNative Git Integrationというデプロイ自動化の仕組みもあります。
ただし、これはあくまで「デプロイの自動化」であり、Lintやテストを含む「CI/CD」とは異なります。
PR時のLintチェックやマージ後の自動デプロイを一貫して行いたいなら、GitHub Actions+Snowflake CLIの構成が適しています。
技術的には「CIはGitHub Actions、CDはGit Integration」というハイブリッド構成も可能ですが、SiSのデプロイはsnow streamlit deployの1コマンドで完結するため、わざわざ分離するメリットはありません。
また、Git IntegrationはFETCH時に全ブランチ・全タグ・全コミットを Snowflake 側に同期する仕様です。 SiSのデプロイに必要なのは最新のコードだけなので、この点でも CLI 方式のほうが効率的です。
2.全体アーキテクチャ
今回構築したパイプラインの全体像です。

GitHub Actions上でCI(継続的なコード検証・統合)とCD(デプロイ)を一元管理します。
Snowflake CLI でデプロイを行います。
OIDC 認証を使うことで、長期的な秘密情報を GitHub Secrets に保存する必要がありません。
ブランチとSnowflake環境のマッピングは以下のとおりです。
今回は3ブランチ構成を採用しました。
feature/*— ローカル開発・PR 作成dev— DEV環境へ自動デプロイ(統合テスト用)main— PROD環境へ自動デプロイ(本番)
mainブランチには保護ルールを設定し、PR必須・承認必須・Force Push禁止としています。
3.認証方式: Key-pair vs OIDC
GitHub Actionsから Snowflakeに接続する認証方式は主に2つあります。
| 観点 | Key-pair | OIDC |
|---|---|---|
| 秘密鍵の管理 | GitHub Secretsに保存が必要 | 不要 |
| 漏洩リスク | 鍵漏洩で長期アクセス可能 | トークンは短命で限定的 |
| ローテーション | 手動で定期更新 | 自動(都度生成) |
| 設定の複雑さ | シンプル | Snowflake側の初期設定が必要 |
今回はOIDC 認証(Workload Identity)を採用しました。
GitHub Actionsが発行する短命のOIDCトークンでSnowflakeに接続するため、GitHub Secretsに秘密鍵を保存する必要がありません。
Snowflake側ではWorkload Identity Userを作成し、特定のリポジトリ・環境からのみ認証を許可します。
-- Snowflake 側の設定例(DEV / PROD それぞれ作成)
-- DEV 環境用
CREATE OR REPLACE USER svc_cicd_dev
TYPE = SERVICE
DEFAULT_ROLE = cicd_role_dev
WORKLOAD_IDENTITY = (
TYPE = OIDC
ISSUER = 'https://token.actions.githubusercontent.com'
SUBJECT = 'repo:<org>/<repo>:environment:dev'
);
GRANT ROLE cicd_role_dev TO USER svc_cicd_dev;
-- PROD 環境用
CREATE OR REPLACE USER svc_cicd_prod
TYPE = SERVICE
DEFAULT_ROLE = cicd_role_prod
WORKLOAD_IDENTITY = (
TYPE = OIDC
ISSUER = 'https://token.actions.githubusercontent.com'
SUBJECT = 'repo:<org>/<repo>:environment:prod'
);
GRANT ROLE cicd_role_prod TO USER svc_cicd_prod;
SUBJECTでGitHub Environmentを指定することで、各環境のワークフローからのみ認証可能になります。
PoCや小規模プロジェクトであればKey-pair認証でも十分ですが、本番運用ではOIDCを推奨します。
GitHub Secrets/Variablesの設定
OIDC認証では秘密鍵は不要ですが、接続先の情報はGitHub Secrets/Variablesで管理します。
リポジトリ Secrets(全環境共通)
| Secret | 説明 |
|---|---|
SNOWFLAKE_ACCOUNT | Snowflake アカウント識別子 |
環境 Secrets(環境ごとに異なる値)*
| Environment | Secret | 値 |
|---|---|---|
dev | SNOWFLAKE_USER | svc_cicd_dev |
prod | SNOWFLAKE_USER | svc_cicd_dev |
4.CI/CDパイプライン
CIパイプライン
PR 作成時に自動実行されるチェックをGitHub Actionsで定義しました。
# ci.yml
name: CI
on:
pull_request:
workflow_call:
jobs:
lint:
runs-on: ubuntu-latest
steps:
- uses: actions/checkout@v6
- name: Setup uv
uses: astral-sh/setup-uv@v7
- name: Run Ruff (lint)
run: uv run ruff check .
- name: Run Ruff (format check)
run: uv run ruff format --check --diff .
RuffはPythonの高速なLinter/Formatterです。ruff checkでコードスタイルの違反を、ruff format --checkでフォーマットの不整合を検出します。
なお、SiSはPythonアプリなので、必要に応じてpytestなどの自動テストを追加することも可能です。
CDパイプライン
ブランチへのpushをトリガーに、Snowflakeへ自動デプロイします。
cd_dev.yml—devブランチへpush時にDEV環境へデプロイcd_prod.yml—mainブランチへpush時にPROD環境へデプロイ
DEV環境へのデプロイでは、CI(Lint)とパッケージ検証を通過してからデプロイが実行されます。
SiS(Warehouse Runtime)ではenvironment.ymlでライブラリを管理しますが、Snowflake環境のAnacondaチャンネルで提供されていないパッケージを指定するとデプロイが失敗します。
これを防ぐため、snow snowpark package lookupで事前チェックしています。
# cd_dev.yml(抜粋)
- name: Setup Snowflake CLI
uses: snowflakedb/snowflake-cli-action@v2.0
with:
use-oidc: true
# environment.yml からパッケージ名を抽出し、各パッケージを検証
- name: Validate Snowflake Anaconda packages
run: snow snowpark package lookup <パッケージ名> -x
- name: Deploy Streamlit App
run: snow streamlit deploy app_dev --replace --prune -x
env:
SNOWFLAKE_ACCOUNT: ${{ secrets.SNOWFLAKE_ACCOUNT }}
SNOWFLAKE_USER: ${{ secrets.SNOWFLAKE_USER }}
-x(--temporary-connection)は、config.tomlの接続定義を使わず環境変数で接続する指定です。
GitHub Actionsのように設定ファイルを持たない環境では、このオプションを付ける必要があります。
環境ごとのデプロイ先はsnowflake.ymlで定義します。
同じデータベース内でスキーマを分離し、app_devはdevスキーマへ、app_prodはprodスキーマへデプロイされます。
# snowflake.yml
definition_version: '2'
entities:
# DEV environment
app_dev:
type: streamlit
identifier:
name: my_app
database: my_db
schema: dev
main_file: app.py
pages_dir: pages
query_warehouse: my_wh
artifacts:
- app.py
- environment.yml
- pages
# PROD environment
app_prod:
type: streamlit
identifier:
name: my_app
database: my_db
schema: prod
main_file: app.py
pages_dir: pages
query_warehouse: my_wh
artifacts:
- app.py
- environment.yml
- pages
5.おわりに
SiSのCI/CDは、GitHub Actions+Snowflake CLI+ OIDCの組み合わせで十分に構築できます。
Snowflake CLI Actionのuse-oidc: trueオプションにより、シークレットレスなデプロイが数行の設定で実現できるようになりました。
最初のセットアップ、特に OIDCのWorkload Identity Userの作成にはやや手間がかかりますが、一度構築すれば運用はほぼ自動化されます。
ランニングコストもGitHub Actions の無料枠(月2,000分)で十分まかなえるため、コストが導入の障壁になることもありません。
SiSアプリの規模が小さいうちからCI/CDを整備しておくと、チームが拡大したときにもスムーズに対応できます。
SnowflakeやSiSを活用したデータ基盤の構築・運用にご興味がありましたら、ぜひシステムエグゼへお気軽にお問い合わせください。
