PTEN

Lambda MicroVMs: shell na Lambda, lifecycle hooks e as best practices que importam

Lambda MicroVMs aceita shell. Como conectar, implementar lifecycle hooks em Node e aplicar as best practices de performance, segurança e custo.

Autor
Will Peixoto
Publicado
20 out 2026
Leitura
11 min
Idioma
PT

🇺🇸 Also available in English: Lambda MicroVMs: shell access, lifecycle hooks and the best practices that matter

Deixa eu te contar uma cena que quem é de infra vai reconhecer na hora. Quando a Lambda nasceu, lá em 2014, e começou a se espalhar, a galera de infraestrutura chegava e perguntava: "mas como eu conecto na Lambda para ver se está rodando? Dar um ps, um tail, olhar a aplicação por dentro?". E a resposta era sempre a mesma: não conecta. Função é caixa preta, você olha pelo CloudWatch e reza.

Pois é. Com o Lambda MicroVMs, agora dá para conectar um shell de verdade. =D Neste post eu mostro como abrir esse shell, como implementar em Node os lifecycle hooks que mantêm a MicroVM saudável, e as best practices oficiais de performance, segurança e custo.

Conectar um shell na Lambda MicroVM

Tem dois caminhos. No console, você seleciona a MicroVM e clica em Connect. No CLI, você gera um token de shell e conecta:

bash
aws lambda-microvms create-microvm-shell-auth-token \
  --microvm-identifier <id> --expiration-in-minutes 30

# já dentro, lista e entra na task:
ctr task ls
ctr task exec -t --exec-id shell <id> /bin/sh

Shell é opt-in. A MicroVM precisa ter sido lançada com o network connector SHELL_INGRESS, e se ela subiu sem esse connector o create-microvm-shell-auth-token devolve um ValidationException. Como os connectors são definidos no run-microvm e não mudam com a MicroVM rodando, você decide na largada quais MicroVMs aceitam essa porta de entrada.

Para o resto do debug, três campos ajudam muito: o terminationMessage no get-microvm (para MicroVM que morreu), os logs de build no CloudWatch em /aws/lambda-microvms/<image-name>, e o StateReason quando um network connector fica em FAILED.

Lifecycle hooks: o que segura a MicroVM de pé

Lembra do caveat do snapshot (a MicroVM sobe de um estado congelado, então o que precisa ser fresco não pode estar congelado)? A AWS resolve isso com lifecycle hooks: quatro endpoints HTTP que a sua app implementa e que o serviço chama com um POST na hora certa.

  • /run: pós-inicialização. É aqui que você gera UUIDs, secrets e valores aleatórios, nunca no build da imagem, senão todas as MicroVMs nascem com o mesmo “aleatório”. Use CSPRNG. O /run também recebe no body o runHookPayload (config por MicroVM, como o ID do tenant, numa string de até 16 KB que você passa com --run-hook-payload no run-microvm) e o microvmId, que o Lambda injeta.

  • /suspend: limpeza graciosa antes de suspender (flush de escrita pendente, fechar conexão, liberar recurso).

  • /resume: revalida conexões e estado em cache. Conexão de AWS SDK costuma se recuperar sozinha; conexão custom pode não se recuperar, então cheque aqui. A MicroVM continua SUSPENDED enquanto esse hook roda e só vira RUNNING quando ele responde 200.

  • /terminate: flush de dados antes de encerrar. Ele só roda na terminação final; antes de suspender, quem trabalha é o /suspend.

Os hooks chegam no path /aws/lambda-microvms/runtime/v1/<hook>, numa porta que você configura, e o tráfego externo só começa a entrar depois que o /run responde 200. Se o /run falhar ou estourar o timeout, a MicroVM pode ir direto para TERMINATING sem nunca chegar em RUNNING, então trate erro e timeout dentro do hook.

Sobre a porta: a doc não manda separar hooks e app, e no exemplo abaixo os dois dividem a 8080, que é a porta default do tráfego externo. Vale decidir isso de propósito, olhando quais portas o token de acesso libera no allowedPorts.

Também existem dois hooks da fase de build da imagem. O /ready responde 200 quando a app terminou de iniciar, e aí o serviço tira o snapshot de disco e memória (enquanto não está pronto, você devolve 503 na hora e o Lambda tenta de novo até o timeout). O /validate é chamado depois do build, numa MicroVM nova criada a partir da imagem: ali você roda payloads de teste que exercitam os code paths, e o Lambda rastreia quais regiões do snapshot foram acessadas para fazer prefetch delas e reduzir a latência no startup. O /ready garante que o snapshot pega a app pronta; o /validate é o que ajuda no tempo de boot.

