Lambda Managed InstancesをTerraformでサクッと試してみる。 #AWSreInvent

Lambda Managed InstancesをTerraformでサクッと試してみる。 #AWSreInvent

2025.12.04

はじめに

皆様こんにちは、あかいけです。

2025/12/1にAWS Lambdaの新機能「Lambda Managed Instances」が発表されました。
ECSのManaged Instancesに似たような概念で、Lambda関数をEC2インスタンス上で実行できるようになる機能です。

従来のLambdaはFirecrackerマイクロVMによるマルチテナント環境で動作していましたが、Lambda Managed Instancesでは自分のAWSアカウント内の専用EC2インスタンス上でコンテナとして実行されます。
これにより、GPUの利用や特定のインスタンスタイプの選択など、より柔軟な構成が可能になりました。

https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances.html
https://aws.amazon.com/about-aws/whats-new/2025/11/aws-lambda-managed-instances/

そんなLambda Managed Instancesですが、実はすでにTerraformが対応していました。
なので今回はTerraformで作成してサクッとLambda Managed Instancesを試してみます。

https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_function
https://registry.terraform.io/providers/hashicorp/aws/latest/docs/resources/lambda_capacity_provider

なお手動での作成/設定手順については、以下記事がわかりやすくてオススメです。

https://dev.classmethod.jp/articles/lambda-managed-instances/

必要となるTerraformリソース

Lambda Managed Instancesを構築するために、以下のTerraformリソースを作成します。

1. aws_lambda_capacity_provider

Lambda Managed Instancesの核となるリソースです。
関数を実行するインフラストラクチャを定義します。

  • 必須設定

    • name: Capacity Providerの名前
    • vpc_config: VPC設定(サブネットID、セキュリティグループID)
    • permissions_config: Lambda がEC2リソースを管理するためのIAMロールARN
  • オプション設定

    • instance_requirements: インスタンスタイプの指定(アーキテクチャ、許可/除外するインスタンスタイプ)
    • capacity_provider_scaling_policy: スケーリングポリシー設定

2. aws_lambda_function

通常のLambda関数に比べて、以下の設定追加で必要となります。

  • Managed Instances固有の設定
    • capacity_provider_config: Capacity ProviderのARNを指定
    • publish_to: LATEST_PUBLISHEDに設定(バージョン発行が必要)
    • memory_size: 最低2,048 MB以上が必要

3. IAM Role(Operator用)

Lambda がEC2インスタンスを管理するためのIAMロールが必要です。
AWS管理ポリシーAWSLambdaManagedEC2ResourceOperatorをアタッチする必要があります。

4. VPCリソース

EC2を利用する都合上、Capacity Providerには必ずVPC関連のリソースが必要となります。

  • VPC
  • サブネット
  • セキュリティグループ

Terraform実装例

以下に、Lambda Managed Instancesを構築するTerraformコードの例を示します。

main.tf
terraform {
  required_version = ">= 1.0"
  required_providers {
    aws = {
      source  = "hashicorp/aws"
      version = "~> 6.0"
    }
  }
}

provider "aws" {
  region = "ap-northeast-1"
}

data "aws_availability_zones" "available" {
  state = "available"
}

data "archive_file" "lambda" {
  type        = "zip"
  source_file = "${path.module}/src/index.py"
  output_path = "${path.module}/lambda.zip"
}

#--------------------------------------------------
# IAM: Operator Role
# LambdaがEC2インスタンスを管理するために必要なロール
#--------------------------------------------------

data "aws_iam_policy_document" "lambda_assume_role" {
  statement {
    effect = "Allow"

    principals {
      type        = "Service"
      identifiers = ["lambda.amazonaws.com"]
    }

    actions = ["sts:AssumeRole"]
  }
}

resource "aws_iam_role" "lambda_operator" {
  name               = "lambda-managed-instances-operator"
  assume_role_policy = data.aws_iam_policy_document.lambda_assume_role.json
}

# このポリシーにより、LambdaがEC2インスタンスのライフサイクルを管理可能になる
resource "aws_iam_role_policy_attachment" "lambda_operator" {
  role       = aws_iam_role.lambda_operator.name
  policy_arn = "arn:aws:iam::aws:policy/AWSLambdaManagedEC2ResourceOperator"
}

#--------------------------------------------------
# IAM: Lambda Execution Role
# Lambda関数の実行に必要なロール
#--------------------------------------------------

resource "aws_iam_role" "lambda_execution" {
  name               = "lambda-managed-instances-execution"
  assume_role_policy = data.aws_iam_policy_document.lambda_assume_role.json
}

resource "aws_iam_role_policy_attachment" "lambda_basic_execution" {
  role       = aws_iam_role.lambda_execution.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaBasicExecutionRole"
}

resource "aws_iam_role_policy_attachment" "lambda_vpc_access" {
  role       = aws_iam_role.lambda_execution.name
  policy_arn = "arn:aws:iam::aws:policy/service-role/AWSLambdaVPCAccessExecutionRole"
}

#--------------------------------------------------
# VPC Resources
# Capacity ProviderにはVPC設定が必須
#--------------------------------------------------

resource "aws_vpc" "main" {
  cidr_block           = "10.0.0.0/16"
  enable_dns_hostnames = true
  enable_dns_support   = true

  tags = {
    Name = "lambda-managed-instances-vpc"
  }
}

# プライベートサブネット(2つのAZに分散配置)
resource "aws_subnet" "private" {
  count             = 2
  vpc_id            = aws_vpc.main.id
  cidr_block        = cidrsubnet(aws_vpc.main.cidr_block, 8, count.index)
  availability_zone = data.aws_availability_zones.available.names[count.index]

  tags = {
    Name = "lambda-managed-instances-private-${count.index + 1}"
  }
}

# セキュリティグループ(アウトバウンドのみ許可)
resource "aws_security_group" "lambda" {
  name        = "lambda-managed-instances-sg"
  description = "Security group for Lambda Managed Instances"
  vpc_id      = aws_vpc.main.id

  egress {
    from_port   = 0
    to_port     = 0
    protocol    = "-1"
    cidr_blocks = ["0.0.0.0/0"]
  }

  tags = {
    Name = "lambda-managed-instances-sg"
  }
}

#--------------------------------------------------
# Lambda Capacity Provider
# EC2インスタンスの配置先やインスタンス要件を定義
#--------------------------------------------------

resource "aws_lambda_capacity_provider" "main" {
  name = "example-capacity-provider"

  # VPC設定(必須)
  vpc_config {
    subnet_ids         = aws_subnet.private[*].id
    security_group_ids = [aws_security_group.lambda.id]
  }

  # Operator Roleの指定(必須)
  permissions_config {
    capacity_provider_operator_role_arn = aws_iam_role.lambda_operator.arn
  }

  # インスタンス要件(オプション)
  # 指定しない場合はLambdaが自動で最適なインスタンスを選択
  instance_requirements {
    architectures = ["x86_64"]
    # 特定のインスタンスタイプに限定する場合は以下を指定
    allowed_instance_types = ["m5.large"]
  }

  tags = {
    Name = "example-capacity-provider"
  }
}

#--------------------------------------------------
# Lambda Function
# capacity_provider_configを指定することでManaged Instancesとして動作
#--------------------------------------------------

resource "aws_lambda_function" "main" {
  filename         = data.archive_file.lambda.output_path
  function_name    = "example-managed-instances-function"
  role             = aws_iam_role.lambda_execution.arn
  handler          = "index.handler"
  source_code_hash = data.archive_file.lambda.output_base64sha256

  runtime     = "python3.13" # Managed InstancesではPython 3.13以降が必要
  memory_size = 2048         # Managed Instancesでは最低2 GB(2048 MB)が必要
  timeout     = 30

  # $LATEST.PUBLISHED形式のバージョンを作成する
  publish    = true
  publish_to = "LATEST_PUBLISHED"

  # このブロックを指定することでManaged Instancesとして動作する
  capacity_provider_config {
    lambda_managed_instances_capacity_provider_config {
      capacity_provider_arn = aws_lambda_capacity_provider.main.arn
    }
  }

  tags = {
    Name = "example-managed-instances-function"
  }

  depends_on = [
    aws_iam_role_policy_attachment.lambda_basic_execution,
    aws_iam_role_policy_attachment.lambda_vpc_access,
  ]
}

サンプルLambda関数コード

src/index.py
import json

def handler(event, context):
    return {
        "statusCode": 200,
        "body": json.dumps({
            "message": "Hello from Lambda Managed Instances!"
        })
    }

上記を構築後に関数を呼び出してあげると、正常にレスポンスが返ってくるかと思います。

% aws lambda invoke --function-name example-managed-instances-function outfile && cat outfile 

{
    "StatusCode": 200,
    "ExecutedVersion": "$LATEST.PUBLISHED"
}
{"statusCode": 200, "body": "{\"message\": \"Hello from Lambda Managed Instances!\"}"}

構築時の注意点

ドキュメントを眺めていて、いくつか注意点があったので記載します。
構築時はこれらの点を考慮した上で、検証してみて下さい。

デフォルトで3台のEC2インスタンスが起動

Lambda Managed Instancesでは、AZの冗長性を確保するため、デフォルトで3台のEC2インスタンスが起動します。
そのため検証目的で小規模に試したい場合でもインスタンス料金がかかる点に注意してください。

また、関数バージョンを発行するとLambdaは3つの実行環境を起動してから関数バージョンをACTIVE状態にします。
このため、関数の作成には数分かかる場合があります。

https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances.html

最小メモリは2 GB

従来のLambdaでは128 MBから設定できましたが、Managed Instancesでは最低2 GBのメモリが必要です。

https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances-scaling.html

小さいインスタンスタイプは非対応

ドキュメントには記載されていませんが、t3.microなどの小さいインスタンスタイプはサポートされていません。

また基本的にはLambdaに最適なインスタンスタイプを自動選択させることが推奨されています。

https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances-capacity-providers.html

サポートされるランタイム

Lambda Managed Instancesでは、以下のランタイムがサポートされています。
そのため前述のTerraformコード例ではpython3.13を指定しています。

  • Java 21以降
  • Python 3.13以降
  • Node.js 22以降
  • .NET 8以降

https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances-runtimes.html

VPCネットワーク設定が必須

Lambda Managed InstancesはVPC内で動作するため、Lamnda関数から外部リソースへのアクセスやCloudWatch Logsへのログ送信にはネットワーク設定が必要です。
以下のいずれかの方法でネットワーク接続を構成してください。

  • パブリックサブネット + インターネットゲートウェイ
  • プライベートサブネット + NATゲートウェイ
  • プライベートサブネット + VPCエンドポイント

https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances-networking.html

Capacity Providerはセキュリティ境界

Capacity Providerは関数のセキュリティ境界として機能します。
同じCapacity Providerに割り当てられた関数はすべて相互に信頼されている必要があります。

なお、コンテナはセキュリティ境界として利用できないため、セキュリティ分離の手段として使用しないでください。
そのため信頼レベルが異なるワークロードは、別々のCapacity Providerに分離することを推奨します。

https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances-security.html

初期化タイムアウトが長い

Lambda Managed Instancesでは、初期化フェーズに最大15分かかる場合があります。
タイムアウトは130秒または設定された関数タイムアウト(最大900秒)のいずれか大きい方が適用されます。

https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances-execution-environment.html

CPU使用率ベースの非同期スケーリング

従来のLambdaはリクエストが来たときに実行環境がなければスケールアウトする(コールドスタート)方式でしたが、Lambda Managed InstancesはCPU使用率に基づいて非同期にスケールします。

https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances-scaling.html

マルチ同時実行モデル

Lambda Managed Instancesの最も大きな特徴の一つが、マルチ同時実行(Multi-concurrent execution)です。
そのためランタイムに応じて、同時実行について考慮が必要となります。

https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances-core-concepts.html

従来のLambdaとの違い

項目 従来のLambda Managed Instances
同時実行 1実行環境 = 1リクエスト 1実行環境 = 複数リクエスト
スレッドセーフ 考慮不要 必須
グローバル変数 リクエスト間で再利用可能 同時アクセスに注意

その他ランタイムごとの注意点や実装方法については公式ドキュメントをご参照ください。

https://docs.aws.amazon.com/lambda/latest/dg/lambda-managed-instances-runtimes.html

余談

Capacity Provider の削除に意外と時間がかかりました。
おそらくEC2インスタンスなどマネージドに管理しているリソースの削除に時間がかかるのかなと思います。

aws_lambda_capacity_provider.main: Still destroying... [name=example-capacity-provider, 10m0s elapsed]
aws_lambda_capacity_provider.main: Destruction complete after 10m5s

さいごに

以上、Lambda Managed InstancesをTerraformで実装する方法でした。
ブログのTerraformコードそのまま構築できるため、皆さんもたくさん検証してみて下さい。

Lambda Managed Instancesは従来のLambdaとは料金モデルやスケーリングの考え方が大きく異なるため、ワークロードの特性に応じて使い分けることが重要だと思います。
定常的で予測可能なワークロードや、EC2の柔軟性が必要なケースでは、Lambda Managed Instancesが有力な選択肢になりそうです。

この記事が誰かのお役に立てば幸いです。

この記事をシェアする

FacebookHatena blogX

関連記事