Streamlit with Google Cloud: BigQuery へのクエリ
今回は Streamlit アプリから BigQuery にクエリを投げ、結果を可視化してみます。
この連載では、Google Cloud 上で Streamlit を上手に動かす方法をご紹介しています。
- Cloud Run での Hello, world!
- Firebase 認証との連携
- BigQuery へのクエリ (本記事)
- GitHub、GitLab、Cloud Build での CI/CD
クエリの実装
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
として保存してください。
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 パイプラインからのデプロイを実装してみましょう。
Discussion