cdk-local (cdkl) で Bedrock AgentCore Runtime のローカル開発体験を試してみた
はじめに
go-to-k/cdk-local (以下 cdkl) に Bedrock AgentCore Runtime のローカル実行サブコマンド start-agentcore が追加されました。あわせて AWS CDK の --hotswap も AgentCore Runtime に対応しています。
start-agentcore の特徴は、CDK コードからランタイム設定を自動取得し、Docker でローカルにコンテナを起動する点です。AWS リソースを更新しないため、CloudFormation ドリフトは発生しません。AgentCore Runtime の実行に伴う追加コストもかかりません。動かしてみたら壊れた、ということがクラウド側に波及しない安心感があります。
本記事では cdkl によるローカル実行の使い勝手と、--from-cfn-stack・--assume-role といった独自機能の動作を確認しました。参考として、hotswap・通常デプロイとの速度比較も載せています。
cdkl や hotswap は開発用です。本番反映には通常 cdk deploy を使ってください。
以前、同じ作者の cdkd について以下の記事を書きました。
hotswap の AgentCore Runtime 対応については以下で解説されています。
検証環境と準備
環境
検証時点(2026年6月)のバージョンです。
| 項目 | 値 |
|---|---|
| EC2 | t4g.medium (ARM64), Amazon Linux 2023 |
| リージョン | us-east-1 |
| Node.js | v22.22.3 |
| CDK CLI | 2.1126.0 |
| cdk-local | 0.139.3 |
| Docker | 25.0.14 |
| IAM ロール | AdministratorAccess + AmazonSSMManagedInstanceCore(検証用) |
本記事では検証簡略化のため AdministratorAccess を使用しています。実運用・共有環境では必要最小権限に絞ってください。
検証環境の構築には CloudFormation テンプレートを使用しました(付録に全文を掲載)。
アプリコード (agent-code/main.py)
AgentCore Runtime アプリはポート 8080 で /ping (GET) と /invocations (POST) を実装する必要があります。環境変数 GREETING の値をレスポンスで返すシンプルなアプリです。
from http.server import HTTPServer, BaseHTTPRequestHandler
import json, os
VERSION = "AAA"
class Handler(BaseHTTPRequestHandler):
def do_GET(self):
if self.path == '/ping':
self.send_response(200)
self.end_headers()
return
self.send_response(404)
self.end_headers()
def do_POST(self):
if self.path == '/invocations':
greeting = os.environ.get('GREETING', 'NOT_SET')
resp = json.dumps({"greeting": greeting, "version": VERSION})
self.send_response(200)
self.send_header('Content-Type', 'application/json')
self.end_headers()
self.wfile.write(resp.encode())
return
self.send_response(404)
self.end_headers()
if __name__ == '__main__':
server = HTTPServer(('0.0.0.0', 8080), Handler)
server.serve_forever()
CDK スタック (lib/agentcore-app-stack.ts)
SSM パラメータから環境変数を取得し、AgentCore Runtime に渡します。
import * as cdk from 'aws-cdk-lib';
import { Construct } from 'constructs';
import * as agentcore from 'aws-cdk-lib/aws-bedrockagentcore';
import * as ssm from 'aws-cdk-lib/aws-ssm';
import * as path from 'path';
export class AgentcoreAppStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
const greeting = ssm.StringParameter.valueForStringParameter(this, '/cdkl-test/greeting');
const artifact = agentcore.AgentRuntimeArtifact.fromCodeAsset({
path: path.join(__dirname, '..', 'agent-code'),
runtime: agentcore.AgentCoreRuntime.PYTHON_3_12,
entrypoint: ['main.py'],
});
new agentcore.Runtime(this, 'HelloAgent', {
runtimeName: 'helloAgent',
agentRuntimeArtifact: artifact,
environmentVariables: {
GREETING: greeting,
},
});
}
}
CDK プロジェクトの初期化
mkdir agentcore-app && cd agentcore-app
cdk init app --language typescript
npm install aws-cdk-lib constructs
SSM パラメータの作成とデプロイ
aws ssm put-parameter --name /cdkl-test/greeting --type String --value "Hello from SSM!" --overwrite --region us-east-1
cdk bootstrap --region us-east-1
cdk deploy --region us-east-1
cdkl start-agentcore によるローカル実行
基本動作
start-agentcore はコンストラクトパスを指定するだけで起動できます。CDK コードからコードパス・ランタイム・エントリポイントを自動取得するため、個別に指定する必要がありません。
cdkl start-agentcore AgentcoreAppStack/HelloAgent --port 8080
コンテナが起動したら /invocations にリクエストします。
curl -s -X POST http://localhost:8080/invocations | jq .
{"greeting": "NOT_SET", "version": "AAA"}
AWS に一切触れず、ローカルだけで動作確認ができました。GREETING はデフォルト値の NOT_SET になっています。cdkl はクラウド上の SSM パラメータを読みに行かないためです。
warm container として繰り返し利用
start-agentcore はコンテナを起動したまま保持します。コードを修正して確認したいときは Ctrl+C で停止して再起動するか、--watch オプションでソース変更時に自動リロードできます。invoke-agentcore(ワンショット実行)とは異なり、繰り返しリクエストを送って動作確認できる設計です。
--from-cfn-stack(デプロイ済みスタックの環境変数を注入)
--from-cfn-stack を指定すると、デプロイ済みの CloudFormation スタックから環境変数の値を取得してローカルコンテナに渡します。SSM パラメータや Ref/Export の解決済みの値がそのまま注入されるため、.env ファイルを手動で管理する必要がありません。
スタック名はターゲットのコンストラクトパスから自動解決されるため、引数なしの --from-cfn-stack だけで動作します。CDK の stackName prop でスタック名を変更している場合のみ --from-cfn-stack MyExplicitCfnName のように明示指定が必要です。
cdkl start-agentcore AgentcoreAppStack/HelloAgent --port 8080 \
--from-cfn-stack --region us-east-1
curl -s -X POST http://localhost:8080/invocations | jq .
{"greeting": "Hello from SSM!", "version": "AAA"}
| モード | GREETING の値 |
|---|---|
| オプションなし | NOT_SET |
--from-cfn-stack |
Hello from SSM! |
SSM パラメータに設定した値がローカルコンテナに注入されました。このオプションは CloudFormation / SSM への読み取りアクセスが発生するため、AWS 認証情報と --region の指定が必要です。
--assume-role(実行ロールの切り替え)
--assume-role を使うと、Runtime 実行ロールに切り替えた状態でローカルコンテナを起動できます。アプリが AWS SDK を呼ぶ場合に、本番と同じ権限で動作確認ができます。
cdkl start-agentcore AgentcoreAppStack/HelloAgent --port 8080 \
--assume-role "arn:aws:iam::<ACCOUNT_ID>:role/<RUNTIME_EXECUTION_ROLE>" \
--region us-east-1
| モード | 実行ロール |
|---|---|
| オプションなし | cdkl-test-ec2-role (EC2 ロール) |
--assume-role |
AgentcoreAppStack-HelloAgentExecutionRoleB1EEC5C6-* |
--assume-role を使うには、指定するロールの信頼ポリシーに開発者ロールからの AssumeRole を許可する設定が必要です。検証では、既存の信頼ポリシーを確認した上で開発用 EC2 ロールからの AssumeRole 許可を追加しました。
以下は検証環境専用の例です。本番用ロールには適用しないでください。
# Runtime実行ロール名を取得
RUNTIME_ROLE=$(aws cloudformation describe-stack-resources \
--stack-name AgentcoreAppStack --region us-east-1 \
--query "StackResources[?LogicalResourceId=='HelloAgentExecutionRole'].PhysicalResourceId" \
--output text)
ACCOUNT_ID=$(aws sts get-caller-identity --query Account --output text)
aws iam update-assume-role-policy --role-name "$RUNTIME_ROLE" \
--policy-document "{
\"Version\": \"2012-10-17\",
\"Statement\": [
{\"Effect\": \"Allow\", \"Principal\": {\"Service\": \"bedrock.amazonaws.com\"}, \"Action\": \"sts:AssumeRole\"},
{\"Effect\": \"Allow\", \"Principal\": {\"AWS\": \"arn:aws:iam::${ACCOUNT_ID}:role/cdkl-test-ec2-role\"}, \"Action\": \"sts:AssumeRole\"}
]
}"
cdkl のメリットまとめ
| 観点 | cdkl start-agentcore |
|---|---|
| AWS リソース更新 | なし(ドリフトが原理的に発生しない) |
| AgentCore Runtime 追加コスト | なし(Docker ローカル実行のため AgentCore の実行課金が発生しない) |
| 設定の同期 | CDK コードから自動取得(乖離しない) |
| 環境変数 | --from-cfn-stack でデプロイ済みスタックから注入 |
| 実行ロール | --assume-role で本番ロールを模倣 |
| ホットリロード | --watch でソース変更時に自動再起動 |
| 失敗時の影響 | ローカルのみ。クラウド環境に変更を加えない |
デプロイ速度比較(参考)
3手法で4回ずつ計測しました。cdkl はローカルでレスポンス取得まで、hotswap / 通常 deploy は CLI 完了までを計測範囲としています。
| 手法 | 平均 | ドリフト |
|---|---|---|
cdkl start-agentcore (ローカル) |
13.7秒 | なし |
cdk deploy --hotswap |
14.0秒 | あり |
cdk deploy (通常) |
12.7秒 | なし |
個別測定値
cdkl: 13850ms, 13328ms, 13941ms, 13761ms → 平均 13,720ms
hotswap: 14146ms, 14069ms, 13788ms, 14183ms → 平均 14,047ms
normal: 12528ms, 12752ms, 12852ms, 12819ms → 平均 12,738ms
検証時点(CDK 2.1126.0)では3手法ともほぼ同速でした。
以前の計測値(CDK 2.1125.0 / cdk-local 0.105.0)
実は1つ前の CDK バージョン(2.1125.0)で同じ検証を行った際は、通常 deploy に 35秒かかっていました。
| 手法 | CDK 2.1125.0 | CDK 2.1126.0 | 変化 |
|---|---|---|---|
| cdkl | 16.8秒 | 13.7秒 | -18% |
| hotswap | 15.2秒 | 14.0秒 | -8% |
| 通常 deploy | 35.1秒 | 12.7秒 | -64% |
CDK 2.1125.0 時点では cdkl・hotswap が通常 deploy の約2倍速く、ローカル実行や hotswap の速度的な優位性が明確でした。CDK 2.1126.0 で通常 deploy の CloudFormation 処理が大幅に高速化されたことで、速度差はほぼ解消されています。
なお、hotswap の AgentCore Runtime 対応は cdkl の作者である go-to-k さんが AWS CDK CLI に直接貢献した機能です(aws/aws-cdk-cli#991)。CDK スタックで使用している AgentRuntimeArtifact.fromCodeAsset メソッドも同氏による貢献です(aws/aws-cdk#36472)。一方、通常 deploy の高速化についてはサービス側の変更によるものと推測されますが、本記事では原因を断定しません。
cdkl の価値は速度よりも、AWS に触れずにローカルで完結する安全性と、--from-cfn-stack / --assume-role / --watch による開発体験の快適さにあります。通常 deploy がどれだけ速くなっても、「クラウドに触らずに確認できる」というメリットは変わりません。
hotswap のドリフト
参考として hotswap のドリフト挙動も確認しました。hotswap は CloudFormation スタック更新を行わず実リソースを直接更新するため、管理状態と実リソースがずれます。
cdk deploy --hotswap --region us-east-1
✨ AWS::BedrockAgentCore::Runtime 'helloAgent-fksMu1GelV' hotswapped!
実際のエンドポイントは新コードで動作していましたが、cdk diff では差分として表示されませんでした。
cdk diff --region us-east-1
Stack AgentcoreAppStack
There were no differences
hotswap は開発環境への迅速な反映に有効ですが、ドリフトを許容する前提で使う必要があります。
使い分け
| フェーズ | 推奨手法 | 理由 |
|---|---|---|
| ハンドラー実装中 | cdkl start-agentcore |
ローカル完結。失敗してもクラウドに影響なし。--watch で変更即反映 |
| 環境変数やロール込みで確認 | cdkl + --from-cfn-stack / --assume-role |
クラウド定義に近い条件でローカルテスト |
| 開発環境への反映 | cdk deploy --hotswap |
実リソースを直接更新(ドリフトあり) |
| 共有環境・本番 | cdk deploy |
CloudFormation 管理状態を維持 |
ローカル開発では cdkl でイテレーションを回し、動作が固まったら hotswap や通常 deploy でクラウドに反映するのが自然な流れです。速度差がほぼないため、使い分けの基準は「AWS に触るか触らないか」「ドリフトを許容するか」になります。
まとめ
cdkl の start-agentcore を使うことで、AgentCore Runtime をローカルで素早く動作確認できることを確認しました。
コンストラクトパスを指定するだけで CDK 定義からランタイム設定を自動取得してくれるため、ローカル実行の設定が CDK コードと乖離する心配がありません。--from-cfn-stack で環境変数を注入し、--assume-role でロールを切り替えれば、クラウド環境に近い条件でのテストもローカルで完結します。
今回は AgentCore Runtime のみで試しましたが、cdkl は Lambda / API Gateway / ECS / ALB / CloudFront などもサポートしています。ローカルで動作確認してからクラウドに反映する開発スタイルに興味がある方は、試してみてください。
付録: 検証環境の CloudFormation テンプレート
このテンプレートは検証用です。AdministratorAccess を付与しているため、共有環境・本番環境ではそのまま使用しないでください。
cfn-ec2-cdkl-agentcore.yaml(クリックで展開)
AWSTemplateFormatVersion: '2010-09-09'
Description: EC2 (ARM64) for cdkl + AgentCore development (SSM only, no SSH)
Resources:
Role:
Type: AWS::IAM::Role
Properties:
RoleName: cdkl-test-ec2-role
AssumeRolePolicyDocument:
Version: '2012-10-17'
Statement:
- Effect: Allow
Principal:
Service: ec2.amazonaws.com
Action: sts:AssumeRole
ManagedPolicyArns:
- arn:aws:iam::aws:policy/AdministratorAccess
- arn:aws:iam::aws:policy/AmazonSSMManagedInstanceCore
InstanceProfile:
Type: AWS::IAM::InstanceProfile
Properties:
InstanceProfileName: cdkl-test-ec2-profile
Roles:
- !Ref Role
Instance:
Type: AWS::EC2::Instance
Properties:
ImageId: !Sub '{{resolve:ssm:/aws/service/ami-amazon-linux-latest/al2023-ami-kernel-default-arm64}}'
InstanceType: t4g.medium
IamInstanceProfile: !Ref InstanceProfile
BlockDeviceMappings:
- DeviceName: /dev/xvda
Ebs:
VolumeSize: 30
VolumeType: gp3
Tags:
- Key: Name
Value: cdkl-agentcore-dev
UserData:
Fn::Base64: |
#!/bin/bash
set -ex
# Node.js 22
curl -fsSL https://rpm.nodesource.com/setup_22.x | bash -
dnf install -y nodejs docker git tmux unzip
# Docker
systemctl enable docker && systemctl start docker
usermod -aG docker ec2-user
# CDK + cdk-local
npm install -g aws-cdk cdk-local
Outputs:
InstanceId:
Value: !Ref Instance
SsmCommand:
Value: !Sub 'aws ssm start-session --target ${Instance} --region ${AWS::Region}'










