Mocker: Docker-совместимый CLI на фреймворке Apple

Инструмент управления контейнерами, совместимый с Docker, построенный на фреймворке Apple Containerization

Mocker — это CLI-инструмент с поддержкой Docker Compose, работающий нативно на macOS с помощью фреймворка Containerization от Apple (требуется macOS 26+). Он «говорит» на том же языке, что и Docker: те же команды, те же флаги, тот же формат вывода — поэтому все существующие скрипты и привычки работают без изменений.

Просто замените docker на mocker

# Было
docker compose up -d
docker ps
docker logs my-app
docker exec -it my-app sh

# Стало — те же команды, нативная среда выполнения Apple, без Docker Desktop
mocker compose up -d
mocker ps
mocker logs my-app
mocker exec -it my-app sh

Существующий docker-compose.yml работает без каких-либо изменений.

Что нового

Полная актуальная история релизов доступна в файле CHANGELOG — он перегенерируется автоматически при каждом выпуске.

Возможности

  • Совместимость с Docker CLIrun, ps, stop, rm, exec, logs, build, pull, push, images, tag, rmi, inspect, stats

  • Управление сетямиnetwork create/ls/rm/inspect/connect/disconnect

  • Управление томамиvolume create/ls/rm/inspect

  • Docker Compose v2compose up/down/ps/logs/restart с учётом порядка зависимостей

  • GUI в строке меню — нативное приложение на SwiftUI (скоро)

  • Хранение состояния в JSON — все метаданные сохраняются в ~/.mocker/

  • Конкурентность Swift 6 — полная потокобезопасность на основе акторов (actors)

Примечание

Замечание о совместимости: Mocker разбирает все флаги Docker CLI для полной взаимозаменяемости, однако часть флагов не поддерживается средой выполнения Containerization от Apple и вызовет предупреждение или ошибку. Подробнее о том, какие команды полностью функциональны, а какие не поддерживаются, см. в COMMANDS.md.

Требования

Компонент Версия

macOS

26.0+ (Sequoia)

Swift

6.0+

Xcode

16.0+

Примечание

Фреймворк Apple Containerization требует macOS 26 на Apple Silicon. Компьютеры Mac на Intel не поддерживаются.

Установка

Homebrew (рекомендуется)

brew tap us/tap
brew install mocker

Сборка из исходного кода

git clone https://github.com/us/mocker.git
cd mocker
swift build -c release
cp .build/release/mocker /usr/local/bin/mocker

Быстрый старт

# Загрузить образ
mocker pull nginx:1.25

# Запустить контейнер
mocker run -d --name webserver -p 8080:80 nginx:1.25

# Список запущенных контейнеров
mocker ps

# Просмотр логов
mocker logs webserver

# Остановить и удалить
mocker stop webserver
mocker rm webserver

Использование

Жизненный цикл контейнера

# Запуск с переменными окружения и томами
mocker run -d \
  --name myapp \
  -p 8080:80 \
  -e APP_ENV=production \
  --env-file .env \
  -v /host/data:/app/data \
  myimage:latest

# Интерактивный запуск (на переднем плане)
mocker run --name temp alpine:latest

# Принудительное удаление работающего контейнера
mocker rm -f myapp

# Выполнить команду внутри работающего контейнера
mocker exec myapp env

# Следить за логами
mocker logs -f myapp

Образы

# Загрузить конкретный тег
mocker pull postgres:15

# Список образов
mocker images

# Список только идентификаторов образов
mocker images -q

# Поставить тег на образ
mocker tag alpine:latest my-registry.io/alpine:v1

# Удалить образ
mocker rmi my-registry.io/alpine:v1

# Собрать из Dockerfile
mocker build -t myapp:latest .

# Мультиплатформенная сборка (флаг --platform повторяется для каждой архитектуры)
mocker build --platform linux/amd64 --platform linux/arm64 -t myapp:latest .

# Отправить в реестр
mocker push my-registry.io/myapp:latest

Манифест-листы (мультиархитектурные образы)

# Просмотр OCI image index
mocker manifest inspect myrepo/multi:latest

# Создать манифест-лист из существующих образов под конкретные архитектуры
mocker manifest create myrepo/multi:latest myrepo/app:amd64 myrepo/app:arm64

# Добавить дочерний образ в существующий список (заменяет запись той же платформы)
mocker manifest add myrepo/multi:latest myrepo/app:arm64

# Удалить запись по спецификации платформы или дайджесту
mocker manifest rm myrepo/multi:latest linux/amd64
mocker manifest rm myrepo/multi:latest sha256:cb96058800ca…

# Переопределить метаданные платформы для записи
mocker manifest annotate myrepo/multi:latest myrepo/app:arm64 --variant v8

# Отправить собранный список в реестр
mocker manifest push myrepo/multi:latest

Сборка под экзотические архитектуры

