AWS Lambda Managed Instances で関数非アクティブ化により起動インスタンス数をゼロにしてみた

AWS Lambda Managed Instances で関数非アクティブ化により起動インスタンス数をゼロにしてみた

非アクティブ化した関数は呼び出し不可となるのでゼロスケールではありません。
2025.12.22

こんにちは、製造ビジネステクノロジー部の若槻です。

re:Invent 2025 にて発表された AWS Lambda Managed Instances (LMI) ですが、re:Invent 期間中に早速 DeepDive のセッションが開催され、配信動画も上がっていました。

https://www.youtube.com/watch?v=7mWa2HpCZfg

配信を視聴してみたところ、LMI 関数を非アクティブ化して、起動インスタンス数をゼロにする方法が紹介されていました。(具体的に動画内のどの時点かは失念してしまいました。)

これが実現できれば夜間や休日にリソースの無駄を最小限に抑えることも可能です。LMI の固定コストを抑える上で有用そうだと感じたので、早速試してみました。

やってみた

リソース作成

リソースの作成には AWS CDK を使用しました。

VPC は予め作成したものを使用します。

VPC 定義コード
lib/constructs/vpc.ts
import * as ec2 from "aws-cdk-lib/aws-ec2";
import { Construct } from "constructs";

/**
 * VPC 実装
 *
 * MEMO: VPC から各種 AWS サービスへのネットワーク経路確保のために NAT Gateway を配置する
 */
export class VpcConstruct extends Construct {
  public readonly vpc: ec2.Vpc;
  constructor(scope: Construct, id: string) {
    super(scope, id);

    this.vpc = new ec2.Vpc(this, "Default", {
      subnetConfiguration: [
        /**
         * NAT Gateway を配置するためのパブリックサブネット
         */
        {
          name: "Public",
          subnetType: ec2.SubnetType.PUBLIC,
        },

        /**
         * Lambda 関数を配置するためのプライベートサブネット
         */
        {
          name: "PrivateIsolated",
          subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
        },
      ],
    });
  }
}

LMI 作成の定義は以下となります。

lib/sample-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 * as lambda_nodejs from "aws-cdk-lib/aws-lambda-nodejs";
import { Construct } from "constructs";

import { VpcConstruct } from "./constructs/vpc";

export class SampleStack extends cdk.Stack {
  constructor(scope: Construct, id: string) {
    super(scope, id);

    /**
     * VPC 作成
     */
    const vpcConstruct = new VpcConstruct(this, "Vpc");
    const vpc = vpcConstruct.vpc;

    /**
     * セキュリティグループ作成
     *
     * MEMO: Capacity Provider 用に作成
     */
    const securityGroup = new ec2.SecurityGroup(this, "SecurityGroup", {
      vpc,
    });

    /**
     * Capacity Provider 作成
     *
     * MEMO: LMI のコア要素となるリソース
     */
    const capacityProvider = new lambda.CapacityProvider(
      this,
      "CapacityProvider",
      {
        subnets: vpc.selectSubnets({
          subnetType: ec2.SubnetType.PRIVATE_WITH_EGRESS,
        }).subnets,
        securityGroups: [securityGroup],
      },
    );

    /**
     * LMI 用 Lambda 関数作成
     */
    const lmiFunction = new lambda_nodejs.NodejsFunction(this, "LmiFunction", {
      entry: "src/handler.ts",
      runtime: lambda.Runtime.NODEJS_24_X, // Lambda Managed Instances では Node.js 18.x 以上が必須
      memorySize: 2048, // Lambda Managed Instances では 2048MB 以上が必須
      tracing: lambda.Tracing.ACTIVE, // コールドスタート発生状況の観測のために、AWS X-Ray を有効化
    });

    /**
     * Capacity Provider に Lambda 関数を追加
     */
    capacityProvider.addFunction(lmiFunction);
  }
}

ここで、LMI 関数を非アクティブ化する具体的な方法は、関数の最小および最大実行環境数を 0 に設定することです。

しかし、下記を参考に minExecutionEnvironments および maxExecutionEnvironments プロパティを 0 に設定しようとしましたが、なぜか CDK Synth の時点で設定が反映されませんでした。

https://docs.aws.amazon.com/cdk/api/v2/docs/aws-cdk-lib.aws_lambda-readme.html#capacity-provider-versions

よって、関数の非アクティブ化はマネジメントコンソールから手動でおこないました。

LMI 関数を非アクティブ化する

前述の CDK 定義をデプロイした後、Capacity Provider の起動インスタンス数を確認します。

起動状態のインスタンスは2台確認でした。

$ aws ec2 describe-instances \
  --filters "Name=tag:aws:lambda:capacity-provider,Values=${CAPACITY_PROVIDER_ARN}" \
  --query "Reservations[].Instances[].{
    InstanceId: InstanceId,
    State: State.Name,
    Type: InstanceType,
    vCPU: CpuOptions.CoreCount,
    AZ: Placement.AvailabilityZone,
    Subnet: SubnetId,
    LaunchTime: LaunchTime,
    Managed: Operator.Managed,
    ManagedBy: Operator.Principal
  }" \
  --output table
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|                                                                               DescribeInstances                                                                              |
+-----------------+----------------------+----------------------------+----------+------------------------------+----------+---------------------------+--------------+--------+
|       AZ        |     InstanceId       |        LaunchTime          | Managed  |          ManagedBy           |  State   |          Subnet           |    Type      | vCPU   |
+-----------------+----------------------+----------------------------+----------+------------------------------+----------+---------------------------+--------------+--------+
|  ap-northeast-1c|  i-06d73797f212c0f63 |  2025-12-21T13:36:38+00:00 |  True    |  scaler.lambda.amazonaws.com |  running |  subnet-021de8f5c4a063eae |  m7i.xlarge  |  2     |
|  ap-northeast-1a|  i-004041cc1e1c55fed |  2025-12-21T13:36:36+00:00 |  True    |  scaler.lambda.amazonaws.com |  running |  subnet-03ee04b39e3e61661 |  m7i.xlarge  |  2     |
+-----------------+----------------------+----------------------------+----------+------------------------------+----------+---------------------------+--------------+--------+

それでは関数を非アクティブ化してみます。

マネジメントコンソールで関数の [Function scaling configuration] メニューを開き、MinExecutionEnvironments および MaxExecutionEnvironments0 に設定して保存します。(キャプチャでは当初前者だけ 0 にしようとしてそちらだけ枠で囲っています。)

設定変更画面です。

MinExecutionEnvironments だけ 0 にしようとした場合、MaxExecutionEnvironments0 にするようにと怒られます。

Invalid function scaling configuration: MinExecutionEnvironments can't be 0 unless MaxExecutionEnvironments is also 0.

どちらも 0 に設定して保存します。

スケーリング構成の反映中となりました。

少し待つと、いずれの設定も 0 になりました。また関数が非アクティブ化されたとのステータスメッセージも表示されました。

Version $LATEST.PUBLISHED is deactivated. To reactivate your function, choose Set scaling to set non-zero execution environment values.

関数を呼び出してみると、以下のエラーメッセージが返り、再アクティブ化を求められました。

Calling the invoke API action failed with this message: The function is in Deactivated state. Reactivate function by increasing the minimum and maximum execution environments, and try again.

Capacity Provider 側でも、該当の関数が非アクティブ化されていることが確認できました。

そしてインスタンス一覧を再度取得してみると、2台とも終了 (Terminate) していることが確認できました。

$ aws ec2 describe-instances \
  --filters "Name=tag:aws:lambda:capacity-provider,Values=${CAPACITY_PROVIDER_ARN}" \
  --query "Reservations[].Instances[].{
    InstanceId: InstanceId,
    State: State.Name,
    Type: InstanceType,
    vCPU: CpuOptions.CoreCount,
    AZ: Placement.AvailabilityZone,
    Subnet: SubnetId,
    LaunchTime: LaunchTime,
    Managed: Operator.Managed,
    ManagedBy: Operator.Principal
  }" \
  --output table
-----------------------------------------------------------------------------------------------------------------------------------------------------------------
|                                                                       DescribeInstances                                                                       |
+-----------------+----------------------+----------------------------+----------+------------------------------+-------------+---------+--------------+--------+
|       AZ        |     InstanceId       |        LaunchTime          | Managed  |          ManagedBy           |    State    | Subnet  |    Type      | vCPU   |
+-----------------+----------------------+----------------------------+----------+------------------------------+-------------+---------+--------------+--------+
|  ap-northeast-1c|  i-06d73797f212c0f63 |  2025-12-21T13:36:38+00:00 |  True    |  scaler.lambda.amazonaws.com |  terminated |  None   |  m7i.xlarge  |  2     |
|  ap-northeast-1a|  i-004041cc1e1c55fed |  2025-12-21T13:36:36+00:00 |  True    |  scaler.lambda.amazonaws.com |  terminated |  None   |  m7i.xlarge  |  2     |
+-----------------+----------------------+----------------------------+----------+------------------------------+-------------+---------+--------------+--------+

Capacity provider instance counts メトリクス上でも、インスタンスが全て終了していることが確認できました。

その後に関数を再アクティブ化すると、再びインスタンスが起動されました。

$ aws ec2 describe-instances \
  --filters "Name=tag:aws:lambda:capacity-provider,Values=${CAPACITY_PROVIDER_ARN}" \
  --query "Reservations[].Instances[].{
    InstanceId: InstanceId,
    State: State.Name,
    Type: InstanceType,
    vCPU: CpuOptions.CoreCount,
    AZ: Placement.AvailabilityZone,
    Subnet: SubnetId,
    LaunchTime: LaunchTime,
    Managed: Operator.Managed,
    ManagedBy: Operator.Principal
  }" \
  --output table
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
|                                                                               DescribeInstances                                                                              |
+-----------------+----------------------+----------------------------+----------+------------------------------+----------+---------------------------+--------------+--------+
|       AZ        |     InstanceId       |        LaunchTime          | Managed  |          ManagedBy           |  State   |          Subnet           |    Type      | vCPU   |
+-----------------+----------------------+----------------------------+----------+------------------------------+----------+---------------------------+--------------+--------+
|  ap-northeast-1c|  i-09bdd916f274dbe0b |  2025-12-21T14:25:55+00:00 |  True    |  scaler.lambda.amazonaws.com |  running |  subnet-021de8f5c4a063eae |  m7a.xlarge  |  4     |
|  ap-northeast-1a|  i-0e59c285f2ca58c30 |  2025-12-21T14:25:54+00:00 |  True    |  scaler.lambda.amazonaws.com |  running |  subnet-03ee04b39e3e61661 |  m7a.xlarge  |  4     |
+-----------------+----------------------+----------------------------+----------+------------------------------+----------+---------------------------+--------------+--------+

おわりに

AWS Lambda Managed Instances で関数非アクティブ化により起動インスタンス数をゼロにしてみたので紹介しました。

これを EventBridge や CloudWatch Alarms と組み合わせて、夜間や休日に自動で非アクティブ化・再アクティブ化するようにすれば、開発環境だけ不要時はインスタンスを落として LMI の固定コストを抑える、なんてことができそうです。

しかし注意点としてはやはり、Aurora Serverless v2 のゼロスケールや Lambda 関数のコールドスタートとは異なり、遅延して起動はせず呼び出しは必ず失敗してしまう点でしょうか。仕様として理解した上で運用する必要がありそうです。

以上

この記事をシェアする

FacebookHatena blogX

関連記事