AWS Lambda Managed Instances with Java 25 and AWS SAM – Part 2 Create Capacity Provider

AWS Lambda Managed Instances with Java 25 and AWS SAM

AWS Lambda Managed Instances with Java 25 and AWS SAM article series article series - Part 1 Introduction and sample application

AWS Lambda Managed Instances with Java 25 and AWS SAM – Part 1 Introduction and sample application

AWS Lambda Managed Instances with Java 25 and AWS SAM article series article series - Part 2

AWS Lambda Managed Instances with Java 25 and AWS SAM – Part 2 Create Capacity Provider

AWS Lambda Managed Instances with Java 25 and AWS SAM – Part 2 Create Capacity Provider

Introduction

In part 1 of the series, we explained the ideas behind AWS Lambda Managed Instances and introduced our sample application. In this article, we’ll explain what a Lambda Capacity Provider is and how to create it using AWS SAM.

Lambda Capacity Provider

Lambda Managed Instances uses capacity providers as the foundation for running your functions:

  • Create a capacity provider. Define where your functions run by specifying VPC configuration and, optionally, instance requirements, and scaling configuration
  • Create your function. Create Lambda functions as usual and attach them to a capacity provider
  • Publish a function version. Function versions become active on capacity provider instances once published. SAM does it automatically when deploying or updating your stack.

Let’s further explore the creation of a capacity provider and navigate to the Capacity Providers menu in the AWS Lambda service, which looks like this:

Lambda Managed Instances - Capacity Providers

You can find a code example of our sample application in my GitHub aws-lambda-java-25-lmi repository. The relevant Infrastructure as Code part is located in the AWS SAM template.

Let’s create a new one. Minimalistic IaC code for this looks like this:

  MyCapacityProvider:
    Type: AWS::Serverless::CapacityProvider
    Properties:
      CapacityProviderName: CapacityProviderForJava25LMI
      VpcConfig: 
        SubnetIds:
          - subnet-1
          - subnet-2
          - subnet-3
        SecurityGroupIds:
          - sg-1
          - sg-2
          - sg-3

The only required parameters are the CapacityProviderName and both VpcConfig settings.

VPC Config of the Lambda Capacity Provider

SubnetIds and SecurityGroupIds (which you should replace with your own ids) should belong to the same VPC. It’s a good practice to configure at least 3 values from the different availability zones for both. You can use the default VPC or create a new one with subnets and security groups. There is more to pay attention to depending on your scenario, so I refer to the official Networking for Lambda Managed Instances article. For my use case, I didn’t have to change anything in the network configuration.

If we deploy our SAM template with the required parameters of the Capacity Provider only, the created one will look like this:

Infrastructure operator role for the Lambda Capacity Provider

There is one more required parameter, which is “Infrastructure operator role”, but AWS SAM takes care of creating a new one or re-using the existing one (in our case, with the name AWSLambdaManagedEC2ResourceOperator) with the attached policies with sufficient permissions automatically:

Permission policies for AWS Lambda to access EC2

The content of this policy looks like this:

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Effect": "Allow",
            "Action": [
                "ec2:RunInstances",
                "ec2:CreateTags",
                "ec2:AttachNetworkInterface"
            ],
            "Resource": [
                "arn:aws:ec2:*:*:instance/*",
                "arn:aws:ec2:*:*:network-interface/*",
                "arn:aws:ec2:*:*:volume/*"
            ],
            "Condition": {
                "StringEquals": {
                    "ec2:ManagedResourceOperator": "scaler.lambda.amazonaws.com"
                }
            }
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:DescribeAvailabilityZones",
                "ec2:DescribeCapacityReservations",
                "ec2:DescribeInstances",
                "ec2:DescribeInstanceStatus",
                "ec2:DescribeInstanceTypeOfferings",
                "ec2:DescribeInstanceTypes",
                "ec2:DescribeSecurityGroups",
                "ec2:DescribeSubnets"
            ],
            "Resource": "*"
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:RunInstances",
                "ec2:CreateNetworkInterface"
            ],
            "Resource": [
                "arn:aws:ec2:*:*:subnet/*",
                "arn:aws:ec2:*:*:security-group/*"
            ]
        },
        {
            "Effect": "Allow",
            "Action": [
                "ec2:RunInstances"
            ],
            "Resource": [
                "arn:aws:ec2:*:*:image/*"
            ],
            "Condition": {
                "StringEquals": {
                    "ec2:Owner": "amazon"
                }
            }
        }
    ]
}

Instance configuration of the Lambda Capacity Provider

There are optional “Instance configuration” properties that we can set, but they all have meaningful default values.

The IaC part for those optional instance configuration properties for our sample application is defined in the properties section of the Capacity Provider. The settings are selected only for demonstrational purposes:

Resources:
  MyCapacityProvider:
    Type: AWS::Serverless::CapacityProvider
    Properties:
      CapacityProviderName: CapacityProviderForJava25LMI
      InstanceRequirements:
        Architectures:
           - x86_64
        AllowedTypes:
           - m7a.large
           - m6a.large
      ScalingConfig:
        MaxVCpuCount: 16
        AverageCPUUtilization: 70.0
Instance Requirements of the Lambda Capacity Provider

Let’s start with the description of the InstanceRequirements:

  • We can set the architecture. x86_64 is a default value that we also set. The other alternative is arm64
  • For the allowed instance types, we can select between include all instance types (default value), only allow instance types that we set by providing the list of EC2 instance types (m7a.large, m6a.large). For a list of supported instance types, go to the AWS Lambda Pricing
    page and select our AWS Region. Please note that the instance type should match the architecture, for example Graviton instance requires the arm64 architecture. We can also set the exclude instance types instead.
Scaling configuration of the Lambda Capacity Provider

Finally, let’s explore the ScalingConfig:

  • MaxVCpuCount value (default is 400), which we set to 16, defines the maximum number of vCPUs for the capacity provider. This ensures that the bill remains in our control in case the wild autoscaling happens. We can’t set too small value, though, because it should match the vCPU count of the allowed instances, which will be launched in the defined availability zones. 16 seems to be currently the lowest value.
  • ScalingMode is Auto (default) for automatic scaling or Manual for manual control. As we set AverageCPUUtilization to 70.0 in our example means that we switched to the Manual and had to define the target scaling policies (currently, only CPU policy is supported).

For detailed information about all settings of the Capacity Provider, please read the official article.

Depending on the requirements of our Lambda functions (for example, CPU, RAM, or network-bound), we can create different Capacity Providers (which we’ll later attach to our Lambda functions) and configure different settings like allowed instance types, maximum vCPU count, or scaling behavior for each.

If we deploy our SAM template with the optional parameters of the Capacity Provider described above, the created one will look like this:

First part of the Capacity Provider instance configuration for Lambda Managed Instance
Second part of the Capacity Provider instance configuration for Lambda Managed Instance

Please note that some properties or fields of the Capacity Provider can’t be edited after creation.

Conclusion

In this article, we explained what a Lambda Capacity Provider is and how to create it using AWS SAM. In the next part of the series, we’ll cover how to create Lambda functions and attach them to a capacity provider.

AWS Lambda Managed Instances with Java 25 and AWS SAM

AWS Lambda Managed Instances with Java 25 and AWS SAM – Part 1 Introduction and sample application