mocker build --platform linux/ppc64le|s390x|riscv64 работает для Dockerfile, состоящих только из слоёв (FROM / COPY / CMD), но завершается ошибкой Exec format error при наличии любой инструкции RUN. BuildKit-VM в Apple container build — это arm64 Linux VM без обработчиков QEMU binfmt_misc для архитектур, отличных от arm64/amd64. linux/amd64 работает только потому, что Apple Silicon поставляется с аппаратной трансляцией Rosetta 2. Отслеживание в апстриме: apple/container#1496.

До тех пор, пока Apple не добавит поддержку QEMU, существуют три обходных пути:

Путь Компромисс

Удалённый сборщик. Направьте mocker на Linux-хост с уже зарегистрированным QEMU binfmt: mocker build --builder <name> --platform linux/ppc64le …. Значение --builder передаётся в container build --builder, который может работать с удалённым узлом BuildKit (например, зарегистрированным через docker buildx create --driver remote ssh://host). Шаги RUN будут выполняться на эмуляторе удалённого хоста, а не в локальной arm64 VM.

Требуется доступный удалённый Linux-хост (нативный ppc64le или x86/arm с qemu-user-static) и однократная регистрация сборщика.

Запустить машину Podman параллельно с mocker. Её VM на Fedora CoreOS имеет зарегистрированный qemu-user-static, поэтому podman build --platform linux/ppc64le корректно обрабатывает шаги RUN. После этого используйте mocker manifest create для сборки образов под разные архитектуры в единый список.

Требуется постоянно работающая QEMU VM — дополнительный расход памяти и усложнение инфраструктуры.

container run --virtualization — запустить Linux VM, установить внутри qemu-user-static и Docker, собрать образ там, затем экспортировать через container image save и добавить результат через mocker manifest add.

Ручная настройка; разовое действие для каждой нужной архитектуры.

Для arm64 и amd64 (Rosetta 2) нативный путь быстрее и официально поддерживается — эмуляция экзотических архитектур остаётся обходным решением до появления соответствующей поддержки в апстриме.

Просмотр и статистика

# Просмотр контейнера (вывод JSON)
mocker inspect myapp

# Просмотр нескольких объектов или с ограничением по типу
mocker inspect container1 container2 alpine:latest
mocker inspect --type image alpine:latest

# JSON-массив в формате Docker ImageInspect; при необходимости выбор платформы
mocker image inspect --platform linux/amd64 alpine:latest

# Статистика использования ресурсов
mocker stats --no-stream

Сети

# Создать сеть
mocker network create mynet

# Список сетей
mocker network ls

# Подключить контейнер
mocker network connect mynet myapp

# Отключить
mocker network disconnect mynet myapp

# Просмотреть
mocker network inspect mynet

# Удалить
mocker network rm mynet

Тома

# Создать именованный том
mocker volume create pgdata

# Список томов
mocker volume ls

# Просмотр (показывает точку монтирования)
mocker volume inspect pgdata

# Удалить
mocker volume rm pgdata

Docker Compose

# Запустить все сервисы (в фоне)
mocker compose -f docker-compose.yml up -d

# Список контейнеров Compose
mocker compose -f docker-compose.yml ps

# Просмотр логов сервиса
mocker compose -f docker-compose.yml logs web

# Перезапустить сервис
mocker compose -f docker-compose.yml restart api

# Остановить и удалить
mocker compose -f docker-compose.yml down

Пример docker-compose.yml:

version: "3.8"

services:
  web:
    image: nginx:1.25
    ports:
      - "8080:80"
    depends_on:
      - api

  api:
    image: myapp:latest
    environment:
      - DB_HOST=db
      - DB_PORT=5432
    depends_on:
      - db

  db:
    image: postgres:15
    environment:
      POSTGRES_PASSWORD: secret
      POSTGRES_DB: myapp
    volumes:
      - pgdata:/var/lib/postgresql/data

volumes:
  pgdata:

Система

# Информация о системе
mocker system info

# Удалить остановленные контейнеры и неиспользуемые ресурсы
mocker system prune -f

Архитектура

mocker/
├── Sources/
│   ├── MockerKit/          # Общая основная библиотека
│   │   ├── Models/         # Типы данных (ContainerInfo, ImageInfo, ...)
│   │   ├── Config/         # MockerConfig (пути ~/.mocker/)
│   │   ├── Container/      # ContainerEngine + ContainerStore (actor)
│   │   ├── Image/          # ImageManager + ImageStore (actor)
│   │   ├── Network/        # NetworkManager (actor)
│   │   ├── Volume/         # VolumeManager (actor)
│   │   └── Compose/        # Парсер ComposeFile + ComposeOrchestrator
│   ├── Mocker/             # Исполняемый файл CLI
│   │   ├── Commands/       # По одному файлу на группу команд
│   │   └── Formatters/     # TableFormatter, JSON-вывод
│   └── MockerApp/          # Приложение SwiftUI в строке меню (macOS 26+)
│       ├── MenuBar/
│       ├── ViewModels/
│       └── Views/
└── Tests/
    ├── MockerKitTests/     # Юнит-тесты основной библиотеки
    └── MockerTests/        # Интеграционные тесты CLI

Ключевые архитектурные решения

Аспект Подход

Потокобезопасность

Все движки и менеджеры являются типами actor

Хранение состояния

JSON-файлы в ~/.mocker/{containers,images,networks,volumes}/

Разбор CLI

swift-argument-parser с AsyncParsableCommand

Разбор YAML

Библиотека Yams

Именование в Compose

Конвенция Docker v2: projectName-serviceName-1 (разделитель — дефис)

JSON-вывод

Всегда обёрнут в массив [{…​}], как в формате inspect Docker

Каталог данных

Mocker хранит всё состояние в ~/.mocker/:

~/.mocker/
├── containers/   # Метаданные контейнеров (один JSON-файл на контейнер)
├── images/       # Метаданные образов
├── networks/     # Метаданные сетей
└── volumes/      # Метаданные томов + каталоги с данными
    └── pgdata/
        └── _data/

Совместимость с Docker

Mocker нацелен на полную совместимость CLI с Docker. Ключевые совпадающие модели поведения:

  • Сообщения об ошибках: Error response from daemon: …​

  • inspect всегда возвращает JSON-массив, даже для одного объекта

  • Идемпотентность pull: повторная загрузка существующего образа выводит «Image is up to date»

  • Именование контейнеров Compose: project-service-1 (дефис, не подчёркивание)

  • stop и rm возвращают в ответ идентификатор, переданный пользователем

  • Короткие ID состоят из 12 символов (первые 12 символов полного 64-символьного шестнадцатеричного ID)

Сборка и тестирование

# Собрать все цели
swift build

# Запустить все тесты
swift test

# Запустить конкретный набор тестов
swift test --filter MockerKitTests

# Запустить CLI напрямую
swift run mocker --help

Производительность

Бенчмарки выполнены на Apple M-серии, macOS 26 (hyperfine --warmup 5 --runs 15):

Инструмент Запуск контейнера По сравнению с Docker

Docker Desktop

320 мс

baseline

Apple container CLI

1 030 мс

в 3,2× медленнее

Mocker

1 153 мс

в 3,6× медленнее

Модель Apple «одна VM на контейнер» обменивает скорость запуска на более строгую изоляцию — каждый контейнер получает собственную лёгкую Linux VM. Mocker добавляет лишь ~120 мс накладных расходов на управление поверх среды выполнения Apple.

Пропускная способность CPU и памяти (sysbench внутри контейнера, 30 с):

Метрика Docker Apple Container

CPU events/s

7 958

7 894

Пропускная способность памяти

13 340 MiB/s

13 119 MiB/s

Производительность вычислений идентична — граница VM практически не создаёт накладных расходов для нагрузок на CPU и память.

Как это работает

Mocker делегирует Apple CLI container операции жизненного цикла контейнеров (run, stop, exec, logs, build). Операции с образами (pull, list, tag, rmi) используют Containerization.ImageStore напрямую. Такой гибридный подход уже сегодня даёт полноценный инструмент, совместимый с Docker, на macOS 26:

Операция Бэкенд

run, stop, exec, logs

Подпроцесс /usr/local/bin/container

build

container build с потоковым выводом в реальном времени

pull, push, tag, rmi

Containerization.ImageStore (напрямую через фреймворк)

images

Хранилище образов Apple CLI (показывает все загруженные и собранные образы)

stats

RSS/CPU процесса VM через ps (сопоставление VirtualMachine.xpc)

Проброс портов -p

Постоянный подпроцесс mocker __proxy на каждый порт

Дорожная карта

  • ✓ Полная совместимость флагов Docker CLI (111 команд)

  • ✓ Поддержка Docker Compose v2

  • ✓ Управление сетями и томами

  • ❏ GUI в строке меню

  • ✓ Реальное выполнение контейнеров на macOS 26 (через Apple container CLI)

  • mocker build — делегирует в container build с потоковым выводом

  • mocker stats — реальные CPU% и память из процесса VM

  • ✓ Проброс портов (-p) — пользовательский TCP-прокси в виде подпроцесса

  • ❏ Аутентификация в реестре (mocker login)

  • mocker compose --scale

  • ❏ Живые метрики контейнеров в строке меню (CPU, память, логи)

  • ❏ Отображение размера слоёв образа

  • ❏ Прямая интеграция с фреймворком Containerization (ожидается совместимость с vminit)

Участие в разработке

Вклад в проект приветствуется! Пожалуйста, ознакомьтесь с docs/contributing.md для получения инструкций.

# Сделать форк и клонировать
git clone https://github.com/yourname/mocker.git

# Создать ветку для функциональности
git checkout -b feat/my-feature

# Внести изменения и запустить тесты
swift test

# Зафиксировать по конвенции Conventional Commits
git commit -m "feat: add my feature"

Лицензия

AGPL-3.0 — подробности в файле LICENSE.

© 2026 meganuke