|
| 1 | +# Dory Compatibility Matrix |
| 2 | + |
| 3 | +This is the honest, maintained statement of what Dory does. It reflects the **current |
| 4 | +implementation**, which talks to a Docker Engine API backend through a pluggable runtime layer |
| 5 | +designed to also target Apple's `container` engine when present. |
| 6 | + |
| 7 | +Legend: ✅ works · 🟡 works with Dory-specific behavior · 🛠️ implemented, activation gated · |
| 8 | +⛔ unsupported / not yet · 🔒 blocked by an external gate. |
| 9 | + |
| 10 | +## Docker Engine API (via Dory's socket `~/.dory/dory.sock`) |
| 11 | + |
| 12 | +On the Docker backend, Dory's socket is a **full transparent proxy**: every request is forwarded |
| 13 | +verbatim and the response streamed back unchanged — uniformly correct for normal, streaming, and |
| 14 | +hijacked (upgrade) endpoints, with all request headers preserved (registry auth, etc.). The |
| 15 | +per-endpoint translation below is what the **Apple `container`** and mock backends present, since |
| 16 | +they have no Docker socket to forward to. |
| 17 | + |
| 18 | +| Capability | Status | Notes | |
| 19 | +|---|---|---| |
| 20 | +| `docker version` / `info` / `_ping` | ✅ | Docker backend: real engine response (transparent passthrough). Apple/mock: Dory-branded. Verified with the real `docker` CLI | |
| 21 | +| `docker ps` / list containers | ✅ | Real containers, correct names/status/ports/timestamps | |
| 22 | +| Container start / stop / restart / remove | ✅ | `POST /containers/{id}/...`, `DELETE /containers/{id}` | |
| 23 | +| `docker images` / list | ✅ | Translated from the runtime snapshot (Apple/mock) | |
| 24 | +| Container create (with body) | ✅ | image, cmd, env, ports, labels, network, restart policy; image refs starting with `-` rejected at the boundary | |
| 25 | +| Exec (create + start + inspect) | ✅ | Used by the Compose health prober | |
| 26 | +| Image pull | ✅ | `POST /images/create` | |
| 27 | +| Network create / remove | ✅ | `POST /networks/create`, `DELETE /networks/{id}` | |
| 28 | +| Volume remove | ✅ | `DELETE /volumes/{id}` | |
| 29 | +| Logs (`docker logs`, `-f`) | ✅ | Docker backend: live follow proxied verbatim. Apple/mock: de-framed via streaming transport | |
| 30 | +| Stats (mem live, CPU%) | ✅ | Docker backend: `docker stats` streamed through the proxy. Apple/mock: two-sample CPU sampler | |
| 31 | +| Events (`docker events`) | ✅ | Docker backend: proxied (live engine events). Apple/mock: synthesized via `EventSynthesizer` | |
| 32 | +| `docker exec` (`-i`, `-it` TTY) + `attach` | ✅ | Bidirectional hijack proxy with correct half-close (stdin EOF) + exit codes; TTY (`/dev/pts/0`) verified | |
| 33 | +| `docker cp` (archive get/put) | ✅ | Both directions verified (incl. chunked request bodies) | |
| 34 | +| `docker build` (classic + **BuildKit**) | ✅ | Both verified end-to-end via Dory's socket (BuildKit gRPC session proxied) | |
| 35 | +| Any other Docker endpoint (Docker backend) | ✅ | Transparent proxy — distribution, swarm, plugins, etc. all pass through | |
| 36 | +| Full create-body flag coverage | 🟡 | Apple/mock translation maps common flags; the long tail is iterative (Docker backend forwards everything) | |
| 37 | + |
| 38 | +## Compose |
| 39 | + |
| 40 | +| Capability | Status | Notes | |
| 41 | +|---|---|---| |
| 42 | +| Parse `compose.yaml` | ✅ | Block + flow YAML, quotes, comments (subset; no anchors/block scalars) | |
| 43 | +| Variable interpolation + `.env` | ✅ | `$VAR`, `${VAR:-default}`, `${VAR-default}`, `$$` | |
| 44 | +| `depends_on` (short + long form) | ✅ | `service_started` / `service_healthy` / `service_completed_successfully` | |
| 45 | +| Dependency ordering | ✅ | Topological start order, cycle + dangling-dep detection | |
| 46 | +| Healthchecks | ✅ | Exec-based probing + Docker-faithful state machine | |
| 47 | +| `up` / `down` | ✅ | Native engine; AND the real `docker compose up/down` CLI drives Dory's socket (verified) | |
| 48 | +| GUI Compose view | ✅ | Projects grouped by service with per-project + per-service start/stop | |
| 49 | +| Named/anonymous volumes | 🟡 | Anonymous-volume tracker built; full volume wiring iterative | |
| 50 | +| Profiles / multiple files / overrides | ⛔ | Parsed-aware; merge logic not yet | |
| 51 | +| `network_mode: service:` / shared pid/ipc | ⛔ | Co-schedule into one machine — by design, against Apple `container` | |
| 52 | + |
| 53 | +## Engine backends |
| 54 | + |
| 55 | +| Backend | Standalone? | Memory model | Notes | |
| 56 | +|---|---|---|---| |
| 57 | +| **Shared VM** (`DORY_RUNTIME=shared`) | ✅ yes | **One shared VM for all containers** (OrbStack-style) | Dory provisions one persistent Linux micro-VM on Apple's `container` engine running `dockerd` (DinD), publishes its socket to the host, and drives it with the verified Docker runtime. Verified: standalone (engine 29.5.3, no OrbStack), workloads share one VM. Measured: 2 containers = **1 VM @ ~122 MB** vs **~574 MB** as 3 per-container VMs. Persistent `/var/lib/docker` (overlayfs preserved across restarts); configurable CPUs/memory; idempotent reuse. | |
| 58 | +| **Docker** (default) | ❌ proxies host engine | host Docker/OrbStack | Transparent proxy to `/var/run/docker.sock`. Companion GUI, not a replacement. | |
| 59 | +| **Apple `container`** | ✅ yes | **One VM per container** | Native per-container micro-VMs; heavier for multi-container stacks. | |
| 60 | + |
| 61 | +## OrbStack parity surface |
| 62 | + |
| 63 | +All verified end-to-end on the shared-VM backend (default). System-wide binds (:53/:80/:443) and the |
| 64 | +CA trust install remain consent-gated — the same one-time admin grant OrbStack needs. |
| 65 | + |
| 66 | +| Capability | Status | Notes | |
| 67 | +|---|---|---| |
| 68 | +| Native GUI (menu bar + main window) | ✅ | All screens, both themes; one-click toggles for k8s/machines/shared-VM | |
| 69 | +| Standalone engine + shared-VM memory | ✅ | Default backend; Dory runs its own `dockerd` in one VM — no OrbStack/Docker. ~4.7× leaner than per-container | |
| 70 | +| `localhost` access to published ports | ✅ | `HostPortForwarder`; verified `localhost:port → 200`, dynamic add/teardown | |
| 71 | +| Automatic `*.dory.local` domains | ✅ | `DoryDNS` resolver + `DoryReverseProxy`; verified `http://name.dory.local → 200`. System-wide via consent script | |
| 72 | +| Automatic local HTTPS | ✅ | `DoryTLSProxy` terminates TLS with a `LocalCA` identity; verified `https://name.dory.local → 200` | |
| 73 | +| **Bind-mount file sharing** | ✅ | Home dir shared into the VM (virtiofs); verified `docker run -v ~/proj:/app` reads/writes host files live | |
| 74 | +| One-click Kubernetes | ✅ | `KubernetesProvisioner` runs k3s in the shared VM; verified host `kubectl` + pod deploy; GUI "Enable" button | |
| 75 | +| Linux machines (Ubuntu/Debian/Fedora/Alpine) | ✅ | `MachineProvider` via `container machine`; verified real machine create/list/start/stop/delete; GUI picker | |
| 76 | +| x86/amd64 emulation | ✅ (qemu) | Auto-installs qemu binfmt; verified `--platform linux/amd64 → x86_64`. Rosetta fast-path is a documented gap | |
| 77 | +| Volume file browser | ✅ | `VolumeBrowser`; verified list + read files inside volumes; GUI sheet | |
| 78 | +| Terminal / SSH into containers + machines | ✅ | `TerminalLauncher` opens Terminal.app against Dory's socket/engine | |
| 79 | +| Docker Desktop / OrbStack migration | ✅ | `MigrationAssistant` imports images + containers into Dory's shared VM | |
| 80 | +| `*.k8s.dory.local` service domains | ✅ HTTP + HTTPS | `KubeServiceProxy` runs `kubectl proxy`; the reverse/TLS proxy rewrites `<svc>.<ns>.k8s.dory.local` → the API service proxy. Verified `http`+`https → 200`. TLS cert carries per-namespace wildcard SANs (`*.default.k8s.dory.local`, `*.kube-system.k8s.dory.local`); other namespaces would need their wildcard added | |
| 81 | +| `dory` CLI (OrbStack's `orb`) | ✅ | `scripts/dory` wraps the engine, machines, and kubectl | |
| 82 | + |
| 83 | +### Remaining gaps — all blocked on ONE thing: `apple/containerization` framework integration |
| 84 | + |
| 85 | +Every feature achievable through Apple's `container` CLI + the dind architecture is done. The four |
| 86 | +items below were each investigated and shown to need low-level VM control the CLI does not expose — |
| 87 | +device passthrough, memory ballooning, Rosetta device, custom mounts. They all become feasible once |
| 88 | +Dory links the `apple/containerization` Swift package and drives the VM in-process (the same |
| 89 | +integration the [packaging](#packaging) section roadmaps). |
| 90 | + |
| 91 | +**Foundation built + PROVEN END-TO-END.** `Packages/ContainerizationEngine/` is an additive Swift |
| 92 | +package (separate from the shipping app) that links `apple/containerization` and drives the Linux VM |
| 93 | +directly via Virtualization.framework. It does not just compile — a signed boot harness |
| 94 | +(`dory-vmboot`, adhoc-signed with `com.apple.security.virtualization`) **boots a real Linux VM |
| 95 | +in-process and runs a container**, verified by exit code: |
| 96 | + |
| 97 | +- `exit 42` — VM booted + container ran (kernel + initfs + image store all working in-process). |
| 98 | +- `exit 77` — an **amd64 image ran via Rosetta** (`uname -m == x86_64`) → **Rosetta-fast x86 PROVEN**. |
| 99 | +- `exit 99` — same run also read a **host file through a `Mount.share`** (`/shared/marker.txt`) → |
| 100 | + **bidirectional file sharing PROVEN**. |
| 101 | + |
| 102 | +**Shipped to users via `dory vm`.** The engine is packaged as a bundled, entitlement-signed helper |
| 103 | +(`Helpers/dory-vm`, built + signed by `scripts/bundle-engine.sh`) that the `dory` CLI and the app |
| 104 | +invoke — exactly how Dory already invokes `container`/`docker`/`kubectl`, so the app gains the |
| 105 | +features without linking the framework's large dependency tree. |
| 106 | + |
| 107 | +| Capability | Status | Delivery | |
| 108 | +|---|---|---| |
| 109 | +| Rosetta-speed x86 | ✅ **delivered** | `dory vm --arch amd64 --rosetta -- <cmd>` → `uname -m == x86_64`. Verified through the CLI | |
| 110 | +| Reverse / bidirectional file mount | ✅ **delivered** | `dory vm --mount host:guest -- <cmd>` reads/writes host files in the container. Verified | |
| 111 | +| USB / audio passthrough | ✅ **delivered** | `dory vm --devices`: a `VZInstanceExtension` injects an XHCI USB controller + `VZVirtioSoundDevice`. Verified `USB controllers attached: 1` | |
| 112 | +| Dynamic memory balloon → macOS | ✅ **delivered** | `dory vm --devices` attaches a balloon and reclaims RAM at runtime via the public `vzVirtualMachine` — verified `1024MiB → 512MiB reclaimed to macOS` | |
| 113 | + |
| 114 | +**All four are delivered** through the bundled, entitlement-signed `dory-vm` helper, surfaced by the |
| 115 | +`dory` CLI (`dory vm`). The default shared-VM engine is untouched. (A GUI entry point for the |
| 116 | +in-process engine is not yet wired up.) |
| 117 | + |
| 118 | +## Packaging — does the user need anything besides Dory.app? |
| 119 | + |
| 120 | +The goal is a single download. Status: |
| 121 | + |
| 122 | +| Component | Bundled? | How | |
| 123 | +|---|---|---| |
| 124 | +| Engine image (`docker:dind`) | ✅ implemented | `scripts/bundle-engine.sh` saves it into `Contents/Resources/dory-engine-image.tar`; `SharedVMProvisioner.ensureImage` loads it offline on first launch (no Docker Hub). Falls back to a registry pull if absent. | |
| 125 | +| Engine toolchain (`container` + kernel + plugins) | 🛠️ wired | `containerBinary()` prefers `Contents/Helpers/container`; the release script copies the ~315 MB toolchain in. Relocating the toolchain's launchd services needs hardening — the **production answer is to link the `apple/containerization` Swift package and spawn the VM in-process** (network-verified reachable; roadmapped). | |
| 126 | +| `docker` CLI | not needed | Dory's GUI manages everything; the Docker-compatible socket is there for users who want a CLI. | |
| 127 | +| **macOS 26+** | requirement, not a download | Apple's virtualization/containerization stack requires it — the unavoidable floor (same as Apple's `container`). | |
| 128 | + |
| 129 | +So: **a self-contained Dory.app is achievable** (image bundling done; engine bundling wired, framework path roadmapped), requiring only macOS 26+ — no Homebrew, no Docker Hub, no Docker Desktop. |
| 130 | + |
| 131 | +## Architectural / environment notes |
| 132 | + |
| 133 | +- **Shared VM vs one-VM-per-container.** Dory offers BOTH: the Apple `container` backend is |
| 134 | + one-VM-per-container, while the **Shared VM backend** runs all containers in one VM like |
| 135 | + OrbStack — measured ~4.7× less memory for 2 containers (122 MB vs 574 MB), with the gap widening |
| 136 | + per container. This closes the headline memory gap and makes Dory a standalone engine. |
| 137 | +- **File-sharing performance** under the Apple `container` runtime + a real bind-mount dev loop is |
| 138 | + not yet benchmarked here. |
| 139 | +- **Distribution.** Signing works locally; **notarization requires an Apple Developer account** |
| 140 | + (external gate). The Homebrew Cask and an auto-updater are scaffolding still to add. |
| 141 | +- The app runs **unsandboxed** (like Docker Desktop/OrbStack) to reach the engine socket and |
| 142 | + host its own socket. |
0 commit comments