Pular para o conteúdo
, , , ,

Construindo um nano-Lambda: como serverless funciona por dentro [pt.2]

Construa um mini AWS Lambda com Firecracker e Python: execute funções em microVMs isoladas e entenda como serverless funciona por dentro.

Avatar de DK
DKTrabalha com Linux e Unix a mais de 23 anos e possui as certificações LPI 3, RHCE, AIX e VIO.

08 dez, 2025
14 min de leitura

Atualizado em 08/06/2026

Série Firecracker:


No artigo anterior, você subiu sua primeira microVM com Firecracker. Viu o Linux iniciar, entrou pelo terminal, explorou o sistema. Legal, né?

Mas você também deve ter pensado: “Tá, e daí? Subi uma VM mínima… e agora?”

Agora a gente vai fazer algo útil. Vamos construir, em Python e sem instalar nenhuma biblioteca externa, um sistema que funciona parecido com o AWS Lambda.

Você passa uma função. O sistema sobe uma microVM isolada. Executa a função lá dentro. Retorna o resultado. Destrói a VM.

É isso que o Lambda faz, no fundo. Claro, o Lambda real é muito mais sofisticado (mantém VMs prontas pra reusar, tira “fotos” da memória pra restaurar rápido, milhares de otimizações). Mas o conceito central? É esse.

Como o Lambda funciona, versão honesta

Antes de construir, vamos entender o que estamos imitando.

Quando você invoca uma função Lambda, mais ou menos isso acontece:

Como o Lambda funciona

O pulo do gato é que a AWS mantém várias microVMs prontas esperando. Então quando sua requisição chega, geralmente já tem uma VM “quente” disponível. Por isso Lambda consegue responder em milissegundos mesmo sendo VM.

A gente não vai fazer esse esquema de manter VMs prontas. Seria complexo demais pra um artigo. Nosso nano-Lambda vai ser mais simples: uma VM por execução, criada na hora, destruída depois.

Ineficiente? Sim. Didático? Muito.

O que vamos construir

Nosso nano-Lambda vai ser um script Python que:

  1. Recebe o caminho de uma função Python
  2. Configura e inicia uma microVM Firecracker
  3. Copia a função pra dentro da VM (colocando no “disco” dela)
  4. Executa a função
  5. Captura o que a função imprimiu na tela
  6. Para e limpa a VM
  7. Retorna o resultado

E pra exemplo prático, nossa função vai gerar QR Codes. Você passa um texto, recebe uma imagem PNG. Algo visual, útil, que você pode testar com o celular.

Preparando o terreno

Vou assumir que você já tem o Firecracker funcionando do artigo anterior. Se não, volta lá primeiro.

Você vai precisar de:

  • Firecracker binário (já tem)
  • Kernel Linux (já tem)
  • Rootfs customizado (vamos criar): o “disco” da VM com Python instalado
  • Python 3 no seu computador (não na VM, no seu mesmo)

O nano-lambda.py que a gente vai escrever usa só a biblioteca padrão do Python, então você não precisa instalar nada com pip. Confere se o Python 3 está aí:

python3 --version

Saída esperada (qualquer versão 3.8 ou mais nova serve):

Python 3.14.5

Customizando o rootfs

Lembra que usamos um rootfs pronto da AWS no Hello World? Aquele era um Alpine Linux pelado, não tinha nem Python.

Pra rodar funções Python, precisamos de um rootfs com Python instalado. Vamos criar um.

O processo em alto nível

A ideia é simples: criar uma imagem de disco vazia, instalar um Linux mínimo nela, adicionar Python e as bibliotecas que precisamos, e configurar pra executar nossa função no boot.

Passo 1: Criar a imagem de disco

Precisamos de um arquivo que vai funcionar como o “HD” da microVM. Criamos um arquivo vazio e formatamos ele pra virar um disco:

dd if=/dev/zero of=rootfs-python.ext4 bs=1M count=500
mkfs.ext4 rootfs-python.ext4

Saída esperada (o mkfs.ext4 descreve o sistema de arquivos que acabou de criar):

mke2fs 1.47.3 (8-Jul-2025)
Creating filesystem with 512000 1k blocks and 128016 inodes
Filesystem UUID: 7400c39d-70d0-4af1-a87d-ca3d1cb289ac
Superblock backups stored on blocks:
        8193, 24577, 40961, 57345, 73729, 204801, 221185, 401409

Allocating group tables: done
Writing inode tables: done
Creating journal (8192 blocks): done
Writing superblocks and filesystem accounting information: done

500MB é mais que suficiente pro nosso caso.

Passo 2: Montar e instalar o sistema base

Primeiro criamos o ponto de montagem e montamos a imagem como se fosse um disco:

sudo mkdir -p /mnt/rootfs
sudo mount rootfs-python.ext4 /mnt/rootfs

Agora usamos Podman (ou Docker) pra instalar um Alpine Linux mínimo dentro do disco montado. O apk, gerenciador de pacotes do Alpine (tipo apt do Debian ou dnf do Fedora), sabe instalar pacotes numa pasta qualquer com a opção --root:

sudo podman run --rm -v /mnt/rootfs:/rootfs:Z alpine:3.21 sh -c '
    mkdir -p /rootfs/etc/apk
    cp -a /etc/apk/keys /rootfs/etc/apk/
    cp /etc/apk/repositories /rootfs/etc/apk/
    apk add --root /rootfs --initdb --no-cache \
        alpine-base openrc python3 py3-pillow py3-qrcode
'

Nota (Fedora/RHEL): o :Z no final do -v faz o Podman ajustar o rótulo SELinux do diretório. Sem ele, o container leva “Permission denied” ao tentar escrever no /rootfs. No Docker em Ubuntu/Debian o SELinux costuma não estar no caminho, então use o mesmo comando sem o :Z.

A gente copia keys e repositories pra dentro do /rootfs antes do apk porque o --initdb cria o banco de pacotes do zero, sem as chaves de assinatura nem a lista de repositórios. Sem elas o apk não consegue baixar nem validar nada.

Saída esperada (no fim, o apk lista os pacotes que instalou):

fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/main/x86_64/APKINDEX.tar.gz
fetch https://dl-cdn.alpinelinux.org/alpine/v3.21/community/x86_64/APKINDEX.tar.gz
(1/71) Installing alpine-baselayout-data (3.6.8-r1)
(2/71) Installing musl (1.2.5-r11)
...
(38/71) Installing python3 (3.12.13-r0)
...
(61/71) Installing py3-pillow (11.0.0-r0)
...
(70/71) Installing py3-qrcode (7.4.2-r3)
(71/71) Installing py3-qrcode-pyc (7.4.2-r3)
Executing busybox-1.37.0-r14.trigger
OK: 64 MiB in 71 packages

Passo 3: Configurar o sistema

Agora precisamos configurar algumas coisas dentro do rootfs. Pra isso usamos chroot, um comando que “finge” que um diretório é a raiz do sistema. Quando você executa chroot /mnt/rootfs /bin/sh, você abre um shell onde /mnt/rootfs vira /. É como se você tivesse “entrado” no Alpine que acabou de instalar.

sudo chroot /mnt/rootfs /bin/sh

Lá dentro, configuramos algumas coisas. O Alpine mínimo vem com o vi pra edição de arquivos, mas se preferir algo mais amigável, pode instalar o nano:

apk add nano

Hostname e rede básica:

echo "nano-lambda" > /etc/hostname
echo "127.0.0.1 localhost" > /etc/hosts
echo "::1 localhost" >> /etc/hosts

Inittab para Lambda-style. O Alpine usa o arquivo /etc/inittab pra definir o que roda no boot. Por padrão ele abre um terminal de login (getty) que ficaria esperando alguém digitar. Pra nosso caso de Lambda, queremos que a VM rode a função e desligue automaticamente, sem ficar esperando. Então substituímos o inittab padrão por uma versão que executa diretamente nossa função via ::wait:/run-function.sh:

cat > /etc/inittab << 'EOF'
# Configurado para microVM Lambda-style
::sysinit:/sbin/openrc sysinit
::sysinit:/sbin/openrc boot
::wait:/sbin/openrc default
::wait:/run-function.sh
::ctrlaltdel:/sbin/reboot
::shutdown:/sbin/openrc shutdown
EOF

A linha ::wait:/run-function.sh é o segredo: ela diz pro init “depois de rodar o runlevel default, execute esse script e espere ele terminar”. Como o script termina com reboot -f, a VM se desliga sozinha depois de executar a função.

Diretórios de trabalho. Criamos duas pastas: /functions vai receber o código Python que queremos executar (nosso handler.py), e /output é onde a função pode salvar resultados (como o QR Code que vamos gerar):

mkdir -p /functions /output

Script de execução. Esse é o coração do nano-Lambda. Criamos um script que roda no boot, executa nossa função Python, e desliga a VM:

cat > /run-function.sh << 'EOF'
#!/bin/sh
echo "=== nano-Lambda executando... ==="

if [ -f /functions/handler.py ]; then
    cd /functions
    python3 handler.py
    echo "=== Execucao finalizada ==="
else
    echo "ERRO: handler.py nao encontrado"
fi

sync
sleep 1
# reboot -f, e nao poweroff: com reboot=k nos boot_args o kernel faz um reset
# que o Firecracker detecta e encerra o processo. O poweroff so derruba a CPU
# (a VM imprime "System halted") e o Firecracker ficaria preso ate o timeout.
reboot -f
EOF

chmod +x /run-function.sh

Pronto! Agora saimos do chroot com exit.

Passo 4: Limpar e desmontar

Removemos o cache de pacotes (economiza espaço) e “ejetamos” o disco:

sudo rm -rf /mnt/rootfs/var/cache/apk/*
sudo umount /mnt/rootfs

O script pronto

Os passos acima mostram o que está acontecendo por baixo dos panos. Se quiser automatizar, no repositório do artigo tem um script build-rootfs.sh que faz tudo isso. Ele detecta se você tem Docker ou Podman e usa o que estiver disponível.

# Baixa o script
curl -LO https://raw.githubusercontent.com/dklima/firecracker-na-pratica/main/02-nano-lambda/build-rootfs.sh
chmod +x build-rootfs.sh

# Executa (precisa de sudo)
sudo ./build-rootfs.sh

Rodando o script você acompanha o progresso passo a passo. No fim ele mostra:

[6/6] Finalizando...

rootfs-python.ext4 criado com sucesso!
    Tamanho: 89M

O rootfs-python.ext4 fica em torno de 90 MB e contém:

  • Alpine Linux 3.21
  • Python 3.12
  • Pillow (processamento de imagem)
  • qrcode (geração de QR codes)

A função de exemplo: gerador de QR Code

Vamos criar uma função simples que lê um texto de um arquivo e gera um QR Code. O código está comentado explicando o que cada bloco faz.

Salva como exemplo-qrcode/handler.py:

#!/usr/bin/env python3
"""
Função nano-Lambda: Gerador de QR Code

Lê o texto de /functions/input.txt e gera um QR Code.
O resultado é salvo em /output/qrcode.png e também
impresso em base64 no stdout para captura externa.
"""

import qrcode
import sys
import base64

def main():
    # Lê o input do arquivo padrão
    try:
        with open('/functions/input.txt', 'r') as f:
            text = f.read().strip()
    except FileNotFoundError:
        print("ERRO: /functions/input.txt não encontrado")
        sys.exit(1)

    # Valida se tem conteúdo
    if not text:
        print("ERRO: input.txt está vazio")
        sys.exit(1)

    print(f"Gerando QR Code para: {text}")

    # Configura o QR Code
    qr = qrcode.QRCode(
        version=1,                              # Tamanho (1 = menor)
        error_correction=qrcode.constants.ERROR_CORRECT_L,  # Correção de erro
        box_size=10,                            # Pixels por "quadradinho"
        border=4,                               # Borda em "quadradinhos"
    )

    # Adiciona os dados e gera
    qr.add_data(text)
    qr.make(fit=True)

    # Cria a imagem
    img = qr.make_image(fill_color="black", back_color="white")

    # Salva no diretório de output
    output_path = '/output/qrcode.png'
    img.save(output_path)

    # Também imprime em base64 no stdout
    # Isso permite capturar o resultado de fora da VM
    with open(output_path, 'rb') as f:
        img_base64 = base64.b64encode(f.read()).decode('utf-8')

    print(f"QR Code gerado com sucesso!")

    # Marcadores para o nano-lambda.py encontrar a imagem
    print(f"BASE64_IMAGE_START")
    print(img_base64)
    print(f"BASE64_IMAGE_END")

if __name__ == '__main__':
    main()

Essa função:

  1. Lê um texto de /functions/input.txt
  2. Gera um QR Code
  3. Salva em /output/qrcode.png
  4. Imprime a imagem codificada em texto (Base64) pra gente conseguir capturar de fora da VM

O nano-Lambda: controlando Firecracker com Python

Diagrama do fluxo do nano-Lambda

Agora o coração do sistema. Vamos criar um script Python que:

  • Copia a função pro rootfs
  • Inicia o Firecracker
  • Captura o que a VM imprimiu
  • Extrai o resultado e salva

O código está comentado explicando o que cada bloco faz.

Salva como nano-lambda.py:

#!/usr/bin/env python3
"""
nano-Lambda: Um Lambda caseiro usando Firecracker

Executa funções Python em microVMs isoladas.
"""

import subprocess
import socket
import http.client
import json
import time
import shutil
import tempfile
import base64
import signal
import sys
import os

# Configurações
FIRECRACKER_BIN = "./firecracker"
KERNEL_PATH = "./vmlinux.bin"
ROOTFS_TEMPLATE = "./rootfs-python.ext4"
SOCKET_PATH = "/tmp/firecracker-nanolambda.socket"
VCPU_COUNT = 1
MEM_SIZE_MIB = 256

class UnixHTTPConnection(http.client.HTTPConnection):
    """
    Conexão HTTP sobre um socket Unix.

    A API do Firecracker fala HTTP, mas escuta num socket Unix em vez
    de uma porta TCP. A stdlib do Python não conversa com socket Unix
    direto, então estendemos HTTPConnection e trocamos só o connect().
    """

    def __init__(self, socket_path):
        super().__init__("localhost")
        self.socket_path = socket_path

    def connect(self):
        sock = socket.socket(socket.AF_UNIX, socket.SOCK_STREAM)
        sock.connect(self.socket_path)
        self.sock = sock

class NanoLambda:
    def __init__(self):
        self.socket_path = SOCKET_PATH
        self.fc_process = None
        self.temp_rootfs = None
        self.output_file = "/tmp/firecracker-output.log"

    def _call_api(self, method, path, data=None):
        """Faz chamada para a API REST do Firecracker via socket Unix."""
        conn = UnixHTTPConnection(self.socket_path)
        body = json.dumps(data) if data is not None else None
        headers = {"Content-Type": "application/json", "Accept": "application/json"}

        conn.request(method, path, body=body, headers=headers)
        resp = conn.getresponse()
        payload = resp.read().decode("utf-8", "replace")
        conn.close()

        if resp.status >= 400:
            raise Exception(f"API error {resp.status}: {payload}")

        return payload

    def prepare_rootfs(self, function_path, input_data):
        """Prepara o rootfs com a função e input"""
        self.temp_rootfs = tempfile.NamedTemporaryFile(
            suffix='.ext4',
            delete=False
        ).name

        print(f"[*] Copiando rootfs template...")
        shutil.copy(ROOTFS_TEMPLATE, self.temp_rootfs)

        mount_point = tempfile.mkdtemp()

        try:
            print("[*] Montando rootfs temporario...")
            subprocess.run(
                ["mount", self.temp_rootfs, mount_point],
                check=True
            )

            # Copia a funcao para /functions/handler.py
            print(f"[*] Copiando funcao: {function_path}")
            func_dest = os.path.join(mount_point, "functions", "handler.py")
            shutil.copy(function_path, func_dest)

            # Escreve o input em /functions/input.txt
            input_dest = os.path.join(mount_point, "functions", "input.txt")
            with open(input_dest, 'w') as f:
                f.write(input_data)

        finally:
            subprocess.run(["umount", mount_point], check=True)
            os.rmdir(mount_point)

    def start_firecracker(self):
        """Inicia o processo Firecracker"""
        if os.path.exists(self.socket_path):
            os.remove(self.socket_path)

        if os.path.exists(self.output_file):
            os.remove(self.output_file)

        print(f"[*] Iniciando Firecracker...")
        self.output_handle = open(self.output_file, 'w')
        self.fc_process = subprocess.Popen(
            [FIRECRACKER_BIN, "--api-sock", self.socket_path],
            stdout=self.output_handle,
            stderr=subprocess.STDOUT
        )

        for _ in range(50):
            if os.path.exists(self.socket_path):
                break
            time.sleep(0.1)
        else:
            raise Exception("Timeout esperando socket do Firecracker")

        time.sleep(0.2)

    def configure_vm(self):
        """Configura a microVM via API"""
        print(f"[*] Configurando kernel...")
        self._call_api("PUT", "/boot-source", {
            "kernel_image_path": KERNEL_PATH,
            "boot_args": "console=ttyS0 reboot=k panic=1 pci=off quiet"
        })

        print(f"[*] Configurando rootfs...")
        self._call_api("PUT", "/drives/rootfs", {
            "drive_id": "rootfs",
            "path_on_host": self.temp_rootfs,
            "is_root_device": True,
            "is_read_only": False
        })

        print(f"[*] Configurando recursos ({VCPU_COUNT} vCPU, {MEM_SIZE_MIB}MB RAM)...")
        self._call_api("PUT", "/machine-config", {
            "vcpu_count": VCPU_COUNT,
            "mem_size_mib": MEM_SIZE_MIB
        })

    def run_vm(self, timeout=30):
        """Inicia a VM e aguarda execução"""
        print(f"[*] Iniciando microVM...")
        self._call_api("PUT", "/actions", {"action_type": "InstanceStart"})

        print(f"[*] Aguardando execução (timeout: {timeout}s)...")

        start_time = time.time()
        while time.time() - start_time < timeout:
            if self.fc_process.poll() is not None:
                break
            time.sleep(0.5)

        self.output_handle.close()

        if self.fc_process.poll() is None:
            self.fc_process.terminate()
            try:
                self.fc_process.wait(timeout=5)
            except subprocess.TimeoutExpired:
                self.fc_process.kill()
                self.fc_process.wait()

        if os.path.exists(self.output_file):
            with open(self.output_file, 'r') as f:
                output = f.read()
        else:
            output = ""

        return output

    def cleanup(self):
        """Limpa recursos"""
        print(f"[*] Limpando...")

        if hasattr(self, 'output_handle') and not self.output_handle.closed:
            self.output_handle.close()

        if self.fc_process and self.fc_process.poll() is None:
            self.fc_process.terminate()
            try:
                self.fc_process.wait(timeout=5)
            except subprocess.TimeoutExpired:
                self.fc_process.kill()

        if self.temp_rootfs and os.path.exists(self.temp_rootfs):
            os.remove(self.temp_rootfs)

        if os.path.exists(self.socket_path):
            os.remove(self.socket_path)

        if os.path.exists(self.output_file):
            os.remove(self.output_file)

    def invoke(self, function_path, input_data):
        """Invoca uma função Lambda-style"""
        try:
            self.prepare_rootfs(function_path, input_data)
            self.start_firecracker()
            self.configure_vm()
            output = self.run_vm()
            return self.parse_output(output)
        finally:
            self.cleanup()

    def parse_output(self, raw_output):
        """Extrai resultado do output bruto"""
        # Procura pelo marcador de imagem base64
        if "BASE64_IMAGE_START" in raw_output and "BASE64_IMAGE_END" in raw_output:
            start = raw_output.find("BASE64_IMAGE_START") + len("BASE64_IMAGE_START")
            end = raw_output.find("BASE64_IMAGE_END")
            base64_data = raw_output[start:end].strip()
            return {
                "success": True,
                "type": "image",
                "data": base64_data
            }

        return {
            "success": False,
            "type": "text",
            "data": raw_output
        }

def main():
    # Precisa de root para montar o rootfs e executar o Firecracker
    if os.geteuid() != 0:
        print("Erro: Este script precisa ser executado como root.")
        print("Uso: sudo python3 nano-lambda.py <funcao.py> <input />")
        sys.exit(1)

    if len(sys.argv) < 3:
        print("Uso: sudo python3 nano-lambda.py <funcao.py> <input />")
        print("Exemplo: sudo python3 nano-lambda.py exemplo-qrcode/handler.py 'https://meusite.com'")
        sys.exit(1)

    function_path = sys.argv[1]
    input_data = sys.argv[2]

    if not os.path.exists(function_path):
        print(f"Erro: funcao nao encontrada: {function_path}")
        sys.exit(1)

    # Confere se firecracker, kernel e rootfs estao no diretorio atual
    for f, desc in [(FIRECRACKER_BIN, "Firecracker"), (KERNEL_PATH, "Kernel"), (ROOTFS_TEMPLATE, "Rootfs")]:
        if not os.path.exists(f):
            print(f"Erro: {desc} nao encontrado: {f}")
            print("Execute primeiro o build-rootfs.sh e baixe o Firecracker e o kernel.")
            sys.exit(1)

    print("=" * 50)
    print("nano-Lambda: Executando funcao em microVM isolada")
    print("=" * 50)
    print(f"Funcao: {function_path}")
    print(f"Input: {input_data}")
    print()

    lambda_runner = NanoLambda()

    # Limpa os recursos se o usuario apertar Ctrl+C no meio
    def signal_handler(signum, frame):
        print("\n[!] Interrompido pelo usuario. Limpando recursos...")
        lambda_runner.cleanup()
        sys.exit(130)  # 128 + SIGINT(2)

    signal.signal(signal.SIGINT, signal_handler)
    signal.signal(signal.SIGTERM, signal_handler)

    result = lambda_runner.invoke(function_path, input_data)

    print()
    print("=" * 50)
    print("Resultado:")
    print("=" * 50)

    if result["success"] and result["type"] == "image":
        output_file = "resultado-qrcode.png"
        img_data = base64.b64decode(result["data"])
        with open(output_file, "wb") as f:
            f.write(img_data)
        print(f"QR Code salvo em: {output_file}")
        print(f"Tamanho: {len(img_data)} bytes")
        print()
        print("Escaneie com seu celular para testar!")
    else:
        print("Output bruto da VM:")
        print(result["data"])

if __name__ == "__main__":
    main()

Testando!

Agora é a hora da verdade. Com tudo preparado:

# Estrutura esperada no diretório:
# .
# |-- firecracker          (binário)
# |-- vmlinux.bin          (kernel)
# |-- rootfs-python.ext4   (rootfs customizado)
# |-- nano-lambda.py       (nosso script)
# `-- exemplo-qrcode/
#     `-- handler.py       (função de exemplo)

# Executando
sudo python3 nano-lambda.py exemplo-qrcode/handler.py "https://fogonacaixadagua.com.br"

Se tudo der certo, você vai ver algo assim:

==================================================
nano-Lambda: Executando função em microVM isolada
==================================================
Função: exemplo-qrcode/handler.py
Input: https://fogonacaixadagua.com.br

[*] Copiando rootfs template...
[*] Montando rootfs temporário...
[*] Copiando função: exemplo-qrcode/handler.py
[*] Iniciando Firecracker...
[*] Configurando kernel...
[*] Configurando rootfs...
[*] Configurando recursos (1 vCPU, 256MB RAM)...
[*] Iniciando microVM...
[*] Aguardando execução (timeout: 30s)...
[*] Limpando...

==================================================
Resultado:
==================================================
QR Code salvo em: resultado-qrcode.png
Tamanho: 562 bytes

Escaneie com seu celular para testar!

A execução inteira leva uns 3 a 4 segundos: a maior parte é pra ligar e desligar a microVM, não pra rodar a função.

Abre o arquivo resultado-qrcode.png. Aponta a câmera do celular. Se abrir o site, funcionou!

Troubleshooting: Se o script der erro no meio da execução, pode ser que tenha ficado uma montagem presa. Verifique com mount | grep tmp e desmonte manualmente com sudo umount /tmp/tmp.* se necessário.

Você acabou de executar código Python dentro de uma microVM completamente isolada, que você controlou do início ao fim. Isso é, em essência, o que o AWS Lambda faz.

O que simplificamos vs Lambda real

Pra ser honesto, nosso nano-Lambda é um brinquedo comparado com o Lambda de verdade. Algumas diferenças:

VMs prontas pra reusar: Lambda mantém VMs “quentes” esperando. A gente cria uma nova toda vez. Muito mais lento.

Fotos da memória: Lambda tira “screenshots” do estado da VM pra restaurar instantaneamente depois. A gente não fez isso.

Internet: Nossas microVMs não têm acesso à internet. Lambda configura rede completa.

Várias linguagens: Lambda suporta Node, Python, Java, Go, .NET, Ruby… A gente só fez Python.

Escala: Lambda aguenta milhares de execuções ao mesmo tempo. A gente roda uma por vez.

Logs e monitoramento: Lambda tem CloudWatch integrado. A gente só vê o que aparece na tela.

Mas… o conceito central tá ali. Você entendeu como funciona. Agora quando usar Lambda, vai saber o que acontece por baixo.

Experimentando mais

Algumas ideias se quiser continuar explorando:

Outras funções: Tenta criar uma função que faz algo diferente. Processamento de texto, cálculos, validações. Só precisa ler de /functions/input.txt e imprimir o resultado na tela.

Medição de tempo: Adicione marcações de tempo no nano-lambda.py pra ver quanto cada etapa demora. Você vai notar que a maior parte do tempo é pra ligar a VM, não pra rodar a função.

Várias execuções: Modifique pra rodar a mesma função várias vezes e veja a média de tempo.

Internet na VM: Se quiser que a VM acesse a internet, tem que configurar rede virtual no seu computador. Mais complexo, mas possível, e é o tema do próximo artigo!

Conclusão

Você construiu um Lambda caseiro. Não vai substituir o Lambda da AWS (óbvio), mas agora você entende o que acontece quando faz aws lambda invoke.

Firecracker é uma tecnologia fascinante. Ela resolve um problema real, isolamento com velocidade, de forma elegante. E o fato de ser open source significa que você pode estudar, experimentar, e até contribuir.

No próximo artigo, vamos configurar rede no Firecracker, fazer a VM ter acesso à internet de verdade. Aí sim as possibilidades ficam interessantes.

Até lá!


Este artigo faz parte da série “Firecracker: MicroVMs na Prática”. Todo o código está disponível em GitHub.

Avatar de DK

Comentários

Comentários fechados para visitantes. Entre ou registre-se para comentar.

Ir para