📊

Streamlit with Google Cloud: Hello, world!

2023/02/27に公開

Streamlit、とても便利ですよね!小さなアプリとしても、データ可視化にしても。

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


Streamlit?なぜ Google Cloud で?

Streamlit は「データ分析スクリプトを、数分で "共有できる Web アプリ" に変える」というキャッチコピー通り、Python で書かれたロジックをそのまま、直感的に、フロントエンドの経験がない人でも数分で Web アプリケーションにしてしまえるようなとても優れたフレームワークです。

まずはぜひ、公式サイトのギャラリー の一例を見てみてください。
https://harmkenn-python-stat-tools-app-8h7fra.streamlit.app/
(↑ このサンプルのソースコードはこちら

そして実際、これをクラウドで使いたいというお問い合わせが最近とーっても増えています。

たしかにそもそも Streamlit が「分析ツールをチームで共有する」ためのものですし、アプリケーションをクラウドで気軽 & 安全に共有できれば抜群に相性がよさそうです。そんなわけで本記事では、以下の点を意識しながら Streamlit を Google Cloud にのせるための方法をお伝えします。

  • 極力運用の手間がかからないこと
  • 認証認可含め、セキュアな方法で共有できること
  • コードを書いて git push したらアプリが更新されること

Cloud Run に Streamlit をのせる

1. ローカルでの起動

すでに Streamlit アプリが手元にあれば読み飛ばしてください。一方、もし Streamlit を使ったことがなければ以下 3 行を実行してみてください。$PATH または Python 仮想環境が正しく設定できていれば Web アプリが起動します。

pip install streamlit
echo 'import streamlit as st;st.text("Hello, world!")' > home.py
streamlit run home.py

2. 設定ファイルの確認

依存関係を定義した requirements.txt は手元にありますか?なければ用意しましょう。1. で初めて Streamlit を使った方であれば、以下のコマンドでも OK です。

echo 'streamlit' > requirements.txt

また、requirements.txt の隣に Dockerfile はありますか?もしなければ、せっかくなので Dockerfile なしにコンテナとして動かす 体験をしてみましょう。以下のコマンドで Procfile を作ります。

echo 'web: streamlit run home.py --server.port ${PORT:-8080}' > Procfile

3. Google Cloud 側の準備

もし手元で gcloud CLI が使えなければインストールしてください。CLI が用意できたら、改めて認証を通し、デプロイ先のプロジェクトを設定しましょう。

gcloud auth login
gcloud config set project <your-project-id>

クラウドで利用するサービスを有効化しましょう。

gcloud services enable compute.googleapis.com run.googleapis.com \
    artifactregistry.googleapis.com cloudbuild.googleapis.com

上記コマンドで有効化されるサービスは以下の通りです。

  • compute.googleapis.com ▶︎ Compute Engine、仮想マシンが利用できます。
  • run.googleapis.com ▶︎ Cloud Run、コンテナアプリをホスト。
  • artifactregistry.googleapis.com ▶︎ Artifact Registry、Docker イメージ の保存。
  • cloudbuild.googleapis.com ▶︎ Cloud Build、サーバーレスな CI 環境です。

4. Cloud Run へのデプロイ

ソースコードをクラウドに転送し、Dockerfile なしにコンテナとしてビルドし、Artifact Registry にそれを保存した上で Cloud Run で起動、誰からでもアクセスできるよう IAM を設定するコマンドは以下の 1 行です。

gcloud run deploy my-app --region "asia-northeast1" --source . \
    --allow-unauthenticated --quiet

5 分ほど待ちます。コーヒーを淹れてきてもいいかもしれません。

ちなみに Dockerfile がない場合、コンテナのビルドには Buildpacks が使われます。便利ですね!

一連の処理がうまくいくと、ログの最後に URL が表示されます。アクセスしてみてください。以下のような出力が出たら、おめでとうございます!クラウドに Streamlit アプリケーションをホストできました 🎉🎉🎉

Poetry による依存管理・デプロイ

requirements.txt で依存関係がうまく解決できなくなった経験はありませんか?また Python の仮想環境を意識した開発がちょっと煩雑だったり。そんなときはそれらを改善できる依存関係管理ツール Poetry の出番です。ここではその詳細には触れませんが、Poetry を前提にしたとき、Streamlit や Cloud Run とどう組み合わせるのがいいのかをみていきます。

1. Poetry で Streamlit をインストール

Poetry の公式ガイドを見つつインストールしましょう。作業フォルダに移動し、 init コマンド で設定ファイルを作ります。

poetry init

パッケージは add コマンド でインストールできるのですが、Streamlit を入れようとするとエラーが起きると思います。

poetry add streamlit

もし手元の Python 環境が 3.9 の場合、出力をよく読むと a possible solution would be to set the python property to ">=3.9,<3.9.7 || >3.9.7,<4.0" というメッセージがでているかもしれません。その場合は Poetry の設定ファイルを提案通りに書き換え、改めてインストールしてみます。(Python 3.11 であれば以下は不要なはずです)

sed -i '' -e 's/python.*/python = ">=3.9,<3.9.7 || >3.9.7,<4.0"/g' pyproject.toml
poetry add streamlit

インストールされましたか?仮想環境にインストールされたコマンドは run コマンド で実行できます。Streamlit のバージョンを確認してみましょう。

poetry run streamlit version

後で必要なら export コマンドrequirements.txt を生成することもできるので、requirements.txt は消してしまいましょう。

rm requirements.txt

2. 静的解析ツールの導入

アプリケーションをテストする一環として、静的解析ツールや脆弱性検証ツールを導入してみましょう。実行環境では使わないので dev グループとして導入します。

poetry add --group dev isort black flake8 pip-audit

先々ローカルと CI で同じテストがしやすいよう、スクリプトにまとめつつ、実行してみます。

cat << EOF > test.sh
#!/bin/sh
set -e
poetry run isort .
poetry run black .
poetry run flake8 --exclude=.venv .
poetry run pip-audit
EOF
chmod +x test.sh
./test.sh

3. Dockerfile の作成

Buildpacks では内部的に requirements.txt が参照されるため、Poetry の export コマンド を組み合わせればビルドできることもありますが、ここから先は厳密な依存関係が尊重されるよう、Buildpacks は諦め、Dockerfile を書きます・・

Dockerfile
FROM python:3.11 as builder
ENV PYTHONDONTWRITEBYTECODE=1 \
    PIP_NO_CACHE_DIR=off \
    POETRY_HOME="/opt/poetry"
ENV PATH="${POETRY_HOME}/bin:${PATH}"
RUN python -c 'from urllib.request import urlopen; print(urlopen("https://install.python-poetry.org").read().decode())' | python -
RUN poetry config virtualenvs.create false
WORKDIR /app
COPY pyproject.toml /app/
COPY poetry.lock /app/
RUN poetry install --no-interaction --without dev --no-ansi --no-root -vvv

FROM python:3.11-slim
ENV PYTHONUNBUFFERED=1 \
    PYTHONIOENCODING="UTF-8"
COPY --from=builder /usr/local/lib/python3.11/site-packages /usr/local/lib/python3.11/site-packages
COPY --from=builder /usr/local/bin/streamlit /usr/local/bin/
WORKDIR /app
COPY . /app/
CMD ["streamlit", "run", "home.py", "--server.port", "8080"]

ポイントは以下です。

  • マルチステージ ビルドを使い、最終的なイメージからは Poetry への依存をなくす
  • ステージ間で依存をうまく引き渡すため、Poetry の仮想環境は作らない
  • 実行環境で不要なパッケージを除外すべく poetry install は --without dev
  • Cloud Run で動作するよう、起動ポートには 8080 番を指定

Cloud Run は内部的に イメージ ストリーミング という技術が使われていて イメージサイズによる起動時間への影響はとても小さいのですが、リンク先にあるようなセキュリティ観点、その他費用やイメージの持ち運び観点でも、何かと小さいほうが便利ではありますよね。ということで最後に、不要となった Procfile は消しておきましょう。

rm Procfile

4. Cloud Run へのデプロイ

Poetry を導入してみましたが、Dockerfile を作りビルドもできる状態です。最後にもう一度、Cloud Run にデプロイしてみましょう!

gcloud run deploy my-app --region "asia-northeast1" --source .

ちなみにですが、ローカルで起動する場合は以下のコマンドを実行すれば OK です。

poetry run streamlit run home.py

いかがでしたか?アプリケーションはうまくクラウドで動いたでしょうか?次は Firebase 認証を使って、簡単なログイン機能を実装してみます。

Google Cloud Japan

Discussion