Lambda MicroVMs で capabilities 付きのサンドボックス環境を立ち上げシェルに入り docker run する

awslinux

Lambda MicroVMs は Lambda Functions でも使われている Linux Kernel-based Virtual Machine (KVM) の Virtual Machine Monitor (VMM) Firecracker によるサンドボックスを提供するサービス。

料金はコンピューティングリソースとスナップショットデータに対してかかる。まだリリースされたばかりだからか日本語の料金ページには表記がないのと Functions からタブを切り替えないと表示されず見つけづらかった。デフォルト 1vCPU / 2GB のベースラインに加えて 4 倍まで自動でスケールした分の課金が発生する。また、環境が維持できるのは 8 時間までだが中断することもできて、その間はコンピューティングの料金はかからない。なので一ヶ月 1vCPU / 2GB で常に動かすと大体 $0.13/hour くらいと EC2 の t2.small (1vCPU/2GB, $0.0304/hour) と比べると 4-5 倍割高な水準ではあるが、IdlePolicy で自動中断/起動させたりすることでサーバーレスらしく需要に応じて安価に使い捨ての環境を立ち上げることができる。

コードと Dockerfile を zip で固めて 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"]

S3 のパスを code-artifact で指定して image を作る

$ 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

MicroVM を立ち上げる。13-15 秒ほどで起動した。なお停止後 auto resume する際は 1.3 秒でレスポンスが返ってきた。 ドキュメントでは ingress-network-connectors に ALL_INGRESS を指定していたが、これには 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}'

token を取得し HTTP リクエストを送るとレスポンスが返ってくる。

$ 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":"/"}

shell-auth-token を取得し websocket で接続するとシェルにアクセスできる。

$ 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"

CI/CD 環境として使うと docker が必要になることがあるが、デフォルトでは dockerd を起動しようとしても cgroup を mount できず失敗する。

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

create-microvm-image 時に additional-os-capabilities を渡すと dockerd が動き docker run も実行できるようになる。

λ $
^[[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/