現実モデリング

データとかエンジニアリングとか健エミュとか

StreamlitをApp Engineにデプロイする

はじめに

Streamlitはデータを活用したアプリケーションの構築を得意とするOSSのWebアプリケーションフレームワークで、インタラクティブダッシュボードを構築したり、通常のダッシュボードでは扱うことができない柔軟な可視化を提供してくれる。

streamlit.io

私も実務で使っているが、Streamlitは素晴らしいフレームワークだ。一方で、デプロイする方法についてはいくつか選択肢があり、ベストプラクティスは確立されていない。GCPAWS、およびSnowflakeの範囲内*1では、デプロイの選択肢としては以下のようなものがある。

  1. AWSのEC2、もしくはGCPのCompute EngineなどのVMにデプロイする
  2. AWSのECSにデプロイする
  3. GCPのCloud Runにデプロイする
  4. GCPのApp Engineにデプロイする
  5. Streamlit in Snowflakeにデプロイする
  6. StreamlitのCommunity Cloudにデプロイする

どの選択肢でもデプロイすることは可能だが、各々の手法にはメリットとデメリットが存在する。筆者は実務でStreamlitのデプロイ方法を検討し、結果としてApp Engineへデプロイすることにした。運用を始めてから3ヶ月たったが、結構いい感じで動作している。

この記事では、他のデプロイ手法と比較しながら、StreamlitをApp Engineへデプロイすることのメリットを説明し、具体的なDockerfileやディレクトリ構成、GitHub Actionsを用いたCI/CDの実現方法について記述する。なお、この記事の情報は2023年1月現在のものであり、前提となっている条件についてはアップデートされる可能性がある。他のStreamlitユーザーの参考になれば幸いである。

StreamlitをApp Engineにデプロイすることのメリット

App EngineはGoogle Cloudが提供するサーバーレスのWebアプリケーション実行環境であり、flexible環境を利用すればDockerfileを用いたデプロイが可能になる。

cloud.google.com

StreamlitをApp Engineにデプロイすることのメリット・デメリットは、何と比較するかによって異なる。先述した選択肢を元に、比較して検討してみよう。

AWSのEC2・ECSへのデプロイと比較した場合のメリデメ

まず前提だが、App Engineを利用すると「IAP(Identity-Aware Proxy)認証」が可能になる。IAP認証を用いれば、App EngineやCompute Engineでデプロイされたアプリケーションを保護し、特定のプリンシパル(認証する対象)に絞ってアプリケーションを限定公開できる。また、IAP認証の設定は数クリックで実現可能である。そのため、Google Workspaceを用いている会社であれば、ドメインプリンシパルとして指定することで「数クリックで社内限定アプリケーションをWeb公開する」ことが可能となる。仮に会社発行ではないメールアドレスを用いてログインしている場合、もしくはログインしていない場合であれば、Webアプリケーションへの認証は弾かれ、ユーザーはアプリケーションを利用できない。

cloud.google.com

これは素晴らしい体験だ!わずか数クリックで社内限定Webアプリケーションが公開できる!しかも、普段使っているアカウントを利用して実現できる!

なぜこれが素晴らしいかを説明したい。

データの利用者は怠惰なものだからシームレスな認証体験が必要

まず前提だが、データの利用者は怠惰な存在だと認識するべきだ。エンジニアも怠惰であるべきだが、それはエンジニアに対するべき論だ。データの利用者は実際に怠惰な存在なのだ!エンジニアの100倍は怠惰だと想定したほうがいい。彼ら・彼女らは常にデータの活用以外のタスクに追われている。認証の段階で手間が取られれば、エンジニアが丹精込めて作ったデータ・アプリケーションを使う気をなくしてまうだろう。「パスワードなんだったっけ?聞こうかな...まぁいいや、それより別のタスクをやろう」となってしまう。BASIC認証ですら面倒なのだ!

IAP認証は怠惰なユーザーにとっては光明となる。普段使っているGoogleアカウントで認証できるため、パスワードを紛失する心配がない。すでにブラウザでログインしているなら、認証画面も出てこない。それでいてセキュリティも担保できる。EC2やECSでは同レベルでの認証体験は提供できない。Cognitoで頑張ればできそうな気がするが、率直に言ってその頑張りは機会損失である。素直にApp Engineを利用する方が素早く付加価値を提供できる。

他にもメリットはある。

開発が早い

EC2はそこまで手間ではないが、ECSの場合はデプロイまでに結構な手間がかかる。タスク定義とかVPC設定とかめんどくさいねん。App Engineなら、app.yamlを書いて、Dockerfileを書いて gcloud app deployでポン!とデプロイできる。本当に早いので一回体験してほしい。

GCPのCloud Runと比較した場合のメリデメ

一応Cloud RunでもIAP認証をつけることは可能ではある。

cloud.google.com

ただし、App EngineでのIAP認証の方が簡単ではある。Cloud Runと比較した場合はあまりメリットとデメリットがはっきりしないので、慣れている方でいいのではないかと思う。どちらも慣れていない場合はApp Engineの方が簡単なのでおすすめ。

なお、Cloud Runでデプロイする方法に関しては、Google Cloud Japanのカスタマーエンジニアの方が書いた記事がわかりやすい。

zenn.dev

Streamlit in Snowflakeと比較した場合のメリット

※2023年1月現在、Streamlit in Snowflakeはパブリックプレビューの段階であり、GAとはなっていない。その前提を踏まえた上での記述になります。

Streamlit in Snowflake(以下SiSと省略)はStreamlitアプリケーションをSnowflake上で作成できる機能であり、2023年1月現在ではパブリックプレビューの段階*2となっている。

docs.snowflake.com

SnowflakeはStreamlitを2022年に買収し、2023年にSiSはパブリックプレビューとなった。Snowflakeはコミュニティ戦略などを利用しながらSiSを推しているものの、実運用の観点ではSiSは推奨はできないと筆者は考えている。理由は「他にもっと良いデプロイ方法があるから」である。仮にStreamlitをデプロイする方法がSiSしかない場合はそちらを薦めるが、StreamlitはOSSである。他にいい方法があるならそちらを利用するべきだろう。

具体的には、以下のような点でApp Engineを利用したデプロイの方が都合がいい。

  1. Gitに対応している。Git対応はSiSのプロダクトロードマップに入っているものの、現段階では機能としては提供されていない。コードのバージョン管理の重要性は今更強調することもないだろう。データエンジニアリングのプラクティスにソフトウェアエンジニアリングのプラクティスを取り入れることについても同様に自明である。
  2. ユーザー体験がいい。先述の通り、IAP認証を用いてシームレスな認証が可能である。シームレスな認証体験はアプリケーションの利用可能性を上昇させる。「せっかく作ったのに使われません」ではユーザーへの価値提供につながらず、作る意味がない。
  3. 開発者体験がいい。適切にフローを組めば、ローカルで開発→PR作成時に開発環境にデプロイ→Approveされたら本番環境にマージの流れが作れる。つまりGitHub-flowの実現が可能になり、開発生産性が上がり、変更のデリバリータイムを短縮できる。

StreamlitはSnowflakeがOwnerとなっているOSSだ。SnowflakeGoogle Cloudを競合相手とみなしていそうであり、心持ちはあまり良くない。が、よく考えてみたら、SnowflakeはSparkをSnowparkとして機能の中に組み込んでいる。そのSparkのOwnerはDatabricksであり、DatabricksとSnowflakeバチバチにやり合っている。OSSの世界は不思議な世界だな〜と思う。

2023年6月には、SnowflakeのSummitとDatabricksのData+AI Summitが同日開催された。その時のラスベガス空港にDatabricksが掲載した広告。「SnowflakeはDatabricksの9倍高い」と書いている

www.teamblind.com

アーキテクトはビジネスに対してコミットする存在であり、ベンダーに忖度することなく自由意志の元にアーキテクチャを選択する権利と義務がある。すべてはユーザーの利益のために、状況とやりたいことに応じて自由にパーツを選び、組み合わせてユーザーの問題を解決する存在であるべきだ。

実装

App EngineでStreamlitのアプリケーションを構築するために必要な技術的事項について記述する。Multi-pageアプリケーションを構成する前提で記述するが、Single-pageのアプリケーションでもあまり変わらない。

docs.streamlit.io

ディレクトリ構成

Streamlit
└── sample_application
    ├── Dockerfile
    ├── Home.py
    ├── app.yaml
    ├── pages
    │   ├── 1_hoge.py
    │   ├── 2_fuga.py
    │   └── 3_hoga.py
    └── requirements.txt

Dockerfile

あまり説明することはなさそう

FROM python:3.9.15
EXPOSE 8080
WORKDIR /app
COPY requirements.txt ./requirements.txt
RUN pip3 install -r requirements.txt
COPY . .
CMD streamlit run Home.py --server.port 8080

app.yaml

flexible環境を利用する。

runtime: custom
env: flex

GitHub Actions

以下の流れはGitHub Actionsを利用することで実現できる。

  1. ローカルで開発
  2. リモートレポジトリにプッシュ
  3. PRを作成
  4. テスト用のGCPプロジェクトにデプロイ
  5. 動作確認
  6. 確認ができたらPRをマージして本番環境にデプロイ

これは個人の意見だが、開発フローにはこだわった方がいいと思っている。開発フローを適切に設計できれば、変更までのリードタイムを最小化できるためだ。逆に、開発フローの設計がまずいと、変更までに時間がめっちゃかかるようになる(体験談)。

PR作成時、もしくは更新時にテスト用のGCPプロジェクトにデプロイするためのGitHub Actions設定用ymlは以下の通りになる。

name: Streamlit Branch Deployments
on:
  pull_request:
    types: [opened, synchronize, reopened]
    paths:
      - "Streamlit/**"  # Streamlitディレクトリ配下に変更があった場合のみに起動するように設定する

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Auth to Google Cloud
        uses: google-github-actions/auth@v1
        with:
          credentials_json: "${{ secrets.STG_GOOGLE_CLOUD_DEPLOY_CREDENTIALS}}"
      - name: Set up Google Cloud CLI
        uses: google-github-actions/setup-gcloud@v1
        with:
          version: ">= 363.0.0"
      - name: Deploy to Google App Engine
        run: |
          cd Streamlit/sample_application
          gcloud app deploy --quiet

こちらはmainブランチにpushがあった場合に、本番環境にデプロイするためのGitHub Actions設定用ymlである。

name: Streamlit prod Deployments
on:
  push:
    branches:
      - "main"
    paths:
      - "Streamlit/**"

jobs:
  deploy:
    runs-on: ubuntu-latest

    steps:
      - name: Checkout code
        uses: actions/checkout@v4
      - name: Auth to Google Cloud
        uses: google-github-actions/auth@v1
        with:
          credentials_json: "${{ secrets.GOOGLE_CLOUD_DEPLOY_CREDENTIALS}}"
      - name: Set up Google Cloud CLI
        uses: google-github-actions/setup-gcloud@v1
        with:
          version: ">= 363.0.0"
      - name: Deploy to Google App Engine
        run: |
          cd Streamlit/sample_application
          gcloud app deploy --quiet

GitHub Actionsを利用することで、GitHub-flowが実現できる。

開発手順

  1. まずHome.pyとpagesディレクトリを作る。pagesディレクトリ配下にページをつくる。
  2. streamlit run Home.pyを実行しながらローカル上でアプリケーションを構築。この時はpagesディレクトリ配下に置かれた.pyファイルを編集する
  3. ローカルでいい感じにできたら、Dockerfileとapp.yamlを作成する。パッケージが必要な場合はrequirements.txtを作成する
  4. PRを作成し、GCPのテスト用プロジェクトにデプロイして動作確認
  5. 動作確認がうまくいったら本番環境へマージする

おわりに

個人的にはStreamlit in Snowflakeに期待しているが、実際は機能的な不十分さが目立つ。パブリックプレビュー段階なのでこういうものなんだと思う。今後機能改善が進み、SiS使ってガンガン本番運用をしている企業が増えるといいなと思っている。

とはいえ、事業上のニーズは待ってくれない。なのでApp Engineを用いたデプロイをやった。

*1:Azureは知らない。ごめんね

*2:パブリックプレビュー:GA/Generally Availableの一歩手前