EnglishРусский Map

pullrun

Toolbox toolboxrustgolangcontainersmicrovmocip2psandboxingwatchlistRust (runtime)Golang (CLICRI shimcompose)Apache-2.0 ↳ show in map Markdown
title
pullrun
type
toolbox
summary
Запускает OCI-образ как runc-контейнер, microVM Firecracker или VM Apple Silicon из контентно-адресуемого DAG-хранилища
tags
rust, golang, containers, microvm, oci, p2p, sandboxing, watchlist
language
Rust (runtime), Golang (CLI, CRI shim, compose)
license
Apache-2.0
created
2026-07-29
updated
2026-07-29
lang
ru
translation_of
pullrun
source_updated
2026-07-29
translated
2026-09-01
translator
lllm/antigravity/gemini-3.7-flash-medium

Pullrun берёт обычный OCI-образ и запускает его тремя способами: как контейнер runc, как microVM Firecracker или как виртуальную машину Apple Virtualization на Apple Silicon. Один и тот же образ, одна и та же команда, одно локальное хранилище - меняется только флаг --backend. Отдельного этапа сборки VM-образа и специфичного для виртуальных машин формата нет, поскольку OCI-манифест напрямую используется как rootfs для VM.

pullrun run alpine:3.18 --cmd "echo" --cmd "hello"                # container (Linux)
pullrun run alpine:3.18 --backend vm --cmd "echo" --cmd "hello"   # Firecracker microVM
pullrun run alpine:3.18 --cmd "echo" --cmd "hello" --attach -t    # Apple VM (macOS default)

В этом вся суть, и проект опирается на тот же аргумент, что и microvm-2026: контейнер - это механизм контроля ресурсов, а не граница безопасности, поэтому выбор между изоляцией на общем ядре и отдельным ядром на VM должен быть флагом времени выполнения, а не отдельным набором инструментов. Если matryoshka-isolation описывает бутерброд "контейнеры внутри VM", на котором останавливается большинство платформ, то pullrun делает их равноправными соседями на базе одного хранилища.

DAG-хранилище

Архитектура хранилища - то, ради чего стоит читать этот проект. Вместо распаковки слоёв через overlayfs pullrun хранит каждый OCI-слой как есть в контентно-адресуемом направленном ациклическом графе с ключом по дайджесту sha256: и делает mmap() блобов при чтении. Реализация на Rust использует rkyv для десериализации без копирования, memmap2 для отображения в память и кэш DashMap<Digest, Arc<Mmap>>, благодаря чему первый читатель платит за mmap() и page fault'ы, а все последующие обходятся одной атомарной операцией загрузки.

Из контентной адресации следуют две вещи. Каждый узел, скачавший alpine:3.18, хранит побайтово идентичные файлы, именно это делает уровень peer-to-peer синхронизации дешёвым - блоки проверяются по хешу при получении, поэтому пиру не обязательно доверять, достаточно иметь к нему доступ. А удаление превращается в задачу на графах, а не в файловой системе: pullrun rmi каскадно удаляет недостижимое поддерево, отдельные sidecar-файлы со счётчиками ссылок на узле сохраняют слои, разделяемые с другим образом, пока не исчезнет последняя ссылка, а проход recompute_all_refcounts при запуске демона пересчитывает счётчики после сбоя. pullrun gc вычищает всё, что больше недостижимо из тегированного образа или работающей нагрузки, по умолчанию в режиме dry-run с 90%-м защитным порогом, который нужно принудительно обходить через --force.

Отказ от overlayfs также преподносится как аргумент в пользу безопасности: в README упоминаются CVE-2023-0386 и CVE-2023-32629 как побеги из контейнера через overlayfs, с которыми хранилище, не создающее overlay, просто не может столкнуться. Далее приводится баг в page cache ядра, CVE-2026-31431 ("Copy Fail"), как пример проблемы общего ядра, которую не может решить ни один драйвер хранилища, но решают изолированные ядра виртуальных машин, - что и служит обоснованием самого существования бэкендов на базе VM. Оба утверждения взяты из собственного README проекта; для второй CVE никаких других источников не приведено.

Бэкенды и цифры

