
Kernel Linux em espaço de usuário baseado em JIT que executa contêineres nativamente no macOS Apple Silicon sem uma VM. Substituição drop-in da API do Docker Engine com isolamento de contêineres, imagens overlay e publicação de portas.
Execute containers Linux no macOS — sem VM.
dd executa containers Linux nativamente no macOS Apple Silicon sem máquina virtual. Não há
kernel Linux nem hipervisor subjacente: um JIT traduz o código do container e trata suas
chamadas de sistema Linux em espaço de usuário (linhagem gVisor / PRoot). O JIT é o kernel Linux
convidado — namespaces, cgroups, camadas de imagem overlay e rede são mantidos como estado de espaço
de usuário. Ele fala a API do Docker Engine, então o CLI comum docker o utiliza.
A computação do container é executada como instruções nativas Apple Silicon; apenas suas chamadas de sistema são interpretadas. Sem VM para iniciar, sem daemon dentro de uma VM, sem custo de virtualização.
Site e documentação: https://ricccrd.github.io/dd/
make jit # build.rs compila + codesign os JITs
DD_IMAGES=/caminho/para/imagens cargo run -p dd-daemon # inicia o daemon
export DOCKER_HOST=unix://$PWD/dd.sock
docker run -p 8080:80 -m 256m alpine sh -c 'echo hi from $(hostname)'
DOCKER_HOST para seu socket e
seus comandos docker run / ps / images / build existentes funcionam sem alterações.jit86) que decodifica x86, sintetiza suas flags e reduz SSE/x87 para NEON (binários glibc
funcionam); e convidados arm64 do macOS (ddcli mac) — sem VM em nenhum deles..wh. whiteout, getdents
mesclado), um VFS de confinamento de caminho livre de TOCTOU, namespaces PID / UTS / USER, uma netns
loopback privada com publicação de porta -p e limites de memória + pids via cgroup (OOM no limite).dd instalam um
daemon de fundo por usuário e um — tudo em , nunca .Qualquer outra forma de executar containers Linux em um Mac — Docker Desktop, Colima, Rancher, OrbStack — inicializa uma VM Linux sob um hipervisor e roda o daemon dentro dela. Essa VM é um imposto que você paga o dia todo. dd a elimina: um container é um processo macOS comum cujas chamadas de sistema são tratadas por um kernel Linux em espaço de usuário.
A vantagem é estrutural: a computação do convidado roda como instruções nativas Apple Silicon (sem
camada de virtualização de hardware no caminho crítico), e o notório gargalo de compartilhamento de
arquivos do Docker Desktop — a ponte virtiofs/FUSE entre macOS e a VM — simplesmente não existe, pois
o VFS do dd é o sistema de arquivos do host protegido por um confinamento de caminho.
Compensação honesta: um kernel em espaço de usuário é tão completo quanto as chamadas de sistema que implementa, e hoje por padrão o convidado roda em um processo — rápido, e a decisão certa para código em que você confia (seu ambiente de desenvolvimento, CI, suas próprias ferramentas). Para código não confiável, há agora uma divisão sentry opcional (
DDJIT_UNTRUSTED): o convidado roda em um sandbox Seatbelt com negação padrão, sem autoridade de fs/rede do host, enquanto um processo sentry confiável possui os recursos reais e atende chamadas de sistema através de um anel de memória compartilhada — a forma gVisor. É cedo (as chamadas de sistema de arquivos principais — read/write/open/close/lseek — são encaminhadas hoje; sockets/exec/fork estão chegando), então para código totalmente hostil uma VM ainda expõe uma superfície mais estreita.
O mesmo binário Linux estático, executado de duas formas em um Apple M5 Pro (macOS 26.3): dentro
da VM Linux (como o Docker baseado em VM executa containers) vs. através do JIT do dd no host sem VM.
Mediana de 7 execuções (make bench). Menor tempo é melhor; "dd vs VM" > 1× significa que dd é mais
rápido. A faixa do dd ainda paga um pequeno imposto de ponte entre processos que o aplicativo real não
paga — portanto, estes são conservadores.
Containers x86-64 — dd vs emulação de VM (qemu-user; executar x86 no Apple Silicon significa traduzir de qualquer forma). O JIT do dd supera o qemu em 9 de 10 cargas de trabalho, dramaticamente em ponto flutuante:
Containers aarch64 — dd vs uma VM nativa (a VM executa arm64 em velocidade nativa máxima — a barra mais difícil):
dd executa a computação arm64 em velocidade nativa — à frente em int sieve + mandelbrot, em paridade
em SHA-256, matmul, memcpy, n-body e base64. As lacunas restantes são trabalhos com muitos desvios
indiretos / chamadas de sistema — qsort (~1,3×), text-scan (~1,35×) e SQLite (~1,5×) — reduzidas
acentuadamente pelas passagens mais recentes (§B-off + x16/x17 roubado levou o SQLite de ~1,9× para
~1,5×). Fechar o resto (despacho VDBE) é a fronteira ativa; veja
docs/design/arm-sqlite-parity.md. (Cada carga de trabalho
tem tamanho para executar ≥0,45s, então o pequeno imposto de ponte por execução da estrutura é
desprezível aqui.)
Estes são micro-benchmarks de computação — eles nem capturam as vantagens estruturais do dd (sem VM
para iniciar, sem RAM residente, I/O direto ao sistema de arquivos do host). Todos os números medidos,
mediana de 7. Reproduza: make bench.
O objetivo é superar a VM em todos os benchmarks. dd já vence todas as cargas de trabalho x86-64 acima e iguala ou supera arm64 nativo; onde ainda está atrás — SQLite arm64 pesado em chamadas de sistema/alocação, e extrair mais do tradutor x86 — é exatamente a fronteira de otimização (otimizador de rastreamento de nível 2 e trabalho de desempenho jit86). Paridade ou melhor em todos os lugares é o padrão.
dd executa um container Linux sendo seu kernel em espaço de usuário. Um JIT traduz o código de
máquina do convidado e intercepta toda instrução de chamada de sistema; o manipulador de interrupção —
service() em dd-jit/src/runtime/os/linux/ — é a ABI de chamada de sistema Linux, implementada
contra o host macOS.
ld.so) e construir a pilha inicial.# 1. Inicie o daemon, aponte o docker para ele
make jit
DD_IMAGES=/caminho/para/imagens cargo run -p dd-daemon
export DOCKER_HOST=unix://$PWD/dd.sock
# 2. É apenas Docker
docker run -p 8080:80 -m 256m alpine sh -c 'echo hi from $(hostname)'
docker ps
docker images
docker run --rm -it ubuntu bash
# 3. Ou através do aplicativo desktop instalado (por usuário, sem root)
dd install # LaunchAgent + contexto docker
dd app # abre a GUI
docker --context dd run alpine echo hi
O dd tem como alvo macOS Apple Silicon (arm64, macOS 12+). O JIT precisa das Ferramentas de Linha
de Comando do Xcode (clang + codesign).
Pegue o .dmg mais recente na página de releases,
abra-o e arraste dd para Aplicativos. Depois, em um terminal:
dd install # árvore ~/.dd + LaunchAgent por usuário + `docker context create dd`
dd app # abre a GUI
dd doctor # verifica socket / agente / contexto / quarentena do app
Gatekeeper: o DMG não é assinado (ad-hoc). Na primeira execução, clique com o botão direito no aplicativo → Abrir, ou execute
xattr -dr com.apple.quarantine /Applications/dd-app.app(dd doctordetecta isso e exibe a correção).
xcode-select --install # clang + codesign
# instale Rust (estável) e Nix (para o shell de desenvolvimento GTK4)
git clone https://github.com/ricccrd/dd && cd dd
make app # compila + monta e assina ad-hoc target/dd-app.app
make dmg # -> target/dist/dd-<ver>-<arch>.dmg
make install # copia para /Applications e executa `dd install`
make app/dmg executam o empacotamento dentro do shell de desenvolvimento Nix
(nix/flake.nix), que fornece GTK4 + dylibbundler / create-dmg. O pacote
reloca o grafo de dylibs do GTK para Contents/Frameworks, organiza os dados de runtime do GTK e
assina ad-hoc de dentro para fora.
Um workspace Cargo.
dd-jit/ — o runtime JIT (C, em src/runtime/) mais suas ligações Rust.
build.rs compila e codesigna um binário JIT por arquitetura convidada (aarch64, x86_64);
src/lib.rs expõe Guest + o contrato de lançamento tipado SpawnConfig. O convidado aarch64 é
totalmente decomposto (mecanismo jit/ + personalidade os/linux/ + frontend frontend/aarch64/);
o convidado x86-64 (jit86) compartilha a camada os/linux/.dd-daemon/ — o daemon da API Docker Engine. Detecta a arquitetura convidada de cada imagem a
partir de seu ELF, escolhe o JIT correspondente e o lança via .O daemon escuta em ~/.dd/run/docker.sock; tanto a GUI quanto docker --context dd o utilizam. O
estado persiste em ~/.dd/state.json.
make test # matriz mecanismo × caso, relatório agrupado
make test ENGINE=x86_64 # um mecanismo
make test FILTER=container # um grupo / casos que correspondem a um nome
cargo run -p dd-tests -- --list # lista grupos + casos
make test-ci # o caminho cargo-test (CI)
Os casos são declarados em dd-tests/src/cases/. Um caso é um programa convidado + asserções;
convidados aarch64 são compilados dinamicamente (gcc -static-pie) e comparados com um oráculo nativo,
convidados x86-64 vêm de fixtures pré-construídas. Cada caso é executado em cada mecanismo para o qual
possui um convidado.
clang + codesign (Xcode CLT).-p), netns loopback privada, limites de memória+pids via cgroup, namespaces UTS/PID/USER.docs/ para as
descrições detalhadas.Richard Hutta — [email protected]
MIT.
docker context$HOMEsudo| dd — kernel em espaço de usuário (JIT) | Docker baseado em VM (Desktop / Colima / …) |
|---|
| Modelo subjacente | Um JIT trata chamadas de sistema Linux em espaço de usuário (linhagem gVisor) | Um kernel Linux completo dentro de uma VM com hipervisor |
| RAM residente quando ocioso | Nenhuma — por container, liberada ao sair | Gigabytes reservados para a VM, sempre ligados |
| Inicialização | Spawn de processo — nenhuma VM para iniciar | Iniciar uma VM Linux + o daemon dentro da VM primeiro |
| Montagem bind / I/O de arquivos | Sistema de arquivos do host direto através de um confinamento de caminho | Ponte virtiofs/gRPC-FUSE através da fronteira da VM |
| Publicação de portas | Diretamente para sockets do host | Através da camada NAT/forwarding da VM |
| Custo de bateria / fundo | Nada executando quando não há container | Uma VM ociosa e consumindo bateria |
| Pegada para distribuir e corrigir | Nenhum kernel Linux — nada para rastrear CVE | Distribui, corrige e rastreia um kernel Linux completo |
| Observabilidade | Um processo macOS normal — amostra, depura, Monitor de Atividade | Uma VM opaca; a carga de trabalho é invisível para ferramentas do host |
| Carga de trabalho | VM (qemu) | dd (sem VM) | dd vs VM |
|---|
| float n-body | 5.39s | 0.23s | 24× mais rápido |
| mandelbrot | 7.81s | 0.83s | 9.4× mais rápido |
| matmul | 8.21s | 1.37s | 6.0× mais rápido |
| SQLite (600k linhas) | 2.99s | 1.01s | 3.0× mais rápido |
| qsort | 3.91s | 1.68s | 2.3× mais rápido |
| memcpy | 2.40s | 1.10s | 2.2× mais rápido |
| text-scan (wc/grep) | 1.42s | 1.11s | 1.3× mais rápido |
| int sieve | 1.31s | 1.04s | 1.25× mais rápido |
| SHA-256 | 2.72s | 2.44s | 1.1× mais rápido |
| base64 | 4.28s | 5.39s | 0.79× (1.26× mais lento) |
| Carga de trabalho | VM (nativo) | dd (sem VM) | dd vs VM |
|---|
| int sieve | 0.75s | 0.48s | 1.58× mais rápido |
| mandelbrot | 0.79s | 0.77s | 1.03× mais rápido |
| matmul | 0.66s | 0.66s | ~paridade |
| memcpy | 0.55s | 0.56s | ~paridade |
| base64 | 0.68s | 0.68s | ~paridade |
| float n-body | 0.17s | 0.17s | ~paridade |
| SHA-256 | 0.80s | 0.82s | ~paridade |
| qsort | 0.83s | 1.10s | 1.33× mais lento |
| text-scan (wc/grep) | 0.51s | 0.68s | 1.35× mais lento |
| SQLite (600k linhas) | 0.36s | 0.62s | 1.71× mais lento |
SpawnConfigdd-tests/ — uma estrutura de testes declarativa; os casos executam em cada mecanismo com um
relatório agrupado.dd-client/ — um cliente pequeno e tipado da API Docker Engine sobre o socket Unix do daemon
(a única fonte da verdade para o formato de transmissão, compartilhado pela GUI e pelo CLI).dd-gui/ (binário dd-app) — uma interface de desktop GTK4. Construída apenas no macOS
através do shell de desenvolvimento Nix.dd-cli/ (binário dd) — a superfície de instalação/controle, tudo sem root.