Pular para o conteúdo
← Voltar para o Skalablog

Artigo publicado

gVisor vs Firecracker vs Docker: qual isola?

Engenharia de Software

gVisor vs Firecracker vs Docker se decide por uma pergunta simples: quem responde à syscall que o código do agente faz. No Docker, o kernel do host responde; no gVisor, o Sentry, um kernel em espaço de usuário, responde; no Firecracker, um kernel convidado separado responde. Cada resposta muda quanto software fica entre o código e o host.

gVisor vs Firecracker vs Docker: quem responde à syscall?

gVisor vs Firecracker vs Docker se decide por quem responde à chamada de sistema do código do agente. Um programa não abre arquivo nem usa a rede sozinho: ele pede ao kernel por meio de uma syscall. No Docker, quem responde é o kernel do host; no gVisor, o Sentry em espaço de usuário; no Firecracker, um kernel convidado separado.

Namespaces e cgroups não respondem à chamada. A documentação do Docker descreve namespaces como o que dá a cada contêiner sua própria visão de processos e rede, e cgroups como o que limita recursos. São recursos do kernel, então todo contêiner usa o mesmo kernel do host.

Essa é a razão de uma falha no runc, o inicializador de contêineres usado por Docker, containerd e Kubernetes, importar para o host. O runc é o programa que efetivamente cria o contêiner; se ele erra, a fronteira cai.

Nenhuma das três caixas é inescapável. Pode haver falha em hipervisor e no gVisor também. A comparação útil é quanta superfície de software fica entre o código e o host.

Falhas do runc: CVE-2019-5736, CVE-2024-21626 e CVE-2025-31133

As três falhas do runc mostram que a fronteira do contêiner é corrigível, mas não permanente. Em fevereiro de 2019, o CVE-2019-5736 permitiu que um contêiner malicioso sobrescrevesse o binário do runc no host, dando root ao atacante. A causa foi um descritor de arquivo mal tratado, e o NVD atribui nota 8,6.

O CVE-2024-21626, batizado de Leaky Vessels e publicado em 31 de janeiro de 2024, veio de um vazamento de descritor de arquivo interno. Um processo iniciado por runc exec podia ter seu diretório de trabalho dentro do sistema de arquivos do host. O aviso cobre quatro ataques e afirma que todos os quatro podem dar controle total do host.

O CVE-2025-31133 é uma falha de temporização na forma como o runc esconde caminhos sensíveis do contêiner. A nota é 7,3, e versões de correção resolvem o problema.

Dois limites importam para o CVE-2019-5736: o atacante precisava de root dentro do contêiner, e um user namespace correto, sem mapear o root do host, bloqueava o ataque. A política AppArmor padrão e a política SELinux do Fedora não bloqueavam.

O que cada CVE exige do atacante

  • CVE-2019-5736 (2019): root dentro do contêiner, muitas vezes via imagem maliciosa ou docker exec.
  • CVE-2024-21626 (2024): um processo iniciado por runc exec ou uma imagem maliciosa, com o diretório de trabalho caindo no host.
  • CVE-2025-31133 (2025): uma condição de corrida no mascaramento de caminhos do host, sem exigir root no host.

A lição prática é atualizar o runc. Cada uma dessas falhas tem versão corrigida, e a exposição real depende de qual versão você roda hoje.

Como o gVisor funciona: Sentry, gofer e o recorte de syscalls

O gVisor responde às syscalls em espaço de usuário, com um kernel de aplicação escrito em Go. Esse componente é o Sentry, que captura as chamadas de sistema e os pedidos de acesso à memória do código e os atende com implementação própria de syscalls, memória, sistemas de arquivos, rede e processos.

A analogia útil: no Docker o visitante entra na mesma casa; no gVisor, um recepcionista atende cada pedido e o visitante não entra. O Sentry não abre nem cria arquivos no host. Todo o I/O de arquivo passa pelos gofers, processos auxiliares que tocam o sistema de arquivos do host.

Os números de exposição vêm de uma postagem de 2019 do gVisor, medida contra o Linux 5.3.11, e podem ter mudado. Naquela contagem, o Linux tinha cerca de 350 syscalls, o Sentry implementava 237 delas para contêineres e podia usar apenas 68 tipos distintos de chamada ao host: 53 sem rede e 15 a mais com rede.

O Sentry é software e pode ter falhas. Uma falha no Sentry pode levar o código mais longe do que o projeto pretende. O gVisor reduz a exposição do host, não a elimina.

Plataforma do gVisor: Systrap, seccomp e ptrace

A plataforma do gVisor escolhe como as chamadas são capturadas, e o padrão mudou em meados de 2023. O Systrap é a opção padrão atual; o ptrace é tratado pela documentação do gVisor como obsoleto.

Na postagem de 2023 do gVisor, o Systrap rodou cerca de 10 vezes mais rápido que o ptrace em um laço de chamadas getpid. Essa comparação é do gVisor com ele mesmo, não com o Docker. No mesmo teste, o Systrap foi cerca de duas vezes mais rápido no Redis e de duas a três vezes mais rápido em uma compilação. A execução de FFmpeg quase não mudou.

Onde o custo aparece segundo o gVisor

  • Custo estrutural: a camada extra do Sentry e o caminho via gofer para arquivos.
  • Custo de implementação: o sistema de arquivos e a pilha de rede do próprio gVisor, menos maduros que os do Linux.
  • Quem paga mais: aplicações limitadas por syscalls, como bancos de dados e serviços de rede estáticos.
  • Quem não paga: código limitado por CPU e acesso bruto à memória, sem custo extra depois que os mapeamentos de memória estão prontos.

O overhead de memória do gVisor é pequeno e quase fixo. O preço real depende do trabalho do seu agente.

MicroVM com Firecracker: dispositivos, threads e números declarados

O Firecracker é um monitor de máquina virtual criado pela AWS para o Lambda e o Fargate, e responde à syscall com um kernel convidado separado. Ele usa o KVM, recurso do Linux que permite à CPU rodar um convidado com kernel próprio. O host vê KVM e um modelo de dispositivos pequeno, não a chamada.

O modelo de dispositivos é enxuto por projeto. O Firecracker expõe apenas dispositivos virtio de rede e bloco, um dispositivo vsock, um console serial e um controlador de teclado parcial que só sinaliza reinício. Virtio é um padrão para dispositivos virtuais, e vsock é um canal entre convidado e host.

Cada processo do Firecracker tem três tipos de thread: uma thread de API para comandos, uma thread de VMM que emula dispositivos em um laço de eventos e uma thread de VCPU por núcleo do convidado. Um jailer configura cgroups e namespaces e depois retira privilégios do processo, e filtros seccomp são carregados por thread antes de qualquer código do convidado rodar.

As metas publicadas vêm de hosts bare metal da AWS com um convidado de um VCPU e 128 MiB de memória. Nesses hosts, o init do convidado começa 125 ms ou menos depois da chamada de API que inicia a instância, e a thread de VMM soma 5 MiB ou menos de overhead. Os 125 ms terminam quando o init começa, não quando o código do agente roda.

Comparação de custo e isolamento entre as três opções

A comparação direta entre Docker, gVisor e Firecracker depende do perfil de trabalho, porque cada caixa cobra em um lugar diferente. O Docker não adiciona camada sobre as syscalls, o gVisor adiciona Sentry e gofer, e a microVM adiciona boot de VM e memória por VM.

Nenhuma fonte citada aqui compara bugs de escape entre as três arquiteturas, e a documentação usada não coloca as três lado a lado na mesma máquina. A tabela abaixo reúne só o que cada fonte primária sustenta.

Qual sandbox escolher para o seu agente de IA

Para código que você escreveu e revisou, um contêiner Docker comum é suficiente, desde que o runc esteja atualizado. A chamada vai direto ao kernel do host, então não há camada extra sobre as syscalls.

Se o agente lê páginas da web ou arquivos que você não controla, uma injeção de prompt pode direcionar o código dele. Trate esse código como hostil e evite o kernel compartilhado.

Se o agente constrói contêineres, ele precisa de Docker in Docker, o que exige privilégios que enfraquecem o isolamento de contêiner. Nesse caso, a microVM é a escolha mais defensável.

Passos para decidir com evidência

  1. Meça o perfil do seu agente: quantas syscalls e quanto I/O de arquivo por execução.

2. Se o trabalho é limitado por CPU, teste o gVisor primeiro e compare com o Docker.

3. Se o agente roda banco de dados ou servidor de rede, teste o gVisor nesse trabalho antes, porque as syscalls dominam o custo.

4. Se o código vem de terceiros ou o agente constrói contêineres, escolha a microVM e aceite o boot.

5. Atualize o runc em qualquer cenário, já que cada falha citada tem versão corrigida.

O Firecracker cobra 5 MiB ou menos de memória do monitor mais a memória que você dá ao convidado, além do boot. Em troca, o código ganha um kernel próprio atrás de virtualização de hardware.

Docker Desktop, Docker Sandboxes e a doação do gVisor ao CNCF

O Docker Desktop no Mac roda contêineres dentro de uma máquina virtual Linux, o que muda onde uma fuga do runc aterrissa. A documentação do Docker lista três opções de backend: Docker VMM, o framework de virtualização da Apple e o HyperKit legado, que o Docker marca como obsoleto e exclusivo para Intel.

Dave Scott argumentou, em 3 de outubro, que o Docker Desktop usa microVMs desde 2016, definindo microVM como uma carga sobre um kernel Linux enxuto rodando em um VMM mínimo como o Firecracker sobre KVM ou Xen. A documentação do Docker diz "VM Linux", não microVM, então o rótulo é dele. A linhagem começa no HyperKit e no LinuxKit e evolui para o Docker VMM.

O produto de agente da própria Docker também usa microVM. O blog de 16 de abril de 2026 descreve o Docker Sandboxes rodando cada sessão de agente em uma microVM dedicada, com kernel próprio e um daemon Docker privado. A Docker não publica números de inicialização nem de memória nessa postagem.

Em 2 de outubro, o Google anunciou a doação do gVisor à CNCF, que aceitou o projeto em 28 de setembro. O gVisor entra no primeiro nível de maturidade da fundação, chamado sandbox, com plano de incubação, e a governança passa a mantenedores com votação por organização. O anúncio não traz detalhe técnico nem número de desempenho, então ele muda quem governa o gVisor, não o desempenho.

Perguntas frequentes

  • O gVisor é mais rápido que o Docker? Não. O gVisor adiciona a camada do Sentry e o caminho via gofer para arquivos, então trabalho limitado por syscalls paga mais que no Docker. As comparações de 10 vezes e de duas a três vezes publicadas pelo gVisor são do Systrap contra o ptrace, ou seja, o gVisor contra ele mesmo, não contra o Docker.
  • O Firecracker é um substituto direto do Docker? Não no sentido de trocar sem mudar nada. A microVM dá ao código um kernel próprio atrás de KVM, com boot e memória por VM. Para um agente que constrói contêineres ou roda código de terceiros, essa troca costuma compensar; para scripts que você revisou, o contêiner comum resolve com menos peças.
  • Qual sandbox devo usar se o agente roda um banco de dados? Teste o gVisor nessa carga antes de decidir. A documentação do gVisor aponta aplicações limitadas por syscalls, como bancos de dados e serviços de rede, entre as que mais sentem o custo estrutural e de implementação. Sem medição no seu caso, a escolha fica no escuro.
  • A doação do gVisor à CNCF muda a segurança dele? Não pelo anúncio. O texto de outubro informa apenas a mudança de governança, com o projeto entrando no nível sandbox e planos de incubação. Não há número de desempenho nem promessa técnica publicada junto.
  • Um contêiner Docker bem configurado já é isolamento suficiente? Depende da origem do código. Namespaces e cgroups limitam visão e recursos, mas a syscall continua chegando ao kernel do host. Para código próprio e revisado, um Docker com runc atualizado é defensável; para código hostil, o kernel compartilhado é o risco central.

Source video