
Пользовательское ядро Linux на основе JIT, которое запускает контейнеры нативно на macOS с Apple Silicon без виртуальной машины. Замена Docker Engine API с возможностью прямой подстановки, обеспечивающая изоляцию контейнеров, оверлейные образы и публикацию портов.
Запуск контейнеров Linux на macOS без виртуальной машины.
dd запускает контейнеры Linux нативно на macOS с Apple Silicon без виртуальной машины. Нет
ядра Linux и нет гипервизора под капотом: JIT транслирует код контейнера и обрабатывает его
системные вызовы Linux в пользовательском пространстве (линия gVisor / PRoot). JIT является
ядром Linux для гостя — пространства имён, cgroups, слои оверлейных образов и сеть поддерживаются
как состояние пользовательского пространства. Он говорит на Docker Engine API, так что обычный
CLI docker управляет им.
Вычисления контейнера выполняются как нативные инструкции Apple Silicon; только его системные вызовы интерпретируются. Нет VM для загрузки, нет демона-в-VM, нет затрат на виртуализацию.
Сайт и документация: https://ricccrd.github.io/dd/
make jit # build.rs компилирует и подписывает JIT
DD_IMAGES=/path/to/images cargo run -p dd-daemon # запуск демона
export DOCKER_HOST=unix://$PWD/dd.sock
docker run -p 8080:80 -m 256m alpine sh -c 'echo hi from $(hostname)'
DOCKER_HOST на его сокет, и ваши существующие команды docker run / ps / images / build будут работать без изменений.jit86), который декодирует x86, синтезирует флаги и снижает SSE/x87 на NEON (бинарники glibc работают); и гости macOS arm64 (ddcli mac) — ни в одном из них нет VM..wh. whiteout, объединённые getdents), VFS с изоляцией путей без TOCTOU, пространства имён PID / UTS / USER, частная loopback netns с публикацией портов -p и ограничения памяти + процессов через cgroups (OOM при достижении лимита).dd устанавливают фоновый демон для каждого пользователя и — всё работает из , никогда не требуется .Любой другой способ запуска контейнеров Linux на Mac — Docker Desktop, Colima, Rancher, OrbStack — загружает Linux VM под гипервизором и запускает демон внутри неё. Эту VM вы оплачиваете весь день. dd избавляется от неё: контейнер — обычный процесс macOS, чьи системные вызовы обслуживаются ядром Linux в пользовательском пространстве.
Выигрыш структурный: вычисления гостя выполняются как нативные инструкции Apple Silicon (нет слоя аппаратной виртуализации на горячем пути), а пресловутое узкое место общего доступа к файлам Docker Desktop — мост virtiofs/FUSE между macOS и VM — просто не существует, потому что VFS dd является файловой системой хоста за изоляцией путей.
Честный компромисс: ядро в пользовательском пространстве настолько полно, насколько реализованы системные вызовы, и сегодня по умолчанию гость работает в одном процессе — это быстро и правильно для кода, которому вы доверяете (ваше окружение разработки, CI, ваши собственные инструменты). Для недоверенного кода теперь существует опциональный разделённый sentry (
DDJIT_UNTRUSTED): гость работает в песочнице Seatbelt с запретами по умолчанию, не имея полномочий на файловую систему/сеть хоста, а доверенный процесс sentry владеет реальными ресурсами и обслуживает системные вызовы через кольцо разделяемой памяти — форма gVisor. Это рано (основные системные вызовы для файлов — read/write/open/close/lseek — уже работают; сокеты/exec/fork внедряются), так что для полностью враждебного кода VM всё ещё предоставляет меньшую поверхность атаки.
Один и тот же статический бинарник Linux, запущенный двумя способами на Apple M5 Pro (macOS 26.3): внутри Linux VM (как VM-основанные Docker запускают контейнеры) и через JIT dd на хосте без VM. Медиана из 7 замеров (make bench). Меньшее время лучше; «dd vs VM» > 1× означает, что dd быстрее. Замеры dd дополнительно платят небольшой налог на межпроцессное взаимодействие, которого нет у реального приложения — так что эти цифры консервативны.
Контейнеры x86-64 — dd vs эмуляция VM (qemu-user; запуск x86 на Apple Silicon означает трансляцию в любом случае). JIT dd побеждает qemu на 9 из 10 нагрузок, особенно в вычислениях с плавающей точкой:
Контейнеры aarch64 — dd vs нативная VM (VM запускает arm64 на полной нативной скорости — самый сложный барьер):
dd выполняет вычисления arm64 на нативной скорости — опережает int sieve + mandelbrot, на паритете SHA-256, matmul, memcpy, n-body и base64. Оставшиеся отставания — тяжёлые на непрямые переходы / системные вызовы — qsort (~1.3×), text-scan (~1.35×) и SQLite (~1.5×) — были значительно сокращены последними проходами (§B-off + stolen x16/x17 улучшили SQLite с ~1.9× до ~1.5×). Закрытие остатка (диспетчеризация VDBE) — активный фронт; см. docs/design/arm-sqlite-parity.md. (Каждая
нагрузка настроена на выполнение ≥0.45s, так что небольшой налог на мост между запусками здесь незначителен.)
Это вычислительные микро-бенчмарки — они даже не учитывают структурных преимуществ dd (нет загрузки VM, нет занимаемой RAM, прямой ввод-вывод к файловой системе хоста). Все цифры измерены, медиана из 7. Воспроизвести: make bench.
Цель — обогнать VM на каждом бенчмарке. dd уже побеждает во всех нагрузках x86-64 выше и сравнивается или обгоняет нативный arm64; там, где он всё ещё отстаёт — тяжёлый на системные вызовы/выделение памяти arm64 SQLite и выжимание большего из транслятора x86 — это и есть фронт оптимизации (оптимизатор трасс второго уровня и работа над производительностью jit86). Паритет или лучше везде — планка.
dd запускает контейнер Linux, являясь его ядром в пользовательском пространстве. JIT транслирует машинный код гостя и перехватывает каждую инструкцию системного вызова; обработчик перехвата — service() в dd-jit/src/runtime/os/linux/ — является ABI системных вызовов Linux, реализованный поверх хоста macOS.
ld.so) и построение начального стека.# 1. Запустить демон, указать docker на него
make jit
DD_IMAGES=/path/to/images cargo run -p dd-daemon
export DOCKER_HOST=unix://$PWD/dd.sock
# 2. Это просто 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. Или через установленное десктопное приложение (для пользователя, без root)
dd install # LaunchAgent + docker context
dd app # открыть GUI
docker --context dd run alpine echo hi
dd предназначен для macOS на Apple Silicon (arm64, macOS 12+). JIT требует инструментов командной строки Xcode (clang + codesign).
Загрузите последний .dmg со страницы релизов,
откройте его и перетащите dd в папку Программы. Затем в терминале:
dd install # ~/.dd дерево + per-user LaunchAgent + `docker context create dd`
dd app # открыть GUI
dd doctor # проверить сокет / агент / контекст / карантин приложения
Gatekeeper: DMG не подписан (ad-hoc). При первом запуске нажмите правой кнопкой мыши на приложение → Открыть, или выполните
xattr -dr com.apple.quarantine /Applications/dd-app.app(dd doctorобнаружит это и покажет исправление).
xcode-select --install # clang + codesign
# установить Rust (stable) и Nix (для оболочки разработки GTK4)
git clone https://github.com/ricccrd/dd && cd dd
make app # сборка + компоновка и ad-hoc-подпись target/dd-app.app
make dmg # -> target/dist/dd-<ver>-<arch>.dmg
make install # скопировать в /Applications и запустить `dd install`
make app/dmg выполняют упаковку внутри оболочки разработки Nix (nix/flake.nix), которая
предоставляет GTK4 + dylibbundler / create-dmg. Пакет перемещает граф dylib GTK4 в
Contents/Frameworks, размещает данные времени выполнения GTK4 и подписывает ad-hoc от внутреннего к внешнему.
Рабочее пространство Cargo.
dd-jit/ — среда выполнения JIT (C, в src/runtime/) плюс его привязки к Rust.
build.rs компилирует и подписывает один JIT-бинарник на гостевую архитектуру (aarch64, x86_64);
src/lib.rs предоставляет Guest + типизированный контракт запуска SpawnConfig. Гость aarch64 полностью
декомпозирован (движок jit/ + персона os/linux/ + фронтенд frontend/aarch64/); гость x86-64 (jit86)
использует общий слой os/linux/.dd-daemon/ — демон Docker Engine API. Определяет архитектуру гостя из его ELF,
выбирает соответствующий JIT и запускает его через .Демон слушает на ~/.dd/run/docker.sock; и GUI, и docker --context dd используют его. Состояние
сохраняется в ~/.dd/state.json.
make test # матрица движков × сценариев, группированный отчёт
make test ENGINE=x86_64 # один движок
make test FILTER=container # одна группа / сценарии, совпадающие по имени
cargo run -p dd-tests -- --list # список групп + сценариев
make test-ci # путь cargo-test (CI)
Сценарии объявлены в dd-tests/src/cases/. Сценарий — это гостевая программа + утверждения; гости aarch64
компилируются на лету (gcc -static-pie) и сравниваются с нативным оракулом, гости x86-64 берутся из
предварительно собранных фикстур. Каждый сценарий выполняется на каждом движке, для которого у него есть гость.
clang + codesign (Xcode CLT).-p), частная loopback netns, ограничения cgroups памяти и процессов, пространства имён UTS/PID/USER.docs/ для подробного описания.Richard Hutta — [email protected]
MIT.
docker context$HOMEsudo| dd — ядро в пользовательском пространстве (JIT) | VM-based Docker (Desktop / Colima / …) |
|---|
| Базовая модель | JIT обслуживает системные вызовы Linux в пользовательском пространстве (линия gVisor) | Полноценное ядро Linux внутри гипервизора VM |
| Потребление RAM в простое | Нет — освобождается при выходе из контейнера | Гигабайты зарезервированы для VM, всегда включены |
| Запуск | Запуск процесса — не нужно загружать VM | Сначала загрузить Linux VM + демон внутри |
| Bind-mount / файловый ввод-вывод | Прямая работа с файловой системой хоста через изоляцию путей | Мост virtiofs/gRPC-FUSE через границу VM |
| Публикация портов | Напрямую к сокетам хоста | Через слой NAT/форвардинга VM |
| Потребление батареи / в фоне | Ничего не выполняется, когда нет контейнера | VM работает вхолостую и расходует батарею |
| Размер для распространения и обновления | Нет ядра Linux — не нужно отслеживать CVE | Включает, обновляет и отслеживает целое ядро Linux |
| Наблюдаемость | Обычный процесс macOS — sample, debug, Activity Monitor | Непрозрачная VM; нагрузка невидима для инструментов хоста |
| Нагрузка | VM (qemu) | dd (без VM) | dd vs VM |
|---|
| float n-body | 5.39s | 0.23s | быстрее в 24× |
| mandelbrot | 7.81s | 0.83s | быстрее в 9.4× |
| matmul | 8.21s | 1.37s | быстрее в 6.0× |
| SQLite (600k строк) | 2.99s | 1.01s | быстрее в 3.0× |
| qsort | 3.91s | 1.68s | быстрее в 2.3× |
| memcpy | 2.40s | 1.10s | быстрее в 2.2× |
| text-scan (wc/grep) | 1.42s | 1.11s | быстрее в 1.3× |
| int sieve | 1.31s | 1.04s | быстрее в 1.25× |
| SHA-256 | 2.72s | 2.44s | быстрее в 1.1× |
| base64 | 4.28s | 5.39s | 0.79× (в 1.26× медленнее) |
| Нагрузка | VM (нативная) | dd (без VM) | dd vs VM |
|---|
| int sieve | 0.75s | 0.48s | быстрее в 1.58× |
| mandelbrot | 0.79s | 0.77s | быстрее в 1.03× |
| matmul | 0.66s | 0.66s | ~паритет |
| memcpy | 0.55s | 0.56s | ~паритет |
| base64 | 0.68s | 0.68s | ~паритет |
| float n-body | 0.17s | 0.17s | ~паритет |
| SHA-256 | 0.80s | 0.82s | ~паритет |
| qsort | 0.83s | 1.10s | медленнее в 1.33× |
| text-scan (wc/grep) | 0.51s | 0.68s | медленнее в 1.35× |
| SQLite (600k строк) | 0.36s | 0.62s | медленнее в 1.71× |
SpawnConfigdd-tests/ — декларативный тестовый каркас; тестовые случаи выполняются на каждом движке с группированным отчётом.dd-client/ — небольшой типизированный клиент Docker Engine API через Unix-сокет демона (единственный источник истины для формата провода, используется GUI и CLI).dd-gui/ (бинарник dd-app) — десктопный интерфейс GTK4. Собирается только на macOS через оболочку разработки Nix.dd-cli/ (бинарник dd) — интерфейс установки/управления, всё без прав root.