はじめに
先日、AWS Amplify HostingのCI/CDからCloudFromationでAgentCore Runtimeを含むAIチャットアプリをデプロイしてみました。
その際、AgentCore RuntimeへデプロイするAIエージェントのソースコードはコンテナ上を指定していました。
今回は、S3バケットから直接コードをデプロイがどうやらCloudFormationでも対応したようなので、試してみたいと思います。
概要
おさらい
今回もデプロイする構成は以下となります。
AgentCore Runtimeがコンテナでなくとも直接コードをデプロイできるようになった!
11/5にAgentCore RuntimeのソースコードをS3から指定できるようになりました。
直接コードデプロイは、ソースコードのパッケージサイズが「250 MB」という制限があるようです。
コンテナの場合は、1GBまでいけるようなので、構築するAIエージェントの規模によって、選択するのが良さげです。pip installする依存パッケージのボリューム次第な気がします。
AWS Amplify HostingのCI/CDイメージ
CodeBuildやECRを経由しなくなったため、だいぶシンプルなフローになりました。
元Mermaid
CloudFormationの場合どうやるか
元々「AWS::BedrockAgentCore::Runtime AgentRuntimeArtifact」に指定できるのは「ContainerConfiguration」だけだったのですが、「CodeConfiguration」が追加されていました。
ここにS3バケットを指定してあげます。
やってみる
前提:デプロイするエージェント by StrandsAgents
import os, logging
from bedrock_agentcore.runtime import BedrockAgentCoreApp
from strands import Agent
from strands.models import BedrockModel
from strands_tools import current_time
from system_prompt import test_system_prompt
log = logging.getLogger("SampleAgent")
logging.basicConfig(level=logging.INFO)
MODEL_ID = os.environ.get("MODEL_ID")
REGION = os.environ.get("REGION")
app = BedrockAgentCoreApp()
@app.entrypoint
async def invoke(payload):
user_prompt = payload.get("prompt", "No prompt found in input, please guide customer to create a json payload with prompt key")
agent = create_agent()
agent_stream = agent.stream_async(user_prompt)
async for event in agent_stream:
if "event" in event:
yield event
if __name__ == "__main__":
app.run()
前回のコンテナデプロイから以下のCFnテンプレートは不要になりました!
- ECR (コンテナイメージ用)
- CodeDeploy (Dockerビルド用)
CFnテンプレートの作成
代わりに以下のAgentCoreのRuntimeにS3バケットを指定しています。
AgentRuntimeArtifact:
CodeConfiguration:
Code:
S3:
Bucket: !Sub "${NamePrefix}-source-bucket"
Prefix: "source.zip"
EntryPoint:
- "main.py"
Runtime: "PYTHON_3_13"
また、今回の対応にあたり、zip化する際にpython-platformを指定する必要があります。
# ソースコードをZIP化してS3にアップロード
- cd agent
- mkdir -p deployment_package
- |
uv pip install \
--python-platform aarch64-manylinux2014 \
--python-version 3.13 \
--target=deployment_package \
--only-binary=:all: \
-r requirements.txt
- cp main.py system_prompt.py deployment_package/
- cd deployment_package
- zip -r ../source.zip .
- cd ..
- aws s3 cp source.zip s3://${NAME_PREFIX}-source-bucket/source.zip
- cd ../
というわけでCFnテンプレートはAgentCore Runtime と S3バケットのみになりました。
S3バケット
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
NamePrefix:
Type: String
Resources:
SourceBucket:
Type: AWS::S3::Bucket
Properties:
BucketName: !Sub '${NamePrefix}-source-bucket'
VersioningConfiguration:
Status: Enabled
PublicAccessBlockConfiguration:
BlockPublicAcls: true
BlockPublicPolicy: true
IgnorePublicAcls: true
RestrictPublicBuckets: true
Outputs:
SourceBucketName:
Value: !Ref SourceBucket
AgentCore Runtime
AWSTemplateFormatVersion: '2010-09-09'
Parameters:
NamePrefix:
Type: String
CognitoUserPoolId:
Type: String
CognitoUserPoolClientId:
Type: String
BuildTimestamp:
Type: String
Resources:
# AgentCoreの実行ロール
AgentCoreExecutionRole:
Type: AWS::IAM::Role
Properties:
RoleName: !Sub ${NamePrefix}-runtime-role
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: bedrock-agentcore.amazonaws.com
Action: sts:AssumeRole
Policies:
- PolicyName: CloudWatchLogsAccess
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: "CloudWatchLogs"
Effect: Allow
Action:
- logs:CreateLogGroup
- logs:CreateLogStream
- logs:PutLogEvents
- logs:DescribeLogGroups
- logs:DescribeLogStreams
Resource: "*"
- PolicyName: BedrockModelInvocation
PolicyDocument:
Version: '2012-10-17'
Statement:
- Sid: "BedrockModelInvocation"
Effect: Allow
Action:
- bedrock:InvokeModel
- bedrock:InvokeModelWithResponseStream
Resource:
- arn:aws:bedrock:*::foundation-model/*
- arn:aws:bedrock:*:*:inference-profile/*
# Amazon Bedrock AgentCore Runtime リソース
AgentCoreRuntime:
Type: AWS::BedrockAgentCore::Runtime
Properties:
AgentRuntimeName: "vite_agent_runtime_v2"
AgentRuntimeArtifact:
CodeConfiguration:
Code:
S3:
Bucket: !Sub "${NamePrefix}-source-bucket"
Prefix: "source.zip"
EntryPoint:
- "main.py"
Runtime: "PYTHON_3_13"
ProtocolConfiguration: HTTP # HTTP or MCP
NetworkConfiguration:
NetworkMode: PUBLIC # VPC or PUBLIC
AuthorizerConfiguration:
CustomJWTAuthorizer:
AllowedClients:
- !Sub "${CognitoUserPoolClientId}"
DiscoveryUrl: !Sub "https://cognito-idp.${AWS::Region}.amazonaws.com/${CognitoUserPoolId}/.well-known/openid-configuration"
EnvironmentVariables:
MODEL_ID: "jp.anthropic.claude-haiku-4-5-20251001-v1:0"
REGION: "ap-northeast-1"
BUILD_TIMESTAMP: !Ref BuildTimestamp
RoleArn: !GetAtt AgentCoreExecutionRole.Arn
あとは、AWSマネジメントコンソ
amplify.ymlの作成
Amplify Hostingでは、「amplify.yml」の内容に従って、デプロイが実行されます。
ということで、先ほど説明したフローに従いファイルを作成します。
version: 1
appRoot: .
env:
variables:
AMPLIFY_DIFF_DEPLOY: false
NAME_PREFIX: vite-agentcore-app-dev3
backend:
phases:
preBuild:
commands:
# uvをインストール
- curl -LsSf https://astral.sh/uv/install.sh | sh
- export PATH="$HOME/.local/bin:$PATH"
# S3バケットをデプロイ
- cd cfn
- |
aws cloudformation deploy \
--stack-name ${NAME_PREFIX}-s3-stack \
--template-file s3.yaml \
--parameter-overrides \
NamePrefix=${NAME_PREFIX} \
--capabilities CAPABILITY_NAMED_IAM \
--region ${REGION} \
--no-fail-on-empty-changeset
- cd ../
build:
commands:
- export PATH="$HOME/.local/bin:$PATH"
# Lambdaの依存ライブラリをインストール
- cd frontend/amplify/functions/sseFunction
- npm ci --cache .npm --prefer-offline
- cd ../../../
# Amplifyのバックエンドをデプロイ
- ls
- npm ci --cache .npm --prefer-offline
- npx ampx pipeline-deploy --branch $AWS_BRANCH --app-id $AWS_APP_ID
# amplify_outputs.jsonの存在確認
- |
if [ ! -f "amplify_outputs.json" ]; then
echo "amplify_outputs.json not found"
exit 1
fi
# amplify_outputs.jsonからCognitoのID情報を取得
- |
COGNITO_USER_POOL_ID=$(node -e \
"console.log(JSON.parse(\
require('fs').readFileSync(\
'amplify_outputs.json')).auth.user_pool_id)")
- |
COGNITO_USER_POOL_CLIENT_ID=$(node -e \
"console.log(JSON.parse(\
require('fs').readFileSync(\
'amplify_outputs.json')).auth.user_pool_client_id)")
- echo "COGNITO_USER_POOL_ID=${COGNITO_USER_POOL_ID}"
- echo "COGNITO_USER_POOL_CLIENT_ID=${COGNITO_USER_POOL_CLIENT_ID}"
- cd ../
# ソースコードをZIP化してS3にアップロード
- cd agent
- mkdir -p deployment_package
- |
uv pip install \
--python-platform aarch64-manylinux2014 \
--python-version 3.13 \
--target=deployment_package \
--only-binary=:all: \
-r requirements.txt
- cp main.py system_prompt.py deployment_package/
- cd deployment_package
- zip -r ../source.zip .
- cd ..
- aws s3 cp source.zip s3://${NAME_PREFIX}-source-bucket/source.zip
- cd ../
# AgentCore Runtimeをデプロイ
- cd cfn
- BUILD_TIMESTAMP=$(date +%Y%m%d-%H%M%S)
- echo "BUILD_TIMESTAMP=${BUILD_TIMESTAMP}"
- |
aws cloudformation deploy \
--stack-name ${NAME_PREFIX}-bedrock-agentcore-runtime \
--template-file agentcore.yaml \
--parameter-overrides \
NamePrefix=${NAME_PREFIX} \
CognitoUserPoolId=${COGNITO_USER_POOL_ID} \
CognitoUserPoolClientId=${COGNITO_USER_POOL_CLIENT_ID} \
BuildTimestamp=${BUILD_TIMESTAMP} \
--capabilities CAPABILITY_NAMED_IAM \
--region ${REGION} \
--no-fail-on-empty-changeset
- cd ../
frontend:
phases:
preBuild:
commands:
- cd frontend
- ls
- npm ci
# amplify_outputs.jsonからSSE関数URLを取得して.envを更新
- |
VITE_LAMBDA_ENDPOINT=$(node -e \
"console.log(JSON.parse(\
require('fs').readFileSync(\
'amplify_outputs.json')).custom.sseFunctionUrl)")
echo "VITE_LAMBDA_ENDPOINT=${VITE_LAMBDA_ENDPOINT}" > .env
build:
commands:
- npm run build
- ls
artifacts:
baseDirectory: frontend/dist
files:
- '**/*'
cache:
paths:
- frontend/node_modules/**/*
- frontend/dist/**/*
あとは、AWSマネジメントコンソールからAmplifyHostingにデプロイすれば完了です。
まとめ
今回でCICDやIaC周りがシンプルになりました!だいぶ、敷居が下がったんじゃないでしょうか。
「250MB」制限は気になりますが、PoCなどで簡単なAIエージェントを作ってみる分には気にならないと思います。CDKも対応したら今度こそCDK版でデプロイしたいと思います...