![Diagrama de sequência do ciclo de vida de uma MicroVM: o hook /ready libera o snapshot, o /validate roda numa MicroVM criada da imagem, depois o /run libera o tráfego e o ciclo suspend, resume e terminate acontece no runtime](https://cdn.hashnode.com/uploads/gql/615b22eead6beb6f6506f2b9/2022a311-7f39-497d-ad59-1c155ea8a6a4.png align=“center”)

No nosso Node HTTP server fica assim:

js
const http = require("http");
const crypto = require("crypto");

let sessionSecret; // gerado no /run, NUNCA no build da imagem

function ok(res, body) {
  res.writeHead(200, { "Content-Type": "application/json" });
  res.end(JSON.stringify(body));
}

const server = http.createServer((req, res) => {
  const HOOK = "/aws/lambda-microvms/runtime/v1";
  switch (req.url) {
    case `${HOOK}/run`:        // aleatoriedade e init vivem aqui; responda 200 antes do tráfego entrar
      sessionSecret = crypto.randomUUID();
      return ok(res, { ready: true });
    case `${HOOK}/suspend`:    // limpeza antes de congelar
      return ok(res, { cleanedUp: true });
    case `${HOOK}/resume`:     // revalida conexoes/estado ao acordar
      return ok(res, { revalidated: true });
    case `${HOOK}/terminate`:  // flush de dados ao encerrar
      return ok(res, { flushed: true });
    default:
      // ... a sua aplicacao de verdade
      return ok(res, { hello: "world" });
  }
});

server.listen(8080, "0.0.0.0");

Se a app não responder depois de um resume, o suspeito número um é não ter o /resume implementado (ou a app não estar bindando na porta certa, tipo 8080, depois que acorda).

Prova rápida: o snapshot congela o seu “aleatório”

Aquele aviso de gerar aleatoriedade no /run parece detalhe até você medir. Montei uma demo pequena que roda local, na minha máquina: sem AWS, sem custo, só Node stdlib. Ela simula o build gerando o snapshot e sobe duas “MicroVMs” a partir dele. O código vai junto com o post da demo, o finale da série.

O resultado, capturado de verdade:

texto
== 3. antes do /run: o servico nao entrega trafego ==
amostra-A  GET /  -> HTTP 503

== 5. depois do /run 200: trafego liberado ==
amostra-A  GET /  -> HTTP 200

== 6. veredito ==
token gerado no BUILD  A vs B: IGUAL     <- colide entre analises
   A: 6fcf9c71-2024-4901-acfb-2593ed5a2fbb
   B: 6fcf9c71-2024-4901-acfb-2593ed5a2fbb
token gerado no /run   A vs B: diferente <- ok
   A: 2011db3c-3120-4b9a-b89d-caa48b034c8f
   B: 496f5bfc-7c7f-4cd7-b39f-2ea3c9b8c281

Dá para ver as duas coisas na mesma saída: o token assado no build nasce idêntico nas duas, e o tráfego só passa a 200 depois que o /run responde.

Importante: essa demo não roda em Lambda MicroVMs. Ela exercita o contrato dos hooks localmente, com um snapshot.json no lugar do congelamento real. Serve para ver o comportamento. Prova do serviço de verdade só rodando numa MicroVM na AWS, e isso fica para o post da demo, o finale da série.

Best practices oficiais, organizadas por pilar

Performance. Escolha a menor MicroVM que atende o seu CPU, memória e banda (a banda escala com a memória configurada). Minimize o snapshot: remova dependências de build e arquivos temporários antes de a imagem ser capturada, isso reduz o tempo de run e de resume. E para workload sensível a latência, mantenha os ambientes mais usados em suspended para resumir rápido.

Segurança. Gere tokens curtos (15 a 30 min) e tenha lógica de refresh no cliente antes de expirar. Limite o token às portas que a app usa, com o parâmetro allowedPorts. Tráfego sensível (banco, API interna) vai por um VPC egress connector, que passa pelos seus security groups e network ACLs. E aplique least-privilege: separe a role de build (criação da imagem) da role de execução (runtime), cada uma com o mínimo. Detalhe útil: o /ready e o /validate rodam sob a role de build, e os hooks de runtime rodam sob a de execução.

Custo. Configure maxIdleDurationSeconds na idle policy para suspender MicroVM ociosa (suspensa não paga compute, só o storage do snapshot). Ponha um teto de segurança com a duração máxima (--maximum-duration-in-seconds no CLI, até 8 horas, somando tempo rodando e suspenso) para não tomar susto na fatura com instância esquecida. Use suspendedDurationSeconds para terminar sozinha a MicroVM que ficou tempo demais parada. Coloque tags nas imagens para cost allocation no Cost Explorer, e apague as versões de imagem que você não usa mais, porque elas também custam storage.

Antes de decidir quanto isolamento e quanta disponibilidade o seu caso pede, vale olhar o custo de cada degrau. Eu abri essa conta no post sobre o custo da resiliência: HA, multi-região ou on-premise.

Apps de browser: um proxy na frente da MicroVM

App que roda no navegador (um VS Code server, um IDE web) esbarra numa regra da doc: toda request para o endpoint da MicroVM precisa do token JWE no header X-aws-proxy-auth, e não existe opção sem autenticação. Quando o usuário abre uma URL, clica num link ou carrega um iframe, o browser não deixa você colocar esse header. Para WebSocket aberto pelo seu JavaScript, a doc oferece passar token e porta como subprotocols (lambda-microvms.authentication.<token>), mas isso não resolve a navegação comum.

A saída de arquitetura é um reverse proxy seu na frente (o pattern Gateway): um componente que recebe a request do browser já autenticada do jeito da sua app, busca ou gera o token da MicroVM e injeta o X-aws-proxy-auth antes de repassar. Ele também precisa de um mapa usuário → MicroVM, porque cada MicroVM tem o próprio endpoint e não há load balancing entre elas. Com esse mapa, quando o usuário fecha a aba e volta depois, você sabe para qual instância rotear. O orquestrador que já chama o run-microvm é um candidato natural para guardar esse mapa.

Se o problema for só domínio próprio, a AWS publicou um pattern com Application Load Balancer que reescreve o Host header, mas ali o cliente continua tendo que mandar o token. Ele não substitui o proxy de autenticação.

Se o que vai orquestrar essas MicroVMs é um agente de IA operando a sua conta, o outro lado dessa moeda é o controle de permissão, que eu tratei em AWS MCP Server: qual usar, quando e como configurar.

Os erros que você vai ver (e o que fazer)

Da tabela de troubleshooting da doc, os que eu deixaria anotados:

  • 502 Bad Gateway: a app caiu ou não está escutando. Cheque o EXPOSE e o CMD do Dockerfile e os logs de runtime. Com auto-resume ligado, também pode ser a MicroVM que não conseguiu resumir (confira o estado com get-microvm).

  • 429 Too Many Requests: você passou do rate (da conta ou da MicroVM). Retry com backoff exponencial e jitter.

  • Conexões caindo: timeout de ocioso. Implemente keepalive (ping/pong) ou aumente o maxIdleDurationSeconds.

  • Build falhou (CREATION_FAILED): olhe os logs em /aws/lambda-microvms/<image-name>, confira a sintaxe do Dockerfile e as permissões de S3 da role de build. Rode docker build local para reproduzir.

E o monitoramento básico: quando uma MicroVM termina do nada, o get-microvm traz o stateReason com o motivo. É o primeiro lugar para olhar.

O que você leva

  • Dá para dar shell na Lambda agora, via console ou create-microvm-shell-auth-token, mas só se a MicroVM subiu com o connector SHELL_INGRESS.

  • Os lifecycle hooks (/run, /suspend, /resume, /terminate) são o que mantém a MicroVM saudável. Gere aleatoriedade no /run, revalide conexão no /resume, e use o /validate para encurtar o boot.

  • Segurança: token curto com refresh, escopo por porta, VPC egress, e role de build separada da de execução.

  • Custo: suspenda no ocioso, ponha teto de duração, termine o que ficou parado e limpe versão de imagem que não usa.

Fontes

Tem um caso de uso de MicroVM rodando aí? Conta qual hook te salvou (ou te queimou por não ter). E se você é de infra e sempre quis dar um shell na Lambda, agora é a sua hora. Manda aquele joinha, compartilha, e bora trocar ideia. Valeu demais!

BUILD. SCALE. REPEAT. =D

Will Peixoto

Will Peixoto é Staff Engineer na Serverless Guru e escreve sobre serverless, arquitetura e agentes de IA na AWS: o que ele escolheria, por quê e quanto custa.

Mais da série

Post novo direto no seu email

Um tema de serverless, arquitetura ou agentes de IA na AWS por edição: o que eu escolheria, por quê e quanto custa. Zero spam.

Abre a página de inscrição numa nova aba.