Série Firecracker:
- Parte 01: Firecracker
- Parte 02: Construindo um nano-Lambda
- Parte 03: Redes no Firecracker
- Parte 04: Snapshots
- Parte 05: Firecracker em produção (você está aqui)
Nos artigos anteriores, a gente construiu um nano-Lambda funcional. Sobe microVM, executa função, derruba microVM. Com rede. Com snapshots pra performance. Tudo lindo.
Mas tem um problema: você tá rodando tudo na mão. sudo python3 nano-lambda.py toda vez. Se o servidor reiniciar às 3h da manhã? A microVM sumiu. Se o processo morrer por falta de memória? Ninguém vai saber. Se você precisar rodar 5 VMs diferentes? Abre 5 terminais.
Isso não é produção. Isso é um demo.
Hoje a gente transforma o demo em serviço de verdade. Vamos usar o systemd, o gerenciador de serviços que já vem no seu Linux, pra fazer as microVMs:
- Iniciarem automaticamente no boot do servidor
- Reiniciarem se morrerem
- Terem rede configurada automaticamente
- Registrarem logs consultáveis
- Rodarem com isolamento de segurança
Por que systemd?
Se você já trabalhou com servidores Linux, provavelmente já usou systemd sem perceber. systemctl start nginx, systemctl enable postgresql… tudo isso é systemd.
O systemd é o “init system” da maioria das distros modernas. Ele é o primeiro processo que roda quando o Linux inicia (PID 1), e é responsável por subir todos os outros serviços na ordem certa.
Pra nossa microVM, o systemd resolve vários problemas de uma vez:
| Problema | Solução systemd |
|---|---|
| “Esqueci de iniciar a VM” | systemctl enable, inicia no boot |
| “A VM morreu e ninguém viu” | Restart=on-failure, reinicia automático |
| “Cadê os logs?” | journalctl -u, logs centralizados |
| “A rede não subiu antes da VM” | After=network.target, dependências |
| “Preciso de 5 VMs iguais” | Templates com @, uma unit, N instâncias |
O que vamos construir
Vamos pegar o nano-Lambda do artigo 03 (o validador de URLs com rede) e transformar ele em serviço. O resultado final:
# Inicia a microVM como serviço
sudo systemctl start nano-lambda
# Verifica status
sudo systemctl status nano-lambda
# Vê os logs
sudo journalctl -u nano-lambda -f
# Habilita pra iniciar no boot
sudo systemctl enable nano-lambda
A rede (interface TAP, NAT, regras de firewall) vai ser configurada automaticamente quando o serviço iniciar, e limpa quando parar.
Pré-requisito: Se você não leu o artigo 03 sobre redes, leia antes de continuar. Lá a gente explica por que a configuração de rede funciona assim. Aqui a gente só vai automatizar o que você já aprendeu.
Anatomia de uma unit file
Antes de meter a mão na massa, um glossário rápido. O systemd usa arquivos .service (chamados “unit files”) pra definir como um serviço funciona. A estrutura básica:
[Unit]
Description=Minha MicroVM
After=network.target
[Service]
Type=simple
ExecStart=/usr/local/bin/firecracker --api-sock /run/firecracker/vm.socket
Restart=on-failure
[Install]
WantedBy=multi-user.target
Três seções:
- [Unit]: Metadados e dependências. “Quem sou eu” e “de quem dependo”
- [Service]: Como rodar. O executável, variáveis de ambiente, política de restart
- [Install]: Como instalar. Em qual “target” (modo de operação) esse serviço deve rodar
Os campos mais importantes pra gente:
| Campo | O que faz |
|---|---|
After= |
Espera outros serviços iniciarem primeiro |
Type=simple |
O processo principal é o próprio ExecStart |
ExecStartPre= |
Comandos pra rodar ANTES do serviço principal |
ExecStopPost= |
Comandos pra rodar DEPOIS do serviço parar |
Restart=on-failure |
Reinicia se o processo morrer com erro |
RuntimeDirectory= |
Cria diretório em /run/ com permissões corretas |
Passo 1: O script de setup de rede
Primeiro, vamos criar um script que configura toda a rede necessária pra microVM. Isso inclui:
- Criar a interface TAP
- Configurar IP
- Habilitar IP forwarding
- Configurar NAT/masquerading
- Bloquear acesso à rede local (segurança)
Salve como /usr/local/bin/firecracker-network-setup.sh:
#!/bin/bash
# firecracker-network-setup.sh
# Configura rede para microVM Firecracker
set -e
TAP_DEV="${TAP_DEV:-tap0}"
TAP_IP="${TAP_IP:-172.16.0.1}"
TAP_CIDR="${TAP_CIDR:-24}"
ACTION="${1:-up}"
setup_network() {
echo "Configurando rede para microVM..."
# Verifica se já existe
if ip link show "$TAP_DEV" &>/dev/null; then
echo "Interface $TAP_DEV já existe, pulando criação"
return 0
fi
# Cria interface TAP
ip tuntap add dev "$TAP_DEV" mode tap
ip addr add "${TAP_IP}/${TAP_CIDR}" dev "$TAP_DEV"
ip link set "$TAP_DEV" up
echo "Interface $TAP_DEV criada com IP $TAP_IP/$TAP_CIDR"
# Habilita IP forwarding
sysctl -w net.ipv4.ip_forward=1 > /dev/null
# Configura firewall (detecta firewalld ou iptables)
if command -v firewall-cmd &>/dev/null && systemctl is-active firewalld &>/dev/null; then
setup_firewalld
else
setup_iptables
fi
echo "Rede configurada com sucesso"
}
setup_firewalld() {
echo "Configurando firewalld..."
firewall-cmd --zone=trusted --add-interface="$TAP_DEV" 2>/dev/null || true
firewall-cmd --add-masquerade 2>/dev/null || true
# Bloqueia acesso a redes privadas (seguranca)
firewall-cmd --zone=trusted --add-rich-rule="rule family=ipv4 source address=172.16.0.0/24 destination address=10.0.0.0/8 drop" 2>/dev/null || true
firewall-cmd --zone=trusted --add-rich-rule="rule family=ipv4 source address=172.16.0.0/24 destination address=192.168.0.0/16 drop" 2>/dev/null || true
}
setup_iptables() {
echo "Configurando iptables..."
# Detecta interface de saida
DEFAULT_IFACE=$(ip route | grep default | awk '{print $5}' | head -1)
# NAT/Masquerading
iptables -t nat -C POSTROUTING -o "$DEFAULT_IFACE" -j MASQUERADE 2>/dev/null || \
iptables -t nat -A POSTROUTING -o "$DEFAULT_IFACE" -j MASQUERADE
# Forward
iptables -C FORWARD -i "$TAP_DEV" -o "$DEFAULT_IFACE" -j ACCEPT 2>/dev/null || \
iptables -A FORWARD -i "$TAP_DEV" -o "$DEFAULT_IFACE" -j ACCEPT
iptables -C FORWARD -i "$DEFAULT_IFACE" -o "$TAP_DEV" -m state --state RELATED,ESTABLISHED -j ACCEPT 2>/dev/null || \
iptables -A FORWARD -i "$DEFAULT_IFACE" -o "$TAP_DEV" -m state --state RELATED,ESTABLISHED -j ACCEPT
# Bloqueia acesso a redes privadas (seguranca)
iptables -C FORWARD -i "$TAP_DEV" -d 10.0.0.0/8 -j DROP 2>/dev/null || \
iptables -I FORWARD -i "$TAP_DEV" -d 10.0.0.0/8 -j DROP
iptables -C FORWARD -i "$TAP_DEV" -d 192.168.0.0/16 -j DROP 2>/dev/null || \
iptables -I FORWARD -i "$TAP_DEV" -d 192.168.0.0/16 -j DROP
}
teardown_network() {
echo "Removendo configuracao de rede..."
if ip link show "$TAP_DEV" &>/dev/null; then
ip link set "$TAP_DEV" down
ip tuntap del dev "$TAP_DEV" mode tap
echo "Interface $TAP_DEV removida"
fi
# Nao removemos regras de firewall automaticamente
# pois podem estar sendo usadas por outras VMs
echo "Limpeza concluida"
}
case "$ACTION" in
up|start)
setup_network
;;
down|stop)
teardown_network
;;
*)
echo "Uso: $0 {up|down}"
exit 1
;;
esac
Torne executável:
sudo chmod +x /usr/local/bin/firecracker-network-setup.sh
O script detecta automaticamente se você usa firewalld (Fedora, RHEL) ou iptables (Ubuntu, Debian) e configura apropriadamente.
Passo 2: O script de inicialização da microVM
Agora precisamos de um script que inicia o Firecracker e configura a microVM via API. Esse script vai ser chamado pelo systemd.
Salve como /usr/local/bin/firecracker-vm-start.sh:
#!/bin/bash
# firecracker-vm-start.sh
# Inicia uma microVM Firecracker
set -e
# Configuracoes (podem ser sobrescritas por variaveis de ambiente)
VM_NAME="${VM_NAME:-default}"
SOCKET_PATH="${SOCKET_PATH:-/run/firecracker/${VM_NAME}.socket}"
KERNEL_PATH="${KERNEL_PATH:-/var/lib/firecracker/vmlinux.bin}"
ROOTFS_PATH="${ROOTFS_PATH:-/var/lib/firecracker/rootfs-${VM_NAME}.ext4}"
VCPU_COUNT="${VCPU_COUNT:-1}"
MEM_SIZE_MIB="${MEM_SIZE_MIB:-256}"
TAP_DEV="${TAP_DEV:-tap0}"
GUEST_MAC="${GUEST_MAC:-AA:FC:00:00:00:01}"
FIRECRACKER_BIN="${FIRECRACKER_BIN:-/usr/local/bin/firecracker}"
# Garante que o diretorio do socket existe
mkdir -p "$(dirname "$SOCKET_PATH")"
# Remove socket antigo se existir
rm -f "$SOCKET_PATH"
echo "Iniciando Firecracker para VM: $VM_NAME"
echo " Socket: $SOCKET_PATH"
echo " Kernel: $KERNEL_PATH"
echo " Rootfs: $ROOTFS_PATH"
# Inicia Firecracker em background e salva PID
$FIRECRACKER_BIN --api-sock "$SOCKET_PATH" &
FC_PID=$!
# Aguarda socket ficar disponivel
for i in $(seq 1 50); do
if [ -S "$SOCKET_PATH" ]; then
break
fi
sleep 0.1
done
if [ ! -S "$SOCKET_PATH" ]; then
echo "ERRO: Timeout esperando socket do Firecracker"
exit 1
fi
sleep 0.2
echo "Configurando VM via API..."
# Configura kernel
curl --unix-socket "$SOCKET_PATH" -s -X PUT \
"http://localhost/boot-source" \
-H "Content-Type: application/json" \
-d "{
\"kernel_image_path\": \"$KERNEL_PATH\",
\"boot_args\": \"console=ttyS0 reboot=k panic=1 pci=off quiet\"
}"
# Configura rootfs
curl --unix-socket "$SOCKET_PATH" -s -X PUT \
"http://localhost/drives/rootfs" \
-H "Content-Type: application/json" \
-d "{
\"drive_id\": \"rootfs\",
\"path_on_host\": \"$ROOTFS_PATH\",
\"is_root_device\": true,
\"is_read_only\": false
}"
# Configura recursos
curl --unix-socket "$SOCKET_PATH" -s -X PUT \
"http://localhost/machine-config" \
-H "Content-Type: application/json" \
-d "{
\"vcpu_count\": $VCPU_COUNT,
\"mem_size_mib\": $MEM_SIZE_MIB
}"
# Configura rede
curl --unix-socket "$SOCKET_PATH" -s -X PUT \
"http://localhost/network-interfaces/eth0" \
-H "Content-Type: application/json" \
-d "{
\"iface_id\": \"eth0\",
\"guest_mac\": \"$GUEST_MAC\",
\"host_dev_name\": \"$TAP_DEV\"
}"
echo "Iniciando microVM..."
# Inicia a VM
curl --unix-socket "$SOCKET_PATH" -s -X PUT \
"http://localhost/actions" \
-H "Content-Type: application/json" \
-d '{"action_type": "InstanceStart"}'
echo "MicroVM iniciada com sucesso (PID: $FC_PID)"
# Aguarda o processo Firecracker (isso mantem o servico "rodando")
wait $FC_PID
Torne executável:
sudo chmod +x /usr/local/bin/firecracker-vm-start.sh
Passo 3: A unit file do systemd
Agora o coração da coisa: a unit file que junta tudo.
Salve como /etc/systemd/system/nano-lambda.service:
[Unit]
Description=Nano-Lambda MicroVM (Firecracker)
Documentation=https://github.com/firecracker-microvm/firecracker
After=network.target
Wants=network.target
[Service]
Type=simple
# Variaveis de ambiente para os scripts
Environment=VM_NAME=nano-lambda
Environment=SOCKET_PATH=/run/firecracker/nano-lambda.socket
Environment=KERNEL_PATH=/var/lib/firecracker/vmlinux.bin
Environment=ROOTFS_PATH=/var/lib/firecracker/rootfs-network.ext4
Environment=VCPU_COUNT=1
Environment=MEM_SIZE_MIB=256
Environment=TAP_DEV=tap0
Environment=TAP_IP=172.16.0.1
Environment=GUEST_MAC=AA:FC:00:00:00:01
# Cria diretorio em /run para o socket
RuntimeDirectory=firecracker
RuntimeDirectoryMode=0755
# Antes de iniciar: configura rede
ExecStartPre=/usr/local/bin/firecracker-network-setup.sh up
# Comando principal
ExecStart=/usr/local/bin/firecracker-vm-start.sh
# Depois de parar: limpa rede
ExecStopPost=/usr/local/bin/firecracker-network-setup.sh down
# Politica de restart
Restart=on-failure
RestartSec=5
StartLimitBurst=3
StartLimitIntervalSec=60
# Timeout
TimeoutStartSec=30
TimeoutStopSec=10
# Logs
StandardOutput=journal
StandardError=journal
SyslogIdentifier=nano-lambda
[Install]
WantedBy=multi-user.target
Vamos entender os campos importantes:
Ciclo de vida:
ExecStartPre=, Roda ANTES do serviço principal. Aqui a gente configura a rede.ExecStart=, O serviço principal. O Firecracker rodando.ExecStopPost=, Roda DEPOIS do serviço parar. Limpeza da rede.
Diretórios:
RuntimeDirectory=firecracker, Cria/run/firecracker/automaticamente com permissões certas. Esse diretório é limpo no reboot (é um tmpfs), então o systemd recria toda vez.
Restart:
Restart=on-failure, Reinicia se o processo morrer com código de erro (não se for parado manualmente)RestartSec=5, Espera 5 segundos antes de reiniciarStartLimitBurst=3eStartLimitIntervalSec=60, No máximo 3 restarts em 60 segundos. Se falhar mais que isso, desiste (evita loop infinito de crash).
Logs:
StandardOutput=journal, Manda stdout pro journaldSyslogIdentifier=nano-lambda, Nome que aparece nos logs
Passo 4: Preparando os arquivos
Antes de testar, precisamos colocar os arquivos nos lugares certos.
# Cria diretorio para arquivos do Firecracker
sudo mkdir -p /var/lib/firecracker
# Copia o binario do Firecracker
sudo cp ./firecracker /usr/local/bin/firecracker
# Copia o kernel
sudo cp ./vmlinux.bin /var/lib/firecracker/vmlinux.bin
# Copia o rootfs com rede (do artigo 03 - https://fogonacaixadagua.com.br/2025/12/redes-no-firecracker-configurando-tap-nat-e-internet-para-seu-nano-lambda/)
sudo cp ./rootfs-network.ext4 /var/lib/firecracker/rootfs-network.ext4
Importante: O rootfs precisa ter a rede configurada internamente:
- IP estático:
172.16.0.2/24(ou outro IP da subnet)- Gateway:
172.16.0.1(o IP do host na TAP)- DNS: configurado em
/etc/resolv.confSem isso, a VM não terá conectividade. Se você não fez essa configuração, volte ao artigo 03 e siga os passos de configuração do rootfs.
Passo 5: Testando
Recarregue o systemd e inicie o serviço:
# Recarrega as unit files
sudo systemctl daemon-reload
# Inicia o servico
sudo systemctl start nano-lambda
# Verifica status
sudo systemctl status nano-lambda
Se tudo der certo, você verá algo assim:
? nano-lambda.service - Nano-Lambda MicroVM (Firecracker)
Loaded: loaded (/etc/systemd/system/nano-lambda.service; disabled; preset: disabled)
Active: active (running) since Mon 2024-12-09 10:30:00 UTC; 5s ago
Docs: https://github.com/firecracker-microvm/firecracker
Process: 1234 ExecStartPre=/usr/local/bin/firecracker-network-setup.sh up (code=exited, status=0/SUCCESS)
Main PID: 1235 (firecracker-vm-)
Tasks: 5 (limit: 4915)
Memory: 105.0M
CPU: 1.234s
CGroup: /system.slice/nano-lambda.service
??1235 /bin/bash /usr/local/bin/firecracker-vm-start.sh
??1242 /usr/local/bin/firecracker --api-sock /run/firecracker/nano-lambda.socket
Pra ver os logs em tempo real:
sudo journalctl -u nano-lambda -f
Pra habilitar no boot:
sudo systemctl enable nano-lambda
Passo 6: Verificando a rede
Pra confirmar que a rede está funcionando:
# Verifica se a interface TAP existe
ip addr show tap0
# Verifica se o NAT está configurado
sudo iptables -t nat -L -n | grep MASQUERADE
# ou
sudo firewall-cmd --query-masquerade
Se você tiver outro terminal aberto, pode verificar que a VM consegue acessar a internet usando o console serial via journalctl.
A saída do console serial da VM (console=ttyS0) vai pro stdout do Firecracker, que o systemd redireciona pro journald. Então você pode ver a saída do boot e interagir (de forma limitada) pelos logs:
# Ver a saida do console em tempo real
sudo journalctl -u nano-lambda -f
Pra testar a conectividade de dentro da VM, o rootfs precisa ter um script de inicialização que faça isso automaticamente, ou você pode usar SSH se tiver configurado no rootfs.
Uma alternativa é rodar o Firecracker manualmente (fora do systemd) pra ter acesso interativo ao console:
# Para o servico
sudo systemctl stop nano-lambda
# Roda manualmente com console interativo
sudo /usr/local/bin/firecracker --api-sock /tmp/fc-test.socket &
# ... configure via API ou use o nano-lambda.py do artigo 02 ...
De dentro da VM (se tiver acesso), teste a conectividade:
# Testa acesso a internet
ping -c 3 8.8.8.8
# Testa resolucao DNS
ping -c 3 google.com
Logging e observabilidade
Com o systemd, os logs vão todos pro journald. Isso significa que você pode:
# Ver todos os logs do servico
sudo journalctl -u nano-lambda
# Logs em tempo real
sudo journalctl -u nano-lambda -f
# Logs desde o ultimo boot
sudo journalctl -u nano-lambda -b
# Logs das ultimas 2 horas
sudo journalctl -u nano-lambda --since "2 hours ago"
# Logs com prioridade de erro ou acima
sudo journalctl -u nano-lambda -p err
Isso é muito melhor do que caçar arquivos de log espalhados pelo sistema.
Restart automático e health checks
A configuração que fizemos já reinicia automaticamente em caso de falha. Mas você pode ajustar o comportamento:
# Reinicia sempre (inclusive se parar normalmente)
Restart=always
# Reinicia só em falha (codigo de saida != 0)
Restart=on-failure
# Nunca reinicia
Restart=no
O RestartSec=5 evita que o systemd fique tentando reiniciar freneticamente. Se a VM morrer, espera 5 segundos antes de tentar de novo.
Os limites StartLimitBurst=3 e StartLimitIntervalSec=60 previnem loops infinitos: se a VM crashar 3 vezes em menos de 1 minuto, o systemd desiste e marca o serviço como “failed”. Isso evita consumir CPU tentando subir algo que claramente está quebrado.
Hardening: segurança via systemd
Até aqui, o Firecracker roda como root. Funciona, mas não é ideal. O systemd oferece várias diretivas pra isolar o processo e reduzir a superfície de ataque.
Adicione essas linhas na seção [Service] da unit file:
[Service]
# ... configuracoes anteriores ...
# Isolamento de filesystem
ProtectSystem=strict
ProtectHome=yes
PrivateTmp=yes
ReadWritePaths=/var/lib/firecracker /run/firecracker
# Restricoes de processo
NoNewPrivileges=yes
PrivateDevices=yes
DeviceAllow=/dev/kvm rw
DeviceAllow=/dev/net/tun rw
# Capabilities minimas
CapabilityBoundingSet=CAP_NET_ADMIN CAP_NET_RAW
AmbientCapabilities=CAP_NET_ADMIN CAP_NET_RAW
# Limites de recursos
MemoryMax=512M
TasksMax=10
O que cada um faz:
Filesystem:
ProtectSystem=strict, Filesystem do host é read-only (exceto /dev, /proc, /sys)ProtectHome=yes, Sem acesso ao /homePrivateTmp=yes, /tmp isolado (cada serviço vê um /tmp diferente)ReadWritePaths=, Exceções: onde o Firecracker precisa escrever
Processo:
NoNewPrivileges=yes, Previne escalação de privilégios via setuidPrivateDevices=yes, Sem acesso a /dev (exceto o que liberarmos)DeviceAllow=, Whitelist: só /dev/kvm (virtualização) e /dev/net/tun (rede)
Capabilities:
CapabilityBoundingSet=, Dropa todas as capabilities exceto as listadasCAP_NET_ADMIN, Necessário pra criar interface TAPCAP_NET_RAW, Necessário pra alguns tipos de operação de rede
Recursos:
MemoryMax=512M, Limite de memória pro processo (além da RAM da VM)TasksMax=10, Limite de threads/processos filhos
Com essas ~10 linhas, você reduz drasticamente o que um possível atacante poderia fazer mesmo se conseguisse escapar da microVM.
Nota sobre User=: O ideal seria rodar o Firecracker como usuário não-privilegiado usando
User=firecrackerna unit file. O problema: os scripts de rede (criar TAP, configurar NAT) precisam de root. Uma solução seria separar os comandos de rede em scripts comsudoou usarExecStartPre=+/script(o+força execução como root). Para este artigo, mantemos a simplicidade. Se você for pra produção de verdade, vale investigar essa separação.
Templates: múltiplas VMs com uma unit file
E se você precisar rodar 5 microVMs diferentes? Criar 5 unit files quase iguais seria tedioso.
O systemd tem um recurso chamado “templates” (ou “instanced units”). Você cria uma unit file com @ no nome, e ela pode ser instanciada várias vezes com parâmetros diferentes.
Salve como /etc/systemd/system/[email protected]:
[Unit]
Description=Firecracker MicroVM (%i)
Documentation=https://github.com/firecracker-microvm/firecracker
After=network.target
[Service]
Type=simple
# %i é substituido pelo nome da instancia
Environment=VM_NAME=%i
Environment=SOCKET_PATH=/run/firecracker/%i.socket
Environment=KERNEL_PATH=/var/lib/firecracker/vmlinux.bin
Environment=ROOTFS_PATH=/var/lib/firecracker/rootfs-%i.ext4
# Cada VM precisa de TAP e MAC diferentes
# Usamos um arquivo de configuracao por VM
# O hifen (-) significa: nao falha se o arquivo nao existir
EnvironmentFile=-/etc/firecracker/%i.conf
RuntimeDirectory=firecracker
RuntimeDirectoryMode=0755
ExecStartPre=/usr/local/bin/firecracker-network-setup.sh up
ExecStart=/usr/local/bin/firecracker-vm-start.sh
ExecStopPost=/usr/local/bin/firecracker-network-setup.sh down
Restart=on-failure
RestartSec=5
StandardOutput=journal
StandardError=journal
SyslogIdentifier=firecracker-%i
[Install]
WantedBy=multi-user.target
O %i é substituído pelo nome da instância. O hífen em EnvironmentFile=- significa que o serviço não falha se o arquivo de configuração não existir, usa os defaults definidos nas linhas Environment=.
Agora crie arquivos de configuração:
# /etc/firecracker/web.conf
TAP_DEV=tap0
TAP_IP=172.16.0.1
GUEST_MAC=AA:FC:00:00:00:01
VCPU_COUNT=2
MEM_SIZE_MIB=512
# /etc/firecracker/worker.conf
TAP_DEV=tap1
TAP_IP=172.16.1.1
GUEST_MAC=AA:FC:00:00:00:02
VCPU_COUNT=1
MEM_SIZE_MIB=256
E use assim:
# Inicia a VM "web"
sudo systemctl start firecracker@web
# Inicia a VM "worker"
sudo systemctl start firecracker@worker
# Status de todas
sudo systemctl status 'firecracker@*'
# Logs da VM web
sudo journalctl -u firecracker@web -f
Cada instância roda independente, com sua própria rede, seus próprios logs, seu próprio ciclo de vida.
Exemplo prático: daemonizando o validador de URLs
Vamos juntar tudo e transformar o validador de URLs do artigo 03 em serviço.
Primeiro, garanta que você tem o rootfs com rede e a função configurada:
# Estrutura esperada
/var/lib/firecracker/
??? vmlinux.bin # Kernel
??? rootfs-network.ext4 # Rootfs com Python, requests, rede configurada
??? functions/
??? handler.py # Validador de URLs (opcional, se montar dinamicamente)
A unit file já está pronta (nano-lambda.service). Só precisamos garantir que o rootfs tem:
- Rede configurada (IP 172.16.0.2, gateway 172.16.0.1, DNS)
- Python e requests instalados
- O script
/run-function.shconfigurado
Se você seguiu o artigo 03, já tem tudo isso.
Agora teste:
# Inicia
sudo systemctl start nano-lambda
# Verifica que está rodando
sudo systemctl status nano-lambda
# Vê os logs
sudo journalctl -u nano-lambda -f
# Para
sudo systemctl stop nano-lambda
# Verifica que a rede foi limpa
ip link show tap0 # Deve dar erro "does not exist"
Troubleshooting
Serviço não inicia:
# Veja os logs detalhados
sudo journalctl -u nano-lambda -b --no-pager
# Verifique a sintaxe da unit file
sudo systemd-analyze verify /etc/systemd/system/nano-lambda.service
Rede não funciona:
# Verifique se a TAP existe
ip addr show tap0
# Verifique IP forwarding
sysctl net.ipv4.ip_forward
# Verifique masquerading
sudo iptables -t nat -L -n | grep MASQUERADE
Firecracker não encontra o socket:
# Verifique se o diretório existe
ls -la /run/firecracker/
# Verifique permissões
stat /run/firecracker/
VM crashando em loop:
# Veja o status detalhado
systemctl status nano-lambda
# Se atingiu o limite de restarts, resete
sudo systemctl reset-failed nano-lambda
sudo systemctl start nano-lambda
Indo além: menção ao firectl
Se você quiser ir pra produção de verdade, existe o firectl, uma ferramenta oficial que abstrai muito do que fizemos manualmente.
Com firectl, você faz:
firectl \
--kernel=/var/lib/firecracker/vmlinux.bin \
--root-drive=/var/lib/firecracker/rootfs.ext4 \
--tap-device=tap0/AA:FC:00:00:00:01
E ele cuida de criar o socket, configurar via API, etc.
Mas agora você entende o que o firectl faz por baixo. Quando algo quebrar, e vai quebrar, você sabe onde olhar.
Conclusão
Pronto. Sua microVM agora é um serviço de verdade:
- Inicia no boot
- Reinicia se morrer
- Tem rede configurada automaticamente
- Logs centralizados no journald
- Isolamento de segurança via systemd
A diferença entre “funciona no meu terminal” e “funciona em produção” é exatamente isso: automação, resiliência, observabilidade.
No próximo artigo… bom, a série pode crescer. Orquestração com múltiplas VMs? Integração com containerd? Métricas com Prometheus? Me conta o que te interessa.
Até lá!
Arquivos deste artigo:
firecracker-network-setup.sh, Script de setup/teardown de redefirecracker-vm-start.sh, Script de inicialização da VMnano-lambda.service, Unit file básica[email protected], Template para múltiplas VMs
Este artigo faz parte da série “Firecracker: MicroVMs na Prática”. Todo o código está disponível em GitHub.





Deixe um comentário