Overview
AWS Lambda MicroVMs are Firecracker-based compute environments with VM-level isolation, snapshot start and resume, and full OS capabilities. They suit long-running, stateful sandboxes such as AI agent code execution, interactive development environments, CI jobs, and vulnerability scanners.
This guide runs an OpenTelemetry Collector inside the MicroVM image. The Collector scrapes host metrics, tails application logs, receives OTLP from your application, and exports everything to SigNoz.
Prerequisites
- The AWS CLI with the
lambda-microvmscommand set. Runaws lambda-microvms helpto confirm it listscreate-microvm-imageandrun-microvm. - An S3 bucket in the same region for the code artifact.
- A build role that Lambda assumes during the image build. It needs
s3:GetObjecton the artifact andlogs:CreateLogGroup,logs:CreateLogStream, andlogs:PutLogEvents. - An execution role for the running MicroVM. Without it, application stdout and stderr never reach CloudWatch. It needs
logs:CreateLogGroup,logs:CreateLogStream, andlogs:PutLogEvents. - Both roles need a trust policy that lets Lambda assume them, with
Principal: {"Service": "lambda.amazonaws.com"}andAction: ["sts:AssumeRole", "sts:TagSession"]. Your own caller needslambda:CreateMicrovmImage,lambda:RunMicrovm, andiam:PassRolefor both roles. - An instance of SigNoz (either Cloud or Self-Hosted)
How monitoring works
| Signal | Source inside the MicroVM | Path to SigNoz |
|---|---|---|
| Metrics (host CPU, memory, disk, network) | hostmetrics receiver in the embedded Collector | OTLP/HTTP to SigNoz |
| Traces | Application instrumented with an OpenTelemetry SDK | OTLP to the local Collector, then to SigNoz |
| Logs | filelog receiver, or OTLP from the SDK | OTLP/HTTP to SigNoz |
| Lifecycle and audit | CloudTrail data events | CloudWatch or S3 to SigNoz |
How sizing works
MicroVMs use a baseline and peak model. You set the baseline with the memory value when you create the image, and vCPU scales with it at 2 GB per vCPU. During activity the MicroVM scales vertically up to four times the baseline.
| Baseline | Peak | Max disk |
|---|---|---|
| 0.5 GB, 0.25 vCPU | 2 GB, 1 vCPU | 8 GB |
| 1 GB, 0.5 vCPU | 4 GB, 2 vCPU | 8 GB |
| 2 GB, 1 vCPU (default) | 8 GB, 4 vCPU | 8 GB |
| 4 GB, 2 vCPU | 16 GB, 8 vCPU | 16 GB |
| 8 GB, 4 vCPU | 32 GB, 16 vCPU | 32 GB |
A MicroVM runs for at most 8 hours. Set the limit with --maximum-duration-in-seconds, which
accepts 1 to 28,800 seconds.
Send telemetry to SigNoz
Lambda builds the MicroVM image from a ZIP you upload to S3, then snapshots the running result. The
Collector is baked into that snapshot, so it is already running the moment a MicroVM starts. Your
application exports to it on localhost instead of reaching SigNoz directly.
Step 1: Package the application and Dockerfile
The code artifact is a ZIP that contains a Dockerfile at the archive root plus your application
files. Lambda pulls the ZIP from S3, runs your Dockerfile on top of the managed base image, starts
your application, and snapshots the result.
Two different base images are involved. The MicroVM base image is the operating system
environment, passed as --base-image-arn. The container base image is what your Dockerfile
uses in its FROM instruction.
FROM public.ecr.aws/lambda/microvms:al2023-minimal
# al2023-minimal ships without tar, gzip, or procps. Install what you need
# before extracting anything.
RUN dnf install -y tar gzip python3 python3-pip && dnf clean all
# Release assets are version-named, and MicroVMs are ARM64 only. Pin a version
# and use the arm64 tarball.
ARG OTELCOL_VERSION=0.159.0
ADD https://github.com/open-telemetry/opentelemetry-collector-releases/releases/download/v${OTELCOL_VERSION}/otelcol-contrib_${OTELCOL_VERSION}_linux_arm64.tar.gz /tmp/otelcol.tar.gz
RUN mkdir -p /usr/local/bin \
&& tar -xzf /tmp/otelcol.tar.gz -C /usr/local/bin otelcol-contrib \
&& rm /tmp/otelcol.tar.gz
COPY app.py /app/app.py
COPY otel-collector-config.yaml /etc/otelcol/config.yaml
COPY entrypoint.sh /entrypoint.sh
RUN chmod +x /entrypoint.sh && mkdir -p /var/log/app
CMD ["/entrypoint.sh"]The image build has outbound internet access, so pulling the Collector with ADD works. Start the
Collector in the background and your application in the foreground, which keeps the MicroVM alive:
#!/usr/bin/env bash
set -euo pipefail
# Lambda forwards only stdout and stderr to CloudWatch, so do not redirect the
# Collector to a file. Writing it into /var/log/app would also make the filelog
# receiver tail the Collector's own output.
/usr/local/bin/otelcol-contrib --config /etc/otelcol/config.yaml 2>&1 &
exec python3 -u /app/app.pyStep 2: Configure the OpenTelemetry Collector
receivers:
# On Collector v0.151.0 and newer, use "host_metrics" to avoid a deprecation warning.
hostmetrics:
collection_interval: 30s
scrapers:
cpu:
metrics:
# system.cpu.utilization is an optional metric and off by default.
# Enable it explicitly or it never reaches SigNoz.
system.cpu.utilization:
enabled: true
memory: {}
load: {}
filesystem: {}
network: {}
# On Collector v0.149.0 and newer, use "file_log" to avoid a deprecation warning.
# This only collects anything if your application writes to this path. An
# application that logs to stdout alone produces no records here.
#
# Keep the Collector's own log out of this glob. A Collector that tails its own
# output re-exports every line it writes.
filelog:
include: [/var/log/app/*.log]
exclude: [/var/log/app/otelcol*.log]
start_at: beginning
otlp:
protocols:
http:
endpoint: localhost:4318
processors:
batch: {}
# On Collector v0.153.0 and newer, use "resource_detection" to avoid a deprecation warning.
resourcedetection:
detectors: [env, system]
resource:
attributes:
# Lambda injects this into every MicroVM. It is the same value the
# CloudWatch Agent uses for its ImageName dimension.
- key: aws.lambda.microvm.image_name
value: ${env:AWS_LAMBDA_MICROVM_IMAGE_NAME}
action: upsert
- key: aws.lambda.microvm.image_version
value: ${env:AWS_LAMBDA_MICROVM_IMAGE_VERSION}
action: upsert
exporters:
# On Collector v0.144.0 and newer, use "otlp_http" to avoid a deprecation warning.
otlphttp:
endpoint: ${env:SIGNOZ_ENDPOINT}
headers:
signoz-ingestion-key: ${env:SIGNOZ_INGESTION_KEY}
service:
pipelines:
metrics:
receivers: [hostmetrics, otlp]
processors: [resourcedetection, resource, batch]
exporters: [otlphttp]
traces:
receivers: [otlp]
processors: [resourcedetection, resource, batch]
exporters: [otlphttp]
logs:
receivers: [filelog, otlp]
processors: [resourcedetection, resource, batch]
exporters: [otlphttp]Lambda injects AWS_LAMBDA_MICROVM_IMAGE_NAME, AWS_LAMBDA_MICROVM_IMAGE_ARN,
AWS_LAMBDA_MICROVM_IMAGE_VERSION, and AWS_REGION into every MicroVM. Using the image name as a
resource attribute lets you filter and group all three signals by image in SigNoz.
Step 3: Instrument your application
Because the MicroVM is long-lived, use standard service-style instrumentation rather than a Lambda layer. Point the SDK at the embedded Collector with these variables:
OTEL_EXPORTER_OTLP_ENDPOINT="http://localhost:4318"
OTEL_SERVICE_NAME="my-microvm-app"
OTEL_RESOURCE_ATTRIBUTES="deployment.environment=production"There is no environment variable flag on run-microvm, so pass these to
--environment-variables when you build the image in
Step 4. Setting them anywhere else has no effect.
See the SigNoz instrumentation guides for your language.
Write your application logs to /var/log/app/ for the filelog receiver from
Step 2 to pick them up, or remove that receiver and
export logs over OTLP from the SDK.
Your directory now holds everything the build needs. Zip it with the Dockerfile at the archive
root and upload it:
zip -r app.zip Dockerfile entrypoint.sh otel-collector-config.yaml app.py
aws s3 cp app.zip s3://<your-bucket>/app.zipVerify these values:
<your-bucket>: The S3 bucket you created for the code artifact.
Step 4: Build the MicroVM image
Export your SigNoz destination so the build command can read it:
export SIGNOZ_ENDPOINT="https://ingest.<region>.signoz.cloud:443"
export SIGNOZ_INGESTION_KEY="<your-ingestion-key>"Then create the image:
aws lambda-microvms create-microvm-image \
--name my-monitored-app \
--code-artifact uri=s3://<your-bucket>/app.zip \
--base-image-arn arn:aws:lambda:<aws-region>:aws:microvm-image:al2023-1 \
--build-role-arn arn:aws:iam::<account-id>:role/MicrovmBuildRole \
--cpu-configurations '[{"architecture":"ARM_64"}]' \
--resources '[{"minimumMemoryInMiB":2048}]' \
--environment-variables "SIGNOZ_ENDPOINT=$SIGNOZ_ENDPOINT,SIGNOZ_INGESTION_KEY=$SIGNOZ_INGESTION_KEY,OTEL_EXPORTER_OTLP_ENDPOINT=http://localhost:4318,OTEL_SERVICE_NAME=my-microvm-app" \
--logging '{"cloudWatch":{"logGroup":"/aws/lambda-microvms/my-monitored-app"}}'Verify these values:
<region>: Your SigNoz Cloud region.<your-ingestion-key>: Your SigNoz ingestion key.<your-bucket>: The S3 bucket holding your code artifact.<aws-region>: The AWS region you are deploying to, for exampleus-east-1. Discover available base images withaws lambda-microvms list-managed-microvm-images.<account-id>: Your AWS account ID.
The build is asynchronous. Poll until the image reports CREATED:
aws lambda-microvms get-microvm-image \
--image-identifier arn:aws:lambda:<aws-region>:<account-id>:microvm-image:my-monitored-appStep 5: Run the MicroVM
aws lambda-microvms run-microvm \
--image-identifier arn:aws:lambda:<aws-region>:<account-id>:microvm-image:my-monitored-app \
--execution-role-arn arn:aws:iam::<account-id>:role/MicrovmExecutionRole \
--ingress-network-connectors "arn:aws:lambda:<aws-region>:aws:network-connector:aws-network-connector:ALL_INGRESS" \
--idle-policy '{"maxIdleDurationSeconds":900,"suspendedDurationSeconds":600,"autoResumeEnabled":true}' \
--maximum-duration-in-seconds 1800MicroVMs have public internet access on the egress path by default, so the Collector reaches SigNoz without extra configuration. Attach a customer-managed egress connector when you want outbound traffic to route through your VPC instead:
--egress-network-connectors "<your-vpc-connector-arn>"Verify these values:
<your-vpc-connector-arn>: The ARN of aLambda Network Connectorin theACTIVEstate.
Create that connector with aws lambda-core create-network-connector and wait for it to reach
ACTIVE before you reference it. See
Networking for Lambda MicroVMs.
run-microvm returns a microvmId and a dedicated HTTPS endpoint for that MicroVM. Every request
to the endpoint needs a token in the X-aws-proxy-auth header, and there is no unauthenticated
access:
aws lambda-microvms create-microvm-auth-token \
--microvm-identifier <microvm-id> \
--expiration-in-minutes 30 \
--allowed-ports '[{"port":8080}]'Verify these values:
<microvm-id>: ThemicrovmIdreturned byrun-microvm.
Validate
Give the Collector a minute, then open SigNoz:
- Traces: your
OTEL_SERVICE_NAMEappears as a service with spans. - Metrics Explorer:
system.memory.usageandsystem.cpu.utilizationare present and filterable byaws.lambda.microvm.image_name. - Logs Explorer: your application log lines appear with the same resource attribute.


To confirm the Collector itself started, check the runtime log group
/aws/lambda-microvms/<image-name> for the line Everything is ready. Begin running and processing data.
Troubleshooting
Image build fails with tar: command not found
Symptom: The build stops with exit code 127 and /bin/sh: line 1: tar: command not found.
- Likely cause:
al2023-minimalships withouttarandgzip. - Fix: Add
RUN dnf install -y tar gzipbefore any step that extracts an archive. The same applies topgrepand otherprocpstools. - Verify: The build reaches
CREATED.
Image build fails for another reason
Symptom: The image reports CREATE_FAILED, or latestFailedImageVersion is set.
- Likely cause: A
Dockerfileinstruction failed. - Fix: Read the build output in the CloudWatch log group you passed to
--logging, which defaults to/aws/lambda-microvms/<image-name>. - Verify: The failing instruction appears with its exit code.
The endpoint returns HTTP 403
Symptom: Requests to the MicroVM endpoint return 403 Forbidden.
- Likely cause: The token is missing, expired, or invalid, or the target port is not in the token's
allowedPorts. - Fix: Mint a new token. Requests route to port 8080 unless you send an
X-aws-proxy-portheader, and whichever port you target must appear inallowedPorts. - Verify: The endpoint returns your application's response.
The endpoint returns HTTP 502
Symptom: Requests to the MicroVM endpoint return 502 Bad Gateway with an empty body.
- Likely cause: Your application is not listening on the target port, it crashed handling the request, or auto-resume did not finish within the retry limit.
- Fix: Check the runtime log group for a stack trace. Confirm your application listens on port 8080, or send
X-aws-proxy-portfor a different one. - Verify: The endpoint returns your application's response.
No system.cpu.utilization in SigNoz
Symptom: system.memory.usage appears but system.cpu.utilization returns no data.
- Likely cause:
system.cpu.utilizationis an optionalhostmetricsmetric, disabled by default. - Fix: Enable it explicitly under the
cpuscraper as shown in Step 2. - Verify: The metric appears in Metrics Explorer.
No logs in SigNoz
Symptom: Traces and metrics arrive but the Logs Explorer is empty.
- Likely cause: The
filelogreceiver watches/var/log/app/*.log, and your application writes to stdout only. - Fix: Write logs to a file under
/var/log/app/, or dropfilelogand export logs over OTLP from the SDK. - Verify: Records appear in Logs Explorer.
The Collector logs Configuration references unset environment variable
Symptom: The Collector cannot resolve ${env:SIGNOZ_ENDPOINT} or ${env:SIGNOZ_INGESTION_KEY}.
- Likely cause: An
update-microvm-imagecall omitted--environment-variables, which drops them from the new version. - Fix: Pass
--environment-variableson every update. - Verify: The Collector starts and exports without warnings.
The API returns HTTP 502 intermittently
Symptom: run-microvm, get-microvm, or list-microvm-images fails with Bad Gateway.
- Likely cause: A transient service error. AWS does not document 502 for these APIs, but it occurs in practice.
- Fix: Retry with exponential backoff. Scripts that poll these APIs need retry handling. AWS documents
ThrottlingExceptionandInternalServerExceptionas retryable, andResourceNotFoundExceptionwhen the image is not yetCREATED. - Verify: The call succeeds on a later attempt.
Limitations
- The CloudWatch Agent cannot forward to SigNoz. AWS's recommended metrics agent for MicroVMs runs on Telegraf and the OpenTelemetry Collector. Its Collector build has no
otlpexporter. Its only OTLP exporter,otlphttp, rejects non-AWS endpoints withinvalid AWS endpoint. The agent exits on either config, which also stops the CloudWatch metrics you already had. Run a separate OpenTelemetry Collector as described above. To get CloudWatch data into SigNoz, pull the/aws/lambda-microvms/<image-name>log group and theLambdaMicroVms/Applicationnamespace through the AWS monitoring integration. - Host metrics reflect guest-visible resources.
hostmetricsreads what the guest kernel reports. Those totals differ from the memory and vCPU baseline you configured, so read them as relative signals rather than capacity numbers. - Metrics stop while a MicroVM is suspended. The embedded Collector survives suspend and resume without restarting. No host metrics are produced during the suspended window, so expect gaps in dashboards.
Optional: CloudTrail lifecycle and audit events
MicroVM lifecycle actions are CloudTrail data events, and CloudTrail does not log them by
default. Enable them with an advanced event selector on the AWS::Lambda::MicrovmImage resource
type.
The selectors below keep management events and add MicroVM data events, so they are safe to apply to a trail that was logging management events by default:
aws cloudtrail put-event-selectors \
--trail-name <your-trail> \
--advanced-event-selectors '[
{
"Name": "Keep management events",
"FieldSelectors": [
{ "Field": "eventCategory", "Equals": ["Management"] }
]
},
{
"Name": "Log Lambda MicroVM data events",
"FieldSelectors": [
{ "Field": "eventCategory", "Equals": ["Data"] },
{ "Field": "resources.type", "Equals": ["AWS::Lambda::MicrovmImage"] }
]
}
]'Verify these values:
<your-trail>: The name of an existing CloudTrail trail in the same region.
The second selector captures RunMicrovm, TerminateMicrovm, SuspendMicrovm, ResumeMicrovm,
CreateMicrovmAuthToken, and CreateMicrovmShellAuthToken. Delivery to S3 takes a few minutes.
Forward the stream into SigNoz using the existing
AWS logs ingestion patterns to build
suspend and resume timelines or security audit dashboards.
Image and MicroVM management calls such as CreateMicrovmImage and ListMicrovms are management
events. CloudTrail logs them by default, and the first selector above preserves that. See
Monitoring for Lambda MicroVMs
for the full event list.
Next steps
- Set up alerts on host metrics and error rates.
- Build dashboards grouped by
aws.lambda.microvm.image_name. - Correlate traces and logs to move between signals during an investigation.
- Monitor AWS Lambda functions for classic, per-invocation Lambda.
Get Help
If you need help with the steps in this topic, please reach out to us on SigNoz Community Slack. If you are a SigNoz Cloud user, please use in product chat support located at the bottom right corner of your SigNoz instance or contact us at cloud-support@signoz.io.