Streamlit は Python 製のインタラクティブな Web アプリケーションを簡単に開発できるフレームワークです。特に、データサイエンスや機械学習、BI・ダッシュボードといった領域で広く利用されています。
開発した Streamlit アプリケーションを社内向けに広く利用してもらうことを考えた際、それをデプロイするための環境が必要になります。今回、複数の Streamlit アプリケーションをデプロイするための基盤を AWS 上に構築してみたので、本記事ではその内容についてご紹介できればと思います。アーキテクチャの一例として参考になれば幸いです。
本題に入る前に、社内向けの Streamlit アプリケーションをデプロイする環境としてどのような選択肢があるか見ておきたいと思います。
Streamlit in Snowflake (SiS)
Snowflake ユーザーの方であれば、まず選択肢に挙がるのは「Streamlit in Snowflake (SiS)」ではないでしょうか。Snowflake 上のデータが存在する場所と近い環境でデータアプリケーションを開発・稼働させることができ、手軽に始めやすいオプションです。
Git 統合によるソースコードバージョン管理
執筆時点で Public Preview ですが、Snowflake の Git 統合リソースを作成することで、Snowsight 上でのソースコード編集をバージョン管理することも可能になっています。
PrivateLink 経由での SiS への接続
PrivateLink 経由接続は、執筆時点で AWS, Azure で一般提供 (GA) になっています。
SiS の制約・デメリット
その他のデプロイ環境と比較する上で SiS の制約・デメリットを挙げるとすると、例えば以下のようなものがあるのではないかと思います。
- そもそも Snowflake を導入していないと利用できない
- OSS の方が開発スピードが速く、最新の機能を SiS で利用できない場合がある
- アプリケーションにアクセスする際、Streamlit 以外の Snowsight UI も見えてしまう
自社クラウド・オンプレミス環境
何らかの理由で SiS を利用するのが難しい場合、自社環境にデプロイする方法も考えられます。この場合、Snwoflake の導入は前提にならず、OSS 側でリリースされている最新の機能も利用可能になります。ここでは、アプリケーションが稼働する場所はクラウド・オンプレミスを問わず、何らかのクラウド型 CDN 製品を前段に設ける構成を想定します。
以下の RAKUDEJI 前田さんの記事では、Cloudflare という CDN 製品の各種機能を利用して、Streamlit アプリケーションをセキュアにデプロイする具体的な方法について紹介されています。
本記事でご紹介する内容も考え方はこちらに近く、アプリケーションが稼働する自社クラウド環境として AWS を利用し、CDN 製品として Amazon CloudFront を利用します。具体的な構成については以降の章で詳しく扱います。
Squadbase
株式会社 Queue が提供する Squadbase という製品もあります。これは Sreamlit や Next.js などで構築した社内向け AI アプリをセキュアにデプロイ・運用するためのクラウド PaaS 製品で、2025/5/1 に正式公開されたようです。
自社クラウド環境にアプリケーション基盤を構築する場合、セキュリティや DevOps なども考慮して設計・構築していく必要がありますが、このような分析価値に直接繋がらない開発・運用コストをプラットフォーム側にオフロードできます。(本記事で紹介しておいて言うのもという気はしますが汗)
ユーザー数ベースの課金体系であることをどう捉えるか次第ですが、利用者規模やエンジニア体制などの組織事情に照らして、導入を検討してみると良いかもしれません。(参考 : Squadbase の Zenn Publication)
さて、前置きが長くなりましたが本題です。
以下のようなアーキテクチャで Streamlit アプリケーション基盤を構築しました。(少し長いので、以降「SiAWS 基盤」と表現することにします)
Streamlit in AWS (SiAWS) 基盤アーキテクチャ
各コンポーネントの詳細を以下に説明していきます。リソース間の依存関係を考慮すると、例えば以下のような順序でデプロイすると良さそうです。
- ALB + デフォルトターゲットグループ
- CloudFront ディストリビューション
- デフォルト ECS サービス
- 各アプリケーションの ALB リスナールール + ターゲットグループ
- 各アプリケーションの ECS サービス
CloudFront ディストリビューション
前述の通り、CDN として CloudFront ディストリビューション(以下、「CloudFront」)を構成します。これは、SiAWS 基盤に1つのみ置くものとしています。
- オリジンとして Streamlit 用の Application Load Balancer (ALB) を設定します。
- Route 53 でユーザーがアクセスする URL のエイリアスレコードとして CloudFront の URL を設定し、CloudFront の代替ドメイン名にユーザーアクセス用 URL を設定します。
- URL をカバーする ACM 証明書をバージニア北部 (us-east-1) リージョンで作成し、CloudFront のカスタム SSL 証明書に設定します。Viewer Protocol Policy を
Redirect HTTP to HTTPS
にしておくことで、ユーザーに HTTPS 通信を強制できます。 - Behaviour の Viewer Request に認証用の Lambda@Edge を関連づけることで、アクセス時にインフラ層での SAML 認証を通すように設定しています。
Application Load Balancer (ALB)
Elastic Load Balancing サービスを利用して、SiAWS 基盤に1つ ALB を配置します。
アプリケーション毎に ALB を配置することもできますが、ALB 自体にも稼働コストがかかるため1つに集約しています。パスパターン毎にターゲットグループを振り分けることで、複数アプリケーションのデプロイを実現します。
また本構成では ALB で SSL 終端させており、その先の VPC 内通信は HTTP で行っています。
各アプリケーションの ALB リスナールール + ターゲットグループ
Terraform で実装する場合、例えば以下のようになります。
Terraform 実装例
variable "applications" {
type = map(object({ name = string, path = string, priority = number }))
}
resource "aws_lb_listener_rule" "default" {
for_each = var.applications
listener_arn = data.aws_lb_listener.default.arn
priority = each.value.priority
action {
type = "forward"
target_group_arn = aws_lb_target_group.default[each.key].arn
}
condition {
path_pattern {
values = ["/${each.value.path}", "/${each.value.path}/*"]
}
}
}
resource "aws_lb_target_group" "default" {
for_each = var.applications
name = "${var.load_balancer.name}-${each.value.name}"
port = 8501
protocol = "HTTP"
target_type = "ip"
vpc_id = var.network.vpc_id
health_check {
enabled = true
healthy_threshold = 2
interval = 30
path = "/${each.value.path}/healthz"
port = "traffic-port"
protocol = "HTTP"
timeout = 5
unhealthy_threshold = 5
}
}
- いずれかのアプリケーションのパスパターンに一致するリクエストがあった場合、該当するターゲットグループにリクエストを転送します。(いずれにも一致しなかった場合、デフォルトターゲットグループに転送されます)
- リスナールールの優先度
priority
は 1~50,000 (執筆時点) の整数値で設定可能です。パスパターンのみで定義する場合、他と重複さえしなければ各アプリケーションに割り当てる優先度は任意の値で問題ありません。 - Streamlit ではヘルスチェック用のエンドポイントとして
/healthz
が提供されているので、ターゲットグループに設定するヘルスチェックパスにはこれを設定します。
Streamlit アプリケーション側の設定
ALB リスナールールで指定したパスでアクセスできるようにするために、Streamlit の設定ファイル .streamlit/config.toml
の baseUrlPath
にアプリケーション用のものを設定します。
.streamlit/config.toml
[server]
port = 8501
baseUrlPath = "/{app_path}"
enableWebsocketCompression = false
[browser]
gatherUsageStats = false
ECS サービス
各 Streamlit アプリケーションは ECS サービス上で稼働します。コンテナイメージは、アプリケーションコードを含むビルド済みイメージを ECR リポジトリから読み込みます。
Terraform 実装例
resource "aws_ecs_service" "default" {
name = var.app_config.name
cluster = data.aws_ecs_cluster.default.arn
desired_count = 1
launch_type = "FARGATE"
platform_version = "1.4.0"
propagate_tags = "SERVICE"
task_definition = aws_ecs_task_definition.default.arn
load_balancer {
container_name = "server"
container_port = 8501
target_group_arn = data.aws_lb_target_group.default.arn
}
network_configuration {
security_groups = [aws_security_group.default.id]
subnets = var.network.private_subnet_ids
assign_public_ip = false
}
deployment_circuit_breaker {
enable = true
rollback = true
}
tags = {
Name = "streamlit-${var.app_config.name}"
}
}
このうち ALB ターゲットグループに関連するのは以下の部分です。ECS サービスがデプロイされ、指定のヘルスチェック条件を満たすと、ターゲットグループに登録されます。
resource "aws_ecs_service" "default" {
load_balancer {
container_name = "server"
container_port = 8501
target_group_arn = data.aws_lb_target_group.default.arn
}
}
データベース
前述のアーキテクチャでは、アプリケーションが利用するデータベース領域として Snowflake を想定しましたが、Snowflake 以外のデータベースでも問題ありません。
Snowflake を利用する場合、例えば以下のように構成できます。
リソース | 管理範囲の考え方 |
---|---|
Database |
STREAMLITAPP のように Streamlit 用に1つ作成する。 |
Schema |
/demo-app11 のアプリケーションであれば DEMO_APP_11 のように、アプリケーション毎に作成する。 |
Table | アプリケーション内の用途で必要な分だけテーブルを作成する。 |
アーキテクチャの各コンポーネントのところ説明しきれなかった部分について、以降で扱います。
CI/CD
アプリケーション開発のライフサイクルとして、以下のようなものを想定しています。
- ローカルで開発・動作確認する
- GitHub 上でブランチ・Draft PR を作成し、STG 環境に手動デプロイする
- STG 環境での動作にも問題がなければ PR を Open し、レビュー依頼する
- PR 承認後、main ブランチにマージされたことをトリガーに本番環境に自動デプロされる
これを実現するにあたり、GitHub 上のソースコードから Docker イメージを Build して ECR リポジトリに Push し、新しい ECS サービスをデプロイする GitHub Actions (GHA) ワークフローを定義しました。STG 環境にデプロイする際は workflow_dispatch で手動で起動します。また、main マージ時にソースコード変更のあった Streamlit アプリケーションに対して、自動で上記の GHA ワークフローが呼び出されるようにしています。
ネットワークセキュリティ
Streamlit に限ったものではありませんが、CloudFront → ALB → ECS 構成の一般的なネットワーク制御についても言及しておきます。
ALB や ECS は VPC サブネット上で稼働するので、セキュリティグループ (SG) を設定します。CloudFront は使用する IP アドレスの範囲を マネージドプレフィックスリスト として公開しているので、ALB 用 SG のソースをこれに限定することで、クライアントから ALB 用 URL に直接アクセスすることを拒否し、CloudFront 経由に限定することができます。
Terraform 実装例
data "aws_ec2_managed_prefix_list" "cloudfront" {
name = "com.amazonaws.global.cloudfront.origin-facing"
}
resource "aws_security_group" "default" {
name = "streamlit-lb-sg"
description = "streamlit-lb-sg"
vpc_id = var.network.vpc_id
ingress {
from_port = 443
to_port = 443
protocol = "tcp"
prefix_list_ids = [
data.aws_ec2_managed_prefix_list.cloudfront.id,
]
}
egress {
from_port = 0
to_port = 0
protocol = "-1"
cidr_blocks = ["0.0.0.0/0"]
}
}
また、ECS 用 SG のソースを ALB 用 SG に限定することで、VPC 内のその他のサービスからの接続も制限することができます。
最後に SiAWS 基盤周りで今後やっていきたいことについて触れておきたいと思います。
アプリケーション不使用時停止機構の整備
ECS サービスが稼働していると当然その分のコストがかかりますが、常時稼働させておく必要のないものもあると思うので、以前に以下記事でもご紹介した仕組みなども転用しながら「必要な時だけオンデマンドで起動する」「夜間の停止・起動を自動化する」といった仕組みを検討・整備していきたいと考えています。
アプリケーション毎の認証・認可
現状 CloudFront に対してインフラ層での SAML 認証を設定し、アクセスを社内ユーザーに限定できていますが、今後 Streamlit アプリケーション層での認証・認可も実装していく想定です。アプリケーションによっては更新操作をさせるケースも出てくると思うので、「どのユーザーがどのアプリケーションに対して、何のロール(権限)でアクセスできるのか」を制御できるようにしていきたいと考えています。
AWS 上で Streamlit アプリケーション基盤を構築する方法について書いてみました。
今回は Streamlit in Snowflake (SiS) 以外の方法をご紹介してみましたが、SiS もどんどん便利になっていきそうな気がするので、今後当社でも開発環境を整備して使用感を確かめつつ、SiS に移行できそうなものは徐々にしていくかもしれません。とはいえ SiS の制約から実現できないことをやりたいということも依然ある気がするので、そういった場合に利用する環境として今回ご紹介したものも運用し続けようかなと考えています。
最後まで読んでいただき、ありがとうございました。
Views: 0