
AWS Lambda Managed Instances を AWS CDK で実装してみた
こんにちは!製造ビジネステクノロジー部の小林です。
2025年12月に発表された AWS Lambda Managed Instances は、Lambda のサーバーレス開発体験を維持しながら、EC2 インスタンス上で Lambda 関数を実行できる新機能です。
「Lambda はサーバーレスなのに EC2 で実行?」と思われた方も多いのではないでしょうか。
この記事では、Lambda Managed Instances の仕組みや従来の Lambda との違いを整理しながら、AWS CDK を使った実装方法をご紹介します。
Lambda Managed Instances とは?
Lambda Managed Instances は、Lambda 関数を自分の AWS アカウント内の専用 EC2 インスタンスで実行できる新しいコンピューティングオプションです。
Lambda Managed Instances を使うと嬉しいこと
EC2 の料金体系でコスト最適化
従来の Lambda は実行時間に応じて課金されますが、Lambda Managed Instances では EC2 インスタンスの稼働時間に応じた課金となり、EC2 の料金モデルを適用できます。
- Reserved Instances や Savings Plans が利用可能
- 予測可能な高トラフィックワークロードでは、従来の Lambda よりコスト効率が良い場合がある
- EC2 の運用負荷(OS パッチ、スケーリング、ライフサイクル管理)なしに EC2 の料金メリットを享受できる
最新のハードウェアを選択できる
従来の Lambda では選択できなかったハードウェアオプションが利用可能です。
選択可能なハードウェア
- Graviton4(ARM64): 最新世代の高性能 CPU、優れたコストパフォーマンス
- GPU インスタンス: ML 推論、動画処理、画像生成などの GPU ワークロードに対応
- 高帯域ネットワーク: データ集約的なアプリケーション向け(C7gn など)
- 大容量メモリ: メモリ集約型ワークロード向け(R7g、X2gd など)
- ストレージ最適化: 大規模データ処理向け(I4g など)
下記のドキュメントに、Lambda Managed Instances で使用できるインスタンスが記載されています。
コールドスタートの排除
Capacity Provider を作成すると、デフォルトで3つのインスタンスが事前起動され、実行環境が準備完了した状態で待機します。
これにより、初回リクエストでもレイテンシが安定し、Provisioned Concurrency のような追加コストなしにコールドスタート問題を解決できます。
3つのコンピューティングサービスの違い
| 項目 | 従来の Lambda | EC2 | Lambda Managed Instances |
|---|---|---|---|
| 実行環境 | AWS マネージド(マルチテナント) | 自分で管理する専用インスタンス | AWS マネージド(シングルテナント) |
| 実行場所 | Firecracker microVM(共有環境) | 自分の VPC 内 | 自分の VPC 内 |
| インフラ管理 | 不要 | 必要(OS、パッチ、スケーリング) | 不要 |
| スケーリング | 自動 | 手動または Auto Scaling | 自動 |
| コールドスタート | あり | なし | なし |
| 料金モデル | 実行時間 × メモリ | インスタンス稼働時間 | リクエスト料金 + EC2 料金 + 15% 管理手数料 |
| Reserved Instance | 利用不可 | 利用可能 | 利用可能 |
| Savings Plans | Compute Savings Plans のみ利用可能 | 利用可能 | 利用可能 |
| ハードウェア選択 | 選択不可 | 自由に選択可能 | 選択可能(Graviton4、GPU など) |
| 最小メモリ | 128MB | インスタンスタイプに依存 | 2048MB(2GB)以上 |
| VPC | オプション | 必須 | 必須 |
CDK での実装
それでは、AWS CDK で実装していきます。
Capacity Provider とは?
Capacity Provider は、Lambda 関数を実行するための EC2 インスタンスプールを管理するリソースです。以下の役割を担います。
- EC2 インスタンスの自動プロビジョニング
- インスタンスのスケーリング管理
- 実行環境の事前起動(コールドスタート排除)
- インスタンスのライフサイクル管理
Capacity Provider を作成すると、AWS が自動的にインスタンスを起動・管理してくれるため、従来の Lambda と同じように関数をデプロイするだけで利用できます。
今回の構成
今回の実装では検証のため、インスタンスタイプやスケーリングを明示的に設定しています。
Capacity Provider の設定
| 項目 | 設定値 | 説明 |
|---|---|---|
| 配置場所 | Private Subnet | セキュリティのためプライベートサブネットに配置 |
| アーキテクチャ | ARM64(Graviton4) | コストパフォーマンスに優れている |
| インスタンスタイプ | m8g.large | 汎用的なワークロード向け |
スケーリング設定
| 項目 | 設定値 | 説明 |
|---|---|---|
| スケーリングモード | マニュアル | CPU 使用率に基づいて自動スケーリング |
| 目標 CPU 使用率 | 70% | この値を維持するようインスタンス数を調整 |
| スケール動作 | 自動 | CPU 使用率が 70% を超えるとインスタンスを追加、下回ると削減 |
注意点
- インスタンスタイプとスケーリング設定は省略可能です
- 省略した場合、AWS が最適な設定を自動的に選択します
lib/lambda-managed-instance-stack.ts
import * as cdk from 'aws-cdk-lib';
import * as ec2 from 'aws-cdk-lib/aws-ec2';
import * as lambda from 'aws-cdk-lib/aws-lambda';
import { NodejsFunction } from 'aws-cdk-lib/aws-lambda-nodejs';
import * as iam from 'aws-cdk-lib/aws-iam';
import * as path from 'path';
import { Construct } from 'constructs';
export class LambdaManagedInstanceStack extends cdk.Stack {
constructor(scope: Construct, id: string, props?: cdk.StackProps) {
super(scope, id, props);
/**
* VPC の作成
* Lambda Managed Instances はVPC内でEC2インスタンスを起動するため必須
* - maxAzs: 高可用性のため2つのAZを使用
* - subnetConfiguration: プライベートサブネット(Lambda用)とパブリックサブネット(NAT Gateway用)を作成
*/
const vpc = new ec2.Vpc(this, 'LambdaVpc', {
maxAzs: 2,
natGateways: 1,
subnetConfiguration: [
{
cidrMask: 24,
name: 'Private',
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
},
{
cidrMask: 24,
name: 'Public',
subnetType: ec2.SubnetType.PUBLIC,
},
],
});
/**
* Security Group の作成
* Capacity Providerが起動するEC2インスタンスに適用されるセキュリティグループ
* - すべてのアウトバウンド通信を許可
*/
const securityGroup = new ec2.SecurityGroup(this, 'LambdaSecurityGroup', {
vpc,
description: 'Security group for Lambda Managed Instance',
allowAllOutbound: true,
});
/**
* Capacity Provider の作成
* Lambda関数を実行するEC2インスタンスのプールを管理
* - subnets:(プライベートサブネットを使用)
* - architectures: ARM64(Graviton4)を使用。
* - instanceTypeFilter: m8g.large(Graviton4ベース)を指定。
*/
const capacityProvider = new lambda.CapacityProvider(this, 'MyCapacityProvider', {
capacityProviderName: 'my-lambda-capacity-provider',
subnets: vpc.selectSubnets({
subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
}).subnets,
securityGroups: [securityGroup],
/**
* アーキテクチャの指定
* ARM64(Graviton4)を使用
* Lambda関数のアーキテクチャと一致させる必要がある
* インスタンスタイプを指定する場合は必須
*/
architectures: [lambda.Architecture.ARM_64],
/**
* インスタンスタイプの指定(オプション)
* m8g.large: Graviton4ベースのインスタンス
*/
instanceTypeFilter: lambda.InstanceTypeFilter.allow([
ec2.InstanceType.of(ec2.InstanceClass.M8G, ec2.InstanceSize.LARGE),
]),
/**
* スケーリング設定(オプション)
* マニュアルモードでCPU使用率70%を目標にスケーリング
* - 目標値を下回ると自動的にインスタンスを削減
* - 目標値を上回ると自動的にインスタンスを追加
*/
scalingOptions: lambda.ScalingOptions.manual([
lambda.TargetTrackingScalingPolicy.cpuUtilization(70),
]),
});
/**
* Lambda実行用のIAMロールを作成
* VPC内でLambda関数を実行するために必要な権限を付与
* - AWSLambdaBasicExecutionRole: CloudWatch Logsへの書き込み権限
* - AWSLambdaVPCAccessExecutionRole: VPC内でのネットワークインターフェース管理権限
*/
const lambdaRole = new iam.Role(this, 'LambdaExecutionRole', {
assumedBy: new iam.ServicePrincipal('lambda.amazonaws.com'),
managedPolicies: [
iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaBasicExecutionRole'),
iam.ManagedPolicy.fromAwsManagedPolicyName('service-role/AWSLambdaVPCAccessExecutionRole'),
],
});
/**
* Lambda 関数の作成
*/
const managedInstanceFunction = new NodejsFunction(this, 'ManagedInstanceFunction', {
entry: path.join(__dirname, '../lambda/index.ts'),
handler: 'handler',
runtime: lambda.Runtime.NODEJS_22_X,
architecture: lambda.Architecture.ARM_64, // Capacity Providerと一致させる
role: lambdaRole,
timeout: cdk.Duration.seconds(10),
memorySize: 2048, // Lambda Managed Instances では 2048MB 以上が必須
});
/**
* Capacity Providerに関数を追加
* この操作により、Lambda関数がCapacity Provider上で実行されるようになる
*/
capacityProvider.addFunction(managedInstanceFunction);
}
}
上記のスタック定義では、NodejsFunction で関数を作成してから、capacityProvider.addFunction() で Capacity Provider に追加しています。
capacityProvider.addFunction() を呼ぶと、CDK が内部で以下の処理を行います。
- Lambda関数のL1リソース(
CfnFunction)を取得 CapacityProviderConfigプロパティを設定- Capacity Provider と Lambda関数を紐付ける
つまり、L2コンストラクトの便利なAPIを使い、CDKが内部でL1コンストラクトを設定してくれます。
それではデプロイしてみましょう。
トラブルシュート
デプロイ時に下記のエラーが発生しました。
エラーメッセージ
| CREATE_FAILED | AWS::Lambda::Function | ManagedInstanceFunctionB21AD5EF
Resource handler returned message: "'MemorySize' value failed to satisfy constraint: Lambda Managed Instance functions must have memory size greater than or equal to 2048 (Service: Lambda, Status Code: 400, Request ID: cc865e2c-55cf-4817-b435-b7f144d9db8d) (SDK Attempt Count: 1)" (RequestToken: a8dcb03e-5954-c5fb-2f9a-3eaebdcfdae4, HandlerErrorCode: InvalidRequest)
重要部分
'MemorySize' value failed to satisfy constraint: Lambda Managed Instance functions must have memory size greater than or equal to 2048
原因ですが、Lambda Managed Instances では 2048MB(2GB)以上のメモリサイズが必要なようです。下記のように修正してデプロイを実施しました。
const managedInstanceFunction = new NodejsFunction(this, 'ManagedInstanceFunction', {
memorySize: 2048, // メモリサイズを 2048 以上を指定
});
デプロイ後の確認
デプロイが完了したら、AWSマネジメントコンソールから作成されたリソースを確認してみます。
Capacity Provider の確認
AWS マネジメントコンソール > Lambda > Capacity providers から確認できます。
Capacity Provider 詳細画面

作成した my-lambda-capacity-provider が Active 状態になっていますね。
モニタリング画面では、Capacity Provider のメトリクスが確認できます。


Lambda関数の確認
Capacity Provider の詳細画面 > 「関数のバージョン」タブ から、紐付けられた Lambda関数が確認できます。
Lambda 関数のコンソールからテストイベントを実行してみます。

テストが成功しました!

EC2インスタンスの確認
EC2 > インスタンス から、Capacity Provider が自動的に起動した EC2インスタンスを確認できます。

キャパシティープロバイダーを使用して関数バージョンを公開すると、Lambda はアカウントでマネージドインスタンスを起動します。AZ の回復性を確保するために、デフォルトで 3 つのインスタンスが起動され、関数バージョンが ACTIVE になる前に 3 つの実行環境が起動されます。
公式ドキュメントでは「デフォルトで3つのインスタンス」とありますが、今回の検証では m8g.large タイプのインスタンスが4つ作成されました。この差異の原因についてご存知の方はこちらまで、フィードバックでお知らせいただけると幸いです!
おわりに
今回は、2025年12月に発表されたばかりの AWS Lambda Managed Instances を AWS CDKで実装してみました。
Lambda Managed Instances は新しい機能で、これからも機能追加やアップデートが予想されます。注目のサービスですね!
この記事がみなさまの実装の参考になれば幸いです。
参考リンク







