Launching a Sandbox Environment with Capabilities on Lambda MicroVMs, Entering a Shell, and Running docker run

awslinux

Lambda MicroVMs is a service that provides a sandbox based on Firecracker, the Linux Kernel-based Virtual Machine (KVM) Virtual Machine Monitor (VMM) also used by Lambda Functions.

Pricing is charged for compute resources and snapshot data. Perhaps because it was only just released, it wasn’t listed on the Japanese pricing page, and it was hard to find, since you have to switch tabs away from Functions to see it. On top of the default 1vCPU / 2GB baseline, you’re charged for scaling automatically up to 4x. The environment can be kept alive for up to 8 hours, but it can also be suspended, during which no compute charges apply. So running 1vCPU / 2GB continuously for a month costs roughly $0.13/hour, which is about 4-5x more expensive than an EC2 t2.small (1vCPU/2GB, $0.0304/hour), but with IdlePolicy automatically suspending and resuming the environment, you can spin up disposable environments cheaply based on demand, in a serverless manner.

Package the code and Dockerfile into a zip and upload it to S3.

$ tree microvm-app/
microvm-app/
├── Dockerfile
└── app.js

$ cat microvm-app/app.js 
const http = require('http');

const server = http.createServer((req, res) => {
  res.writeHead(200, { 'Content-Type': 'application/json' });
  res.end(JSON.stringify({ status: 'ok', path: req.url }));
});

server.listen(8080, () => {
  console.log('Listening on port 8080');
});

$ cat microvm-app/Dockerfile 
FROM node:24-alpine

WORKDIR /app

COPY app.js .

EXPOSE 8080

CMD ["node", "app.js"]

Build an image by specifying the S3 path as the code-artifact.

$ aws lambda-microvms create-microvm-image \
    --name my-first-microvm-image \
    --code-artifact uri=s3://****/app.zip \
    --base-image-arn arn:aws:lambda:ap-northeast-1:aws:microvm-image:al2023-1 \
    --build-role-arn arn:aws:iam::*****:role/MicrovmBuildRole

Launch a MicroVM. It took about 13-15 seconds to start up; after suspending, auto resume returned a response in 1.3 seconds. For ingress-network-connectors, the documentation specifies ALL_INGRESS, but that doesn’t seem to include SHELL_INGRESS.

$ aws lambda-microvms run-microvm \
    --image-identifier arn:aws:lambda:ap-northeast-1:*****:microvm-image:my-first-microvm-image \
    --ingress-network-connectors "arn:aws:lambda:ap-northeast-1:aws:network-connector:aws-network-connector:HTTP_INGRESS" "arn:aws:lambda:ap-northeast-1:aws:network-connector:aws-network-connector:SHELL_INGRESS" \
    --egress-network-connectors "arn:aws:lambda:ap-northeast-1:aws:network-connector:aws-network-connector:INTERNET_EGRESS" \
    --idle-policy '{"autoResumeEnabled":true,"maxIdleDurationSeconds":900,"suspendedDurationSeconds":300}'

Getting a token and sending an HTTP request returns a response.

$ TOKEN=$(aws lambda-microvms create-microvm-auth-token --microvm-identifier <ID> --expiration-in-minutes 30 --allowed-ports '[{"allPorts":{}}]' --query authToken --output text)
$ curl -sS https://****.lambda-microvm.ap-northeast-1.on.aws/ -H "X-aws-proxy-auth: $TOKEN"
{"status":"ok","path":"/"}

Getting a shell-auth-token and connecting over websocket gives shell access.

$ TOKEN=$(aws lambda-microvms create-microvm-shell-auth-token --microvm-identifier <ID> --expiration-in-minutes 30 --query 'authToken."X-aws-proxy-auth"' --output text)
$ websocat "wss://****.lambda-microvm.ap-northeast-1.on.aws/shell" -H "X-aws-proxy-auth: $TOKEN"
{"type":"session_init","session_id":"18f38694-f3c5-43a5-b18f-c49016b26f3c"}
λ $
cat /etc/os-release
NAME="Alpine Linux"  ID=alpine  VERSION_ID=3.24.1  PRETTY_NAME="Alpine Linux v3.24"  HOME_URL="https://alpinelinux.org/"  BUG_REPORT_URL="https://gitlab.alpinelinux.org/alpine/aports/-/issues"

Using this as a CI/CD environment may require docker, but by default, starting dockerd fails because the cgroup can’t be mounted.

INFO[2026-08-09T15:34:30.424991592Z] Daemon shutdown complete                      error="failed to start daemon: Devices cgroup isn't mounted"  failed to start daemon: Devices cgroup isn't mounted

Passing additional-os-capabilities at create-microvm-image time makes dockerd start, and docker run works too.

λ $
^[[28;5R
docker run hello-world
  Hello from Docker!  This message shows that your installation appears to be working correctly.    To generate this message, Docker took the following steps:   1. The Docker client contacted the Docker daemon.   2. The Docker daemon pulled the "hello-world" image from the Docker Hub.      (arm64v8)   3. The Docker daemon created a new container from that image which runs the      executable that produces the output you are currently reading.   4. The Docker daemon streamed that output to the Docker client, which sent it      to your terminal.    To try something more ambitious, you can run an Ubuntu container with:   $ docker run -it ubuntu bash    Share images, automate workflows, and more with a free Docker ID:   https://hub.docker.com/    For more examples and ideas, visit:   https://docs.docker.com/get-started/