Lambda Execution

With Docker enabled, Lambda functions execute your code in real Docker containers using AWS Lambda base images from public.ecr.aws/lambda/. Your handler code runs the same way it does in real AWS - same runtime environment, same environment variables, same invocation protocol.

Prerequisites

  • SIMFRA_DOCKER=true
  • Lambda runtime images are pulled automatically on first invocation

Supported Runtimes

Runtime Image
nodejs18.x, nodejs20.x, nodejs22.x, nodejs24.x public.ecr.aws/lambda/nodejs:{version}
python3.8 through python3.13 public.ecr.aws/lambda/python:{version}
java8, java8.al2, java11, java17, java21, java25 public.ecr.aws/lambda/java:{version}
dotnet6, dotnet8, dotnet10 public.ecr.aws/lambda/dotnet:{version}
ruby3.2, ruby3.3, ruby3.4 public.ecr.aws/lambda/ruby:{version}
go1.x public.ecr.aws/lambda/go:1
provided, provided.al2, provided.al2023 public.ecr.aws/lambda/provided:{tag}

Override the image registry with SIMFRA_LAMBDA_IMAGE_REGISTRY (default public.ecr.aws/lambda).

Deploy from Zip

Create a deployment package and deploy:

# Python example
cat > handler.py << 'EOF'
def handler(event, context):
    return {"statusCode": 200, "body": f"Hello, {event.get('name', 'World')}!"}
EOF

zip function.zip handler.py

aws --endpoint-url http://localhost:4599 lambda create-function \
  --function-name my-func \
  --runtime python3.12 \
  --handler handler.handler \
  --zip-file fileb://function.zip \
  --role arn:aws:iam::000000000000:role/lambda-role

Invoke:

aws --endpoint-url http://localhost:4599 lambda invoke \
  --function-name my-func \
  --payload '{"name": "Simfra"}' \
  output.json

cat output.json
{"statusCode": 200, "body": "Hello, Simfra!"}

Deploy from ECR Image

Push a container image to Simfra's ECR (see ECR Image Management), then create the function with PackageType=Image:

aws --endpoint-url http://localhost:4599 lambda create-function \
  --function-name my-image-func \
  --package-type Image \
  --code ImageUri=000000000000.dkr.ecr.us-east-1.localhost:4599/my-app:latest \
  --role arn:aws:iam::000000000000:role/lambda-role

The image must be compatible with the Lambda Runtime Interface Emulator (RIE). AWS Lambda base images include the RIE by default.

Layers

Create a layer and attach it to a function:

zip layer.zip python/my_lib.py

aws --endpoint-url http://localhost:4599 lambda publish-layer-version \
  --layer-name my-layer \
  --zip-file fileb://layer.zip \
  --compatible-runtimes python3.12

aws --endpoint-url http://localhost:4599 lambda update-function-configuration \
  --function-name my-func \
  --layers arn:aws:lambda:us-east-1:000000000000:layer:my-layer:1

Layer contents are extracted and mounted into the function container at /opt.

Environment Variables

Function environment variables are passed to the container:

aws --endpoint-url http://localhost:4599 lambda update-function-configuration \
  --function-name my-func \
  --environment 'Variables={DB_HOST=mydb.abcdef.us-east-1.rds.simfra.dev,DB_PORT=5432}'

Simfra also sets the standard AWS Lambda reserved environment variables: AWS_REGION, AWS_LAMBDA_FUNCTION_NAME, AWS_LAMBDA_FUNCTION_MEMORY_SIZE, AWS_LAMBDA_FUNCTION_VERSION, AWS_LAMBDA_LOG_GROUP_NAME, and others.

Execution Role Credentials

Lambda containers receive temporary STS credentials for their execution role, matching real AWS behavior. The AWS_ACCESS_KEY_ID, AWS_SECRET_ACCESS_KEY, and AWS_SESSION_TOKEN environment variables are set from an STS AssumeRole call. These credentials are valid for the container's lifetime and are refreshed when the container is recycled.

This means your function code can call other AWS services (S3, DynamoDB, SQS, etc.) against Simfra using the default credential chain, and IAM policies on the execution role are enforced.

Container Lifecycle

Lambda containers are kept warm for reuse. After an invocation, the container stays alive for SIMFRA_LAMBDA_KEEP_ALIVE seconds (default 300). Subsequent invocations of the same function version reuse the warm container, matching the real Lambda warm-start behavior.

Containers are cleaned up when:

  • The keep-alive period expires without another invocation.
  • The function is deleted.
  • Execution role credentials are about to expire (container is recycled with fresh credentials).
  • Simfra shuts down.

Event Source Mappings

Event source mappings auto-trigger Lambda invocations from event sources:

SQS

aws --endpoint-url http://localhost:4599 lambda create-event-source-mapping \
  --function-name my-func \
  --event-source-arn arn:aws:sqs:us-east-1:000000000000:my-queue \
  --batch-size 10

The Lambda poller reads messages from the SQS queue, invokes the function with the message batch, and deletes messages on success.

DynamoDB Streams

aws --endpoint-url http://localhost:4599 lambda create-event-source-mapping \
  --function-name my-func \
  --event-source-arn arn:aws:dynamodb:us-east-1:000000000000:table/my-table/stream/2024-01-01T00:00:00.000 \
  --starting-position LATEST \
  --batch-size 100

Kinesis

aws --endpoint-url http://localhost:4599 lambda create-event-source-mapping \
  --function-name my-func \
  --event-source-arn arn:aws:kinesis:us-east-1:000000000000:stream/my-stream \
  --starting-position LATEST \
  --batch-size 100

Event source mapping pollers use the function's execution role to read from the source (poller-owned authorization model). If the role lacks the required permissions, the mapping pauses and retries.

VPC Configuration

Lambda functions can be placed in a VPC:

aws --endpoint-url http://localhost:4599 lambda create-function \
  --function-name my-vpc-func \
  --runtime python3.12 \
  --handler handler.handler \
  --zip-file fileb://function.zip \
  --role arn:aws:iam::000000000000:role/lambda-role \
  --vpc-config SubnetIds=subnet-xxx,SecurityGroupIds=sg-xxx

VPC-attached Lambda containers are placed on the VPC Docker network and use VPC DNS. They can reach RDS, ElastiCache, and other private resources by endpoint name. Non-VPC Lambda containers use bridge DNS to resolve Simfra service names.

Function URLs

Lambda function URLs provide a dedicated HTTP endpoint:

aws --endpoint-url http://localhost:4599 lambda create-function-url-config \
  --function-name my-func \
  --auth-type NONE

Aliases and Versions

Publish versions and create aliases:

aws --endpoint-url http://localhost:4599 lambda publish-version \
  --function-name my-func

aws --endpoint-url http://localhost:4599 lambda create-alias \
  --function-name my-func \
  --name prod \
  --function-version 1

Each version maintains its own warm container pool.

Logs

Lambda function output is captured and forwarded to CloudWatch Logs under the /aws/lambda/{function-name} log group. View logs via the CloudWatch Logs API or the Simfra web console.

Next Steps