Backend Isolation Platform Claimed boot
runc namespaces Linux, macOS, Windows (WSL2) ~400 ms
Firecracker отдельное ядро на VM (KVM) Linux x86_64, WSL2 x86_64 ~500 ms холодный старт, ~200 ms пул разогретых
Apple Virtualization отдельное ядро на VM (Hypervisor.framework) macOS Apple Silicon ~160 ms

Наряду с этим README заявляет 968 мс на первый pull alpine:3.18 против ~2 с у Docker, 24.6 MiB RSS у простаивающего демона против ~90 MiB и ~20 MB стрипнутых бинарников против ~75 MB. Это собственные бенчмарки проекта, прогнанные через hyperfine на M3 против Docker Desktop 4.27 со скриптом, опубликованным в hack/bench.sh, - воспроизводимые в теории, но никем другим пока не проверенные. Цифра для тёплого пула наиболее интересна, так как здесь используется тот же трюк со snapshot-restore в Firecracker, позволяющий обойти нижний порог времени холодной загрузки, описанный в microvm.

Поведение после stop различается в зависимости от бэкенда сильнее, чем время загрузки: VM в Apple Virt сохраняет rootfs через VirtioFS, а VM в Firecracker сохраняет свой ext4-образ, поэтому обе перезапускаются как машины после гибернации, тогда как rootfs нагрузки в runc эфемерна и сохраняются только монтирования --volume.

Всё остальное в бинарнике

Функциональная поверхность для столь молодого проекта весьма широка. Здесь есть встроенный сборщик Dockerfile, который вызывает runc для выполнения инструкций RUN и кэширует слои по хешу инструкций, так что сборкам не нужен демон Docker. Отдельный бинарник pullrun-compose парсит стандартный docker-compose.yml через compose-spec/compose-go и умеет запускать каждый сервис из файла как microVM с помощью --backend vm. Сами ядра тоже представляют собой OCI-артефакты: pullrun kernel install скачивает vmlinux из реестра в DAG-хранилище, а --kernel-image указывает нагрузке на нужное ядро по ссылке.

Движок политик проверяет нагрузки перед запуском: верификация подписей Cosign, оценка SBOM с порогами CVSS и чёрными списками лицензий, профили seccomp, rootfs только для чтения, no_new_privileges - всё это декларируется как required_signature: true, max_cvss_score: 7.0, deny_licenses: ["GPL-3.0"]. Уровень P2P обнаруживает пиры через mDNS, распространяет состояние через gossip-протокол и использует фильтры Блума, чтобы не пересылать блоки, которые у пира уже есть, благодаря чему кластер скачивает данные из реестра один раз, а остальное дельта-синхронизирует на скорости локальной сети. Есть CRI-shim для Kubernetes (бета), предоставляющий RuntimeClasses pullrun-container и pullrun-vm, а также MCP-сервер с 15 операциями среды выполнения и четырьмя типами ресурсов, что ставит его на ту же позицию инструмента для агентов, что и Sandbox Agent SDK от Rivet, только API у pullrun документирован, а не отреверсен.

На что обратить внимание

Репозиторий был создан 2026-06-11 и к концу июля 2026 года набрал 114 звёзд, один форк и ноль открытых issue. Каждая цифра, ссылка на CVE и утверждение в духе "единственный runtime, умеющий X" на этой странице взяты из README, написанного самими авторами проекта; независимых подтверждений здесь нет. Внесение правок требует подписания CLA, что намекает на стремление контролировать лицензирование в проекте под Apache-2.0. Control plane явно находится в разработке (etcd, DNS и admission control помечены как "planned"), CRI-shim обозначен как бета, а разделение между Rust и Golang на одиннадцать crate'ов и четыре компонента на Golang - это слишком большая поверхность для, судя по всему, очень маленькой команды.

По этой причине странице присвоен тег watchlist - критерии повторной проверки описаны в watchlist. Идея с хранилищем достаточно хороша, чтобы её позаимствовать, независимо от того, выживет ли эта реализация.

Apache-2.0, ~114★ на 2026-07-29. Технический отчёт заархивирован на doi.org/10.5281/zenodo.20679669.