📊

Streamlit with Google Cloud: BigQuery へのクエリ

2023/02/27に公開

今回は Streamlit アプリから BigQuery にクエリを投げ、結果を可視化してみます。

この連載では、Google Cloud 上で Streamlit を上手に動かす方法をご紹介しています。


クエリの実装

1. ライブラリのインストール

BigQuery への接続から可視化まで、必要となるパッケージを導入します。

poetry add google-cloud-bigquery pandas db_dtypes

2. Google Cloud の認証

Hello, world! では CLI を使って Google Cloud の API を利用するために gcloud auth login というコマンドを実行しました。しかし今回のように、SDK を使った自作のプログラムからクラウドに繋ぐためには Application Default Credentials (ADC) という仕組みで認可を与えます。なぜこのようなことになっているのか、興味がある方は Yuki さんのこちらの記事 をご覧ください。おもしろいです :)

さて、具体的には以下のコマンドを実行するだけです。

gcloud auth application-default login

合わせて、SDK が参照する環境変数をセットしておきましょう。

export GCLOUD_PROJECT=$( gcloud config get-value project )

3. クエリと可視化の実装

Streamlit の Multipage 機能を使い、BigQuery へクエリし可視化するページを作ってみます。ディレクトリを作成します。

mkdir pages

Open Source Insights のデータが BigQuery の一般公開データセットとして保存されているため、ここから OSS のライセンス情報を引っ張ってみます。以下を pages/bq.py として保存してください。

pages/bq.py
import pandas as pd
import streamlit as st
from google.cloud import bigquery
import firebase

@st.cache_resource()
def bq():
    client = bigquery.Client()
    return client

@st.cache_data(ttl=60 * 10)
def query(sql) -> pd.DataFrame:
    return bq().query(sql).to_dataframe()

def index():
    if not firebase.refresh():
        st.experimental_rerun()
        return

    st.subheader("Open Source Insights")
    sql = """
    SELECT p.System, License, COUNT(DISTINCT p.Name) AS Packages
    FROM `bigquery-public-data.deps_dev_v1.PackageVersionsLatest` AS p,
         p.Licenses AS License
    GROUP BY System, License ORDER BY Packages DESC LIMIT 10
    """
    st.dataframe(query(sql))

if "user" not in st.session_state:
    st.text("左のメニュー [home] からログインしてください")
else:
    index()

静的解析をしつつ、スタイルをフォーマットします。

./test.sh

4. ローカルでの実行

正しく動くか、手元で動かしてみましょう。

poetry run streamlit run home.py

ログインした状態で、左のサイドメニューから bq を選びます。以下のような表が表示されれば成功です 🎉

クラウドへのデプロイ

1. サービス アカウントを作る

Google Cloud で「誰がどのリソースに対して何を実行できるかを制御する」には IAM を利用しますが、人ではなく、アプリケーションに認可を与えたいときは サービス アカウント を使います。

Cloud Run のサービスに渡すサービス アカウントを sa-app という名前で作り、プロジェクト内で BigQuery にクエリを行う権限を付与します。

export project_id=$( gcloud config get-value project )
gcloud iam service-accounts create sa-app --display-name "SA for the streamlit app"
gcloud projects add-iam-policy-binding "${project_id}" \
    --member "serviceAccount:sa-app@${project_id}.iam.gserviceaccount.com" \
    --role "roles/bigquery.jobUser"

2. Cloud Run へデプロイ

作ったサービス アカウントを関連付けて Cloud Run にデプロイしてみましょう。

gcloud run deploy my-app --region "asia-northeast1" --source . \
    --service-account "sa-app@${project_id}.iam.gserviceaccount.com"

3. Cloud Build での明示的なビルド

これまでは gcloud run deploy--source オプションを使い、ソースコードのビルドから Cloud Run にデプロイするまでを一度に実行していました。ただ現実的にはアプリケーションごとに専用のリポジトリを用意するのが一般的ですし、ソースコードと関連づくタグをイメージにもちたいといった背景から、ビルドとデプロイを切り離してみます。

まずは Docker イメージのリポジトリを作ります。

gcloud artifacts repositories create my-apps \
    --repository-format "docker" --location "asia-northeast1" \
    --description "Containerized applications"

ローカルのファイルをクラウドに転送し、Cloud Build にビルドを任せ、Artifact Registry への保存までをしてくれるコマンドは以下の通りです。タグ名は先ほど作成したリポジトリをベースにしつつ streamlit:v1.0 部分でこのアプリケーションとそのバージョンを特定できるようにしています。

gcloud builds submit \
    --tag "asia-northeast1-docker.pkg.dev/${project_id}/my-apps/streamlit:v1.0" \
    .

イメージは Artifact Registry に格納されたので、Cloud Run へのデプロイには --image オプションを使います。

gcloud run deploy my-app --region "asia-northeast1" \
    --image "asia-northeast1-docker.pkg.dev/${project_id}/my-apps/streamlit:v1.0"

Cloud Run にはうまく反映されましたか?

次は CI/CD パイプラインからのデプロイを実装してみましょう。

Google Cloud Japan

Discussion