AWS CDK の hotswap デプロイ (hotswap deployments) が Bedrock AgentCore Runtime に対応しました。
目次
hotswap デプロイについて
hotswap デプロイとは
hotswap デプロイ (hotswap deployments) とは、cdk deploy コマンドに --hotswap オプションを使用したデプロイのことで、CloudFormation スタックを更新する代わりに、変更するリソースを CDK 内部で AWS SDK によって直接更新することで、デプロイ時間を大幅に短縮する機能です。
npx cdk deploy --hotswap
AWS CDK は、内部で「合成」という処理を実行することで、CDK コードをもとに CloudFormation テンプレートを生成します。そして、そのテンプレートをもとに CloudFormation スタックをデプロイします。
一方で、Lambda 関数のコードやコンテナイメージの更新などアプリケーション側のファイルのみの変更を行った場合にも、CDK では CloudFormation スタックのデプロイが必要となり、デプロイに時間がかかってしまいます。
アプリケーションコードはインフラ定義に比べて変更頻度が高いことが多いため、コードの変更のたびに CloudFormation デプロイを行うことによる待ち時間は、開発体験を損なう要因となります。
そこで CDK ではこのようなケースに対応するために、hotswap デプロイ機能を提供しています。hotswap デプロイを使用すると、Lambda 関数のコードやコンテナイメージの更新などアプリケーション側のファイルのみの変更の際に、CloudFormation のデプロイ処理を行わずに直接リソースを更新することができます。そのため、デプロイ時間を大幅に短縮でき、開発サイクルが迅速化されます。
しかし、この hotswap は Lambda 関数のコードアセットや ECS のイメージアセットなど、一部のリソースの特定の変更に対してのみ対応しています。対応リソースなどの詳細については公式ドキュメントをご参照ください。
hotswap デプロイの仕組み
hotswap デプロイでは、まず最初に合成処理が実行され、実装した CDK コードを元に CloudFormation テンプレートが生成されます。
次に、そのテンプレートと、実際にデプロイ済みのスタックのテンプレートとの差分を取得します。
差分のあるリソースのプロパティが hotswap 対応のものだった場合、AWS SDK の Get 系の API を使って現在の設定値を取得します。そして、今回生成したテンプレートの情報と AWS SDK で取得した情報を合わせて、最終的に AWS SDK の Update 系の API で差分を更新します。
Bedrock AgentCore Runtime の hotswap 対応
AWS CDK CLI の v2.1102.0 で、hotswap デプロイが Bedrock AgentCore Runtime に対応しました。
実はこちらの機能ですが、私が対応しました。
今までの CDK コントリビュートの中で指折りの大変さでした。特に CDK の機能や実装に関係ないところ(依存関係や integ テスト)でかなり詰まりました。。。
ちなみに CDK は Construct ライブラリのリポジトリと CLI のリポジトリに分かれているのですが、本機能は CLI リポジトリ側の実装になります。
Bedrock AgentCore Runtime での hotswap デプロイの使い方
Bedrock AgentCore Runtime は、ランタイムのソースとしてコンテナイメージ(ECR)、またはコードファイル(S3)をサポートしています。(2026 年 1 月現在、S3 は Python のみ対応)
今回導入した hotswap デプロイは、ECR と S3 のどちらの更新にも対応しています。
バージョン
aws-cdk のバージョンを v2.1102.0 以降にアップデートしてください。
※ aws-cdk が CDK CLI、aws-cdk-lib が Construct ライブラリで、今回の hotswap 機能は CLI 側の機能であるためです。
※ aws-cdk-lib や @aws-cdk/aws-bedrock-agentcore-alpha も忘れずにインストールされていることを確認してください。
package.json の例:
"devDependencies": { // ..., // ..., "aws-cdk": "2.1102.0" }, "dependencies": { "@aws-cdk/aws-bedrock-agentcore-alpha": "^2.235.0-alpha.0", "aws-cdk-lib": "2.235.0",
ECR ソースの実装例
まずは、コンテナイメージを使う場合の実装例です。
AgentRuntimeArtifact.fromAsset メソッドによって、ローカルの Dockerfile をビルドし、自動で CDK 管理の ECR にプッシュしてくれて、それを Runtime のソースに指定することができます。
※ 事前に ArtifactDirectory ディレクトリにアプリケーションコードや Dockerfile を用意する必要がありますが本記事では割愛します。
const runtimeArtifact = AgentRuntimeArtifact.fromAsset(path.join(__dirname, 'ArtifactDirectory')); const runtimeECR = new Runtime(this, 'RuntimeECR', { runtimeName: 'runtime_ecr', description: 'Runtime', agentRuntimeArtifact: runtimeArtifact, environmentVariables: { LOG_LEVEL: 'INFO', }, });
S3 ソースの実装例
次は、コードファイルを使う場合の実装例です。
まず、aws-cdk-lib/aws-s3-assets モジュールの Asset コンストラクトを使って、ローカルのコードファイルを S3 にアップロードします。
そして、AgentRuntimeArtifact.fromS3 メソッドによって、その S3 のオブジェクトを Runtime のソースに指定することができます。
const asset = new Asset(this, 'CodeAsset', { path: path.join(__dirname, 'ArtifactDirectory'), }); const runtimeArtifact = AgentRuntimeArtifact.fromS3( { bucketName: asset.s3BucketName, objectKey: asset.s3ObjectKey, }, AgentCoreRuntime.PYTHON_3_13, ['app.py'], ); const runtimeS3 = new Runtime(this, 'RuntimeS3', { runtimeName: 'runtime_s3', agentRuntimeArtifact: runtimeArtifact, description: 'Runtime', environmentVariables: { LOG_LEVEL: 'INFO', }, });
hotswap デプロイの実行
上記のように CDK の実装が済み、まずは --hotswap オプションなしでデプロイします。
※本例では S3 ソースを使用した CDK コードの場合を示しますが、ECR ソースの場合も同様です。
npx cdk deploy
次に、CDK コードでなくアプリケーションコードのみに変更を加えます。
その後、hotswap デプロイを行う前に、試しに cdk diff コマンドを実行してみましょう。
npx cdk diff
すると、以下のように、Runtime リソースの AgentRuntimeArtifact に対して差分があることが確認できるはずです。AgentRuntimeArtifact は hotswap 対応のプロパティなので、hotswap デプロイを実行することができます。
[~] AWS::BedrockAgentCore::Runtime RuntimeS3 RuntimeS39E2E9695
└─ [~] AgentRuntimeArtifact
└─ [~] .CodeConfiguration:
└─ [~] .Code:
└─ [~] .S3:
└─ [~] .Prefix:
├─ [-] a18dede8bbfbfc4db1d3a434052cab2fe8ea82c01a945a1d66127d63b5523299.zip
└─ [+] f2793197e0247f4f89ebcf16787e78399b4de6c255ff8e57d7d1766ac38d4113.zip
そして、 --hotswap オプションを付けてデプロイを実行します。
npx cdk deploy --hotswap
以下のように hotswapped! というようなメッセージが出力されると、hotswap デプロイが成功しています。デプロイにかかる時間は、hotswap デプロイではない場合に比べて大幅に短縮されているはずです。
✨ Synthesis time: 3.45s ⚠️ The --hotswap and --hotswap-fallback flags deliberately introduce CloudFormation drift to speed up deployments ⚠️ They should only be used for development - never use them for your production Stacks! CdkSampleStack: start: Building CdkSampleStack Template CdkSampleStack: success: Built CdkSampleStack Template CdkSampleStack: start: Publishing CdkSampleStack Template (current_account-us-east-1-2ad80d58) CdkSampleStack: success: Published CdkSampleStack Template (current_account-us-east-1-2ad80d58) CdkSampleStack: deploying... [1/1] ✨ hotswapping resources: ✨ AWS::BedrockAgentCore::Runtime 'runtime_s3-iImLoZB224' ✨ AWS::BedrockAgentCore::Runtime 'runtime_s3-iImLoZB224' hotswapped!
hotswap に対応する Bedrock AgentCore Runtime プロパティ
hotswap デプロイに対応している Bedrock AgentCore Runtime のプロパティは以下の通りです。
つまり、以下のプロパティに変更があった場合にのみ、hotswap デプロイが実行されます。
agentRuntimeArtifactdescriptionenvironmentVariables
その他のプロパティの変更も含む場合、上記のプロパティに対する変更のみが hotswap デプロイで適用され、その他のプロパティの変更は無視されます。
--hotswap-fallback オプションを使用すると、完全な CloudFormation デプロイにフォールバックすることができます。
npx cdk deploy --hotswap-fallback
ちなみに、Lambda の hotswap 対応プロパティに合わせて、これらの 3 つのプロパティにしました。
内部実装的には対象プロパティはいくらでも増やせるのですが、あまり変更頻度が高くないプロパティを対象にするのも旨みが少ないため、シンプルに Lambda と同じく必要最低限のプロパティに絞りました。
もし対象にして欲しいプロパティがあれば、変更も検討するので教えてください。
hotswap デプロイの注意点
本番環境での使用は厳禁
この一見便利な hotswap デプロイですが、本番環境では使用しないようにする必要があります。
なぜなら、hotswap デプロイは CloudFormation スタックに意図的にドリフト(テンプレートと実際のリソースの状態の不一致)を発生させるため、後で CloudFormation スタックを更新しようとしたときに予期せぬ挙動が発生する可能性があるからです。
そのため、開発環境での開発速度を向上させるために hotswap デプロイを使用しましょう。
トークンに注意
例えば、S3 ソースとして定義する場合に、以下のように BucketDeployment と Source.asset() を使うと hotswap が動作しません。
const bucket = new Bucket(this, 'CodeBucket'); // ❌ Not recommended (hotswap doesn't work) const deployment = new aws_s3_deployment.BucketDeployment(this, 'Deploy', { sources: [aws_s3_deployment.Source.asset(path.join(__dirname, 'agent-code'))], destinationBucket: bucket, extract: false, }); const agentRuntimeArtifact = AgentRuntimeArtifact.fromS3( { bucketName: bucket.bucketName, objectKey: cdk.Fn.select(0, deployment.objectKeys), // Token, resolved at deployment time }, AgentCoreRuntime.PYTHON_3_13, ['app.py'], );
ここで生成される objectKey はトークンという、合成時には値が解決しない、デプロイ時に解決されるような情報です。CloudFormation テンプレート上では Fn::GetAtt や Ref などの関数を使って表現されます。
その場合、変更したコードファイルをアップロードしても、CloudFormation テンプレート上の Runtime の S3 情報を指定するプロパティの値は Fn::GetAtt などの関数を使った値のまま差分が発生しないため、hotswap が動作しないのです。そのため、上記のように Asset コンストラクトを利用してください。
"AgentRuntimeArtifact": { "CodeConfiguration": { "Code": { "S3": { "Bucket": { "Ref": "CodeBucketFF4C7AD6" }, "Prefix": { "Fn::Select": [ 0, { "Fn::GetAtt": [ "DeployCustomResource218AF6A4", "SourceObjectKeys" ] } ] } } },
このように、もし hotswap が実行されない場合、トークンでないかどうかを確認してみてください。
具体的には、CDK で生成される CloudFormation テンプレートを見て、Fn::GetAtt など変更しても値が変わらないものなのか確認してみましょう。
deploy-time-build をご利用の方へ
Bedrock AgentCore Runtime は現時点では arm64 プラットフォームにのみ対応しています。
しかし、Runtime を ECR ソースで利用したいとき、Windows マシンなどの環境でコンテナイメージのビルドができない、もしくは QEMU 対応があるけど遅いなどでお困りの人もいるかと思います。
そんな方で、友岡さんの deploy-time-build を使用して対応している方を私の観測範囲でもお見かけします。
しかし、hotswap デプロイは、残念ながら deploy-time-build を使用しているケースでは動作しません。
こちらのライブラリが返すイメージの URI も先ほど説明した例と同じくトークンであり、CloudFormation テンプレート上のプロパティが Fn::GetAtt などの関数を使った値になるため、hotswap デプロイが動作しないのです。
"RuntimeECR95F212C2": { "Type": "AWS::BedrockAgentCore::Runtime", "Properties": { "AgentRuntimeArtifact": { "ContainerConfiguration": { "ContainerUri": { "Fn::Join": [ "", [ { "Fn::Select": [ 4, { "Fn::Split": [ ":", { "Fn::GetAtt": [ "ImageRepositoryD8036990", "Arn" ] } ] } ] }, ".dkr.ecr.", { "Fn::Select": [ 3, { "Fn::Split": [ ":", { "Fn::GetAtt": [ "ImageRepositoryD8036990", "Arn" ] } ] } ] }, ".", { "Ref": "AWS::URLSuffix" }, "/", { "Ref": "ImageRepositoryD8036990" }, ":", { "Fn::GetAtt": [ "Image9D742C96", "ImageTag" ] } ] ] } } },
もっと便利に
S3 をソースとして使う場合、いちいち自前で Asset コンストラクトを呼び出す手間は面倒ですよね。
実は、それを解消するプルリクエストを今 AWS CDK に出しています。
これがマージされると、以下のように AgentRuntimeArtifact.fromCodeAsset メソッドを使って、コードファイルのディレクトリパスを指定するだけで S3 にアップロードしてくれるようになります。
const runtimeArtifact = agentcore.AgentRuntimeArtifact.fromCodeAsset({ path: path.join(__dirname, 'ArtifactDirectory'), runtime: agentcore.AgentCoreRuntime.PYTHON_3_13, entrypoint: ['app.py'], });
最後に
もしバグがあったら教えていただけると助かります。すぐに直します。