19
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

ECSの新機能Expressモードで、認証つきStreamlitアプリを簡単にAWSデプロイしよう!

Last updated at Posted at 2025-11-22

11/22 20:40更新: Dockerfileを更新し忘れていたため反映しました🙏

Amazon ECSの新機能「エクスプレスモード」が登場しました。

ECRにコンテナイメージさえプッシュしておけば、面倒なネットワークやタスク定義などの準備をせずとも、簡単にECS周りのインフラをまとめて自動構築してくれます。

Expressモードのポイントまとめ

  • ECRへのイメージプッシュまでは自分でやっておく必要がある
  • 作成ウィザードで、詳細設定を変更せず進めるとデフォルトVPCにデプロイされる
  • 同じくデフォルトの場合、ALB・タスクともにパブリックサブネットに配置される
  • 実行環境はFargate。x86系アーキテクチャのためMacでビルドする際は注意
  • サービスを削除すると、自動作成されたリソースをまとめて掃除してくれる

これまでの課題

特にBedrockなどのAIチャットボットをStreamlitで開発したとき、WebSocketに対応したインフラを使う必要があるため、AWS App Runnerなどのお手軽デプロイが使えないのがこれまでの課題でした。

かといってECSを自分で構築するのは、特に初心者にとってはそれなりのハードルです。
App Runnerのようなサーバーレスではないため、デプロイ後はランニングコストが発生し続ける点には注意です。
(構成にもよりますが、ざっくり月額数千円〜ぐらいがミニマム?)

1. Dockerイメージを作成する

ECS Express Modeは、残念ながらDockerイメージの構築を自分でやる必要があります。
App RunnerやAmplifyのように、GitHubのリポジトリ紐付けにも対応してほしかった…!

このハンズオンでは、AWSバージニア北部リージョンのみを利用します。

ECRリポジトリを作成する

十分な権限をもつIAMユーザーでAWSアカウントにサインインし、reg と検索してAmazon ECRにアクセスします。

スクリーンショット 2025-11-22 15.00.51.png

トップページの「作成」ボタンから、新規プライベートリポジトリを作成します。
リポジトリ名は simple-streamlit-chatbot にして、他はデフォルトでOKです。

コンテナ構築用の開発環境を起動する

AWS CloudShellを使えないか頑張ったのですが、ディスクが1GBしかないので無理ゲーでした。大人しくローカルPCもしくはGitHub Codespacesなどを使うことにしましょう。

以下より、simple-streamlit-chatbot という名前で新規パブリックリポジトリを作成します。
Add README をオンにしておきましょう。

コードスペースを起動します。

スクリーンショット 2025-11-22 14.55.09.png

AWS CLIの最新版をインストールします。

# インストーラーをダウンロード
curl "https://awscli.amazonaws.com/awscli-exe-linux-x86_64.zip" -o "awscliv2.zip"

# インストーラーを解凍
unzip awscliv2.zip

# インストーラーを実行
sudo ./aws/install

# 不要ファイルを削除
rm -rf awscliv2.zip aws

ターミナルから自分のAWSアカウントを操作できるよう、認証を行います。

aws login --remote

しれっと使ってますが、これも新機能です。
https://aws.amazon.com/jp/blogs/security/simplified-developer-access-to-aws-with-aws-login/

AWS Region [us-east-1]: というプロンプトでリージョンを聞かれたら、Enterでデフォルトのまま進めます。

その後、表示されるURLにアクセスし、今回作業するAWSアカウントでブラウザ認証を行ったあと、検証コードをコピーして、コードスペースのターミナルに貼り付けます。

スクリーンショット 2025-11-22 15.02.27.png

Streamlitアプリを作成する

コードスペースの左サイドバーから、以下の新規Pythonファイルを作成します。

app.py
import asyncio
import streamlit as st
from strands import Agent
from strands.tools.mcp import MCPClient
from mcp import stdio_client, StdioServerParameters

# フロントエンドを描画
st.title("Strands MCPエージェント")
st.text("AWSナレッジMCPサーバーを使って、Nova Premierがあなたの質問に答えます!")
prompt = st.chat_input("質問を入力")

if prompt:
    # ユーザーのプロンプトを表示
    with st.chat_message("user"):
        st.markdown(prompt)

    # エージェントの応答を表示
    with st.chat_message("assistant"):
        with st.spinner("考え中…"):

            # MCPクライアント作成
            client = MCPClient(lambda: stdio_client(
                StdioServerParameters(
                    command="uvx",
                    args=["awslabs.aws-documentation-mcp-server@latest"])
                )
            )

            with client:
                # エージェント作成
                agent = Agent(
                    model="us.amazon.nova-premier-v1:0",
                    system_prompt="思考も回答も日本語で行ってください。",
                    tools=client.list_tools_sync()
                )

                # ストリーミング表示の準備
                container = st.container()
                state = {
                    "text_holder": container.empty(),
                    "buffer": "",
                    "shown_tools": set()
                }

                # Strandsをストリーミング実行する非同期関数を定義
                async def run_stream():
                    async for event in agent.stream_async(prompt):
                        current_tool = event.get('current_tool_use', {})
                        tool_id = current_tool.get('toolUseId')
                        tool_name = current_tool.get('name')

                        # ツール実行を検出して表示
                        if tool_id and tool_name and tool_id not in state["shown_tools"]:
                            state["shown_tools"].add(tool_id)
                            if state["buffer"]:
                                state["text_holder"].markdown(state["buffer"])
                                state["buffer"] = ""
                            container.info(f"🔧 **{tool_name}** ツールを実行中...")
                            state["text_holder"] = container.empty()

                        # テキストを抽出して表示
                        if event.get('data'):
                            state["buffer"] += event['data']
                            state["text_holder"].markdown(state["buffer"] + "")

                    # 最終表示
                    if state["buffer"]:
                        state["text_holder"].markdown(state["buffer"])

                # 非同期関数を実行
                asyncio.run(run_stream())

同様に、コンテナ化に必要なDockerfileも新規作成します。

Dockerfile
FROM python:3.13

# 作業ディレクトリ
WORKDIR /app

# 依存パッケージをインストール
RUN pip install uv mcp streamlit strands-agents strands-agents-tools

# アプリ本体をコピー
COPY . /app

# 公開ポート
EXPOSE 80

# Streamlitを起動
CMD ["streamlit", "run", "app.py", "--server.port=80", "--server.address=0.0.0.0"]

コンテナイメージを作成して登録する

先ほどのECRリポジトリを開くと、「プッシュコマンドを表示」ボタンから必要なコマンドを確認できます。

スクリーンショット 2025-11-22 15.56.44.png

コードスペース上で、これらのコマンドをすべて順番に実行すれば、プッシュ完了です。

2. ECS Express Modeでデプロイする

ECSのコンソールにアクセスし、「今すぐ始める」ボタンからExpressモードのウィザードを開きます。

スクリーンショット 2025-11-22 16.03.36.png

先ほど登録したイメージの latest タグを選択します。

スクリーンショット 2025-11-22 16.04.57.png

2つのロールは、プルダウン内の「新しいロールの作成」を指定します。
ecsTaskExecutionRoleecsInfrastructureRoleForExpressServicesが自動作成されます)

「その他の設定」を展開し、タスクロールの「新しいロールの作成」をクリックします。
Bedrockにアクセス可能な権限を、ECSタスクに設定しましょう。

ステップ1では、ユースケースでECSタスクを選択して次に進みます。

スクリーンショット 2025-11-22 17.00.32.png

許可ポリシーは AmazonBedrockFullAccess をチェックして進みます。

スクリーンショット 2025-11-22 17.01.41.png

ecsTaskExecutionRoleWithBedrock と言う名前でロールを作成します。

ECS Expressモードを作成画面に戻り、タスクロール横の「更新」アイコンを押してから、作成したロールを指定します。

その後、「作成」ボタンを押すとインフラ諸々の構築が開始されます。

スクリーンショット 2025-11-22 16.07.36.png

6分ぐらいでデプロイが完了します。

画面上部の「アプリケーションURL」から、Streamlitアプリにアクセスできます。このURLはこの後すぐ利用するので、コピーしておきましょう。

この時点ではアプリがインターネット公開されているので注意してください。後続の認証画面を実装せずに途中でやめてしまうと、不特定多数の人に使われてしまう恐れがあります。

3. Cognito認証を追加する

ユーザープールを作成する

Amazon Cognitoのメニューにアクセスし、「5分未満で無料で開始できます」をクリックします。

スクリーンショット 2025-11-22 17.07.32.png

以下のみデフォルトから変更します。

  • アプリケーションに名前を付ける: simple-streamlit-chatbot
  • サインイン識別子のオプション: 「メールアドレス」にチェック
  • サインアップのための必須属性: 「email」を選択
  • リターンURL: 作ったECSアプリの「アプリケーションURL」+ /oauth2/idpresponse を入力(例: https://xxx.ecs.us-east-1.on.aws/oauth2/idpresponse

ALBにCognito認証を設定する

ECS Expressモードで作成したサービスの「リソース」タブから、ALBリスナーへジャンプします。

スクリーンショット 2025-11-22 17.19.18.png

優先度「1」のリスナールールを編集して、以下のルールを追加します。

  • 事前ルーティンアクション: ユーザーを認証
  • アイデンティティプロバイダー: Amazon Cognito
  • ユーザープールID: いま作ったものを選択
  • ユーザープールクライアントID: simple-streamlit-chatbot
  • ターゲットグループ: 上記で確認したターゲットグループ名

後はそのまま進んで保存します。

セキュリティグループを修正する

認証完了後に、ALB経由でCognitoの認証エンドポイントにアクセスできるようにするため、セキュリティグループにアウトバウンドルールを追加する必要があります。

リスナールール上部の「ロードバランサー」をクリックして、ALBに移動します。
その後、「セキュリティ」タブからセキュリティグループIDをクリックします。

スクリーンショット 2025-11-22 18.13.26.png

「アウトバウンドルール」タブに移動し、「アウトバウンドのルールを編集」します。
「ルールを追加」ボタンから、以下のルールを追加します。

  • タイプ: HTTPS
  • 送信先: Anywhare-IPv4

動作確認

これで、「アプリケーションURL」からStreamlitアプリに認証つきでアクセスできるようになります!

スクリーンショット 2025-11-22 18.19.38.png

実際に使ってみてください。

アプリを消したいときは、マネコンからECSサービスを削除するだけで、Expressモードで作成された一連のリソースをまとめて削除してくれます。便利ですね!

おまけ

今回の手順でECSとCognitoに入門できたら、以下の書籍でもっと便利なAIエージェントを作ってデプロイしてみよう💪

19
7
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
19
7

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?