{"id":30397902,"url":"https://github.com/dbtreasure/container-shim","last_synced_at":"2026-02-12T01:39:58.034Z","repository":{"id":309127621,"uuid":"1035245900","full_name":"dbtreasure/container-shim","owner":"dbtreasure","description":null,"archived":false,"fork":false,"pushed_at":"2025-08-10T01:08:25.000Z","size":6,"stargazers_count":0,"open_issues_count":0,"forks_count":0,"subscribers_count":0,"default_branch":"main","last_synced_at":"2025-10-12T23:08:37.165Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":null,"language":null,"has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dbtreasure.png","metadata":{"files":{"readme":"README.md","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null,"governance":null,"roadmap":null,"authors":null,"dei":null,"publiccode":null,"codemeta":null,"zenodo":null}},"created_at":"2025-08-10T01:07:57.000Z","updated_at":"2025-08-10T01:08:28.000Z","dependencies_parsed_at":"2025-08-10T03:08:28.417Z","dependency_job_id":"2ff84e8f-1b7f-4ea8-b28e-3379573dd938","html_url":"https://github.com/dbtreasure/container-shim","commit_stats":null,"previous_names":["dbtreasure/container-shim"],"tags_count":0,"template":false,"template_full_name":null,"purl":"pkg:github/dbtreasure/container-shim","repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dbtreasure%2Fcontainer-shim","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dbtreasure%2Fcontainer-shim/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dbtreasure%2Fcontainer-shim/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dbtreasure%2Fcontainer-shim/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dbtreasure","download_url":"https://codeload.github.com/dbtreasure/container-shim/tar.gz/refs/heads/main","sbom_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dbtreasure%2Fcontainer-shim/sbom","scorecard":null,"host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":286080680,"owners_count":29352996,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2026-02-12T01:03:07.613Z","status":"ssl_error","status_checked_at":"2026-02-12T01:00:51.346Z","response_time":97,"last_error":"SSL_read: unexpected eof while reading","robots_txt_status":"success","robots_txt_updated_at":"2025-07-24T06:49:26.215Z","robots_txt_url":"https://github.com/robots.txt","online":false,"can_crawl_api":true,"host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2025-08-21T14:15:52.746Z","updated_at":"2026-02-12T01:39:58.029Z","avatar_url":"https://github.com/dbtreasure.png","language":null,"funding_links":[],"categories":[],"sub_categories":[],"readme":"# PRD — Docker REST API Shim on Apple Containerization (Tahoe)\n\n0) One-liner\n\nExpose a local Docker Engine–compatible REST API that translates to Apple’s Containerization framework so docker and docker compose work on macOS Tahoe without Docker Desktop.\n\n⸻\n\n1) Goals (grug edition)\n\t•\tKeep it tiny. Ship the smallest API surface that runs common Compose v3 stacks (web + db + cache + worker).\n\t•\tZero re-authoring. Existing docker/docker compose CLIs and dev tools target our socket and “just work” for core flows.\n\t•\tDeterministic mapping. Every Docker object maps cleanly to Apple runtime primitives.\n\nNon-Goals (v1)\n\t•\tSwarm/overlay, plugins, secrets/configs, swarm services.\n\t•\tFull BuildKit/buildx parity (we’ll do simple builds first).\n\t•\tRemote TLS daemon; start local-only (/var/run/docker.sock).\n\t•\tFull docker stats parity (basic later).\n\n⸻\n\n2) Target users / use cases\n\t•\tDevs running Compose v3: FastAPI + Postgres + Redis + workers, Node/Rails + DB, etc.\n\t•\tEditors/IDEs (VS Code devcontainers) that talk Docker API.\n\t•\tCI runners on macOS that need docker build/docker run locally.\n\n⸻\n\n3) Assumptions \u0026 constraints\n\t•\tmacOS Tahoe (26) with Apple Silicon; Containerization APIs available.\n\t•\tEach container = lightweight VM; each gets its own IP.\n\t•\tWe can bind to /var/run/docker.sock.\n\t•\tSwift implementation (SwiftNIO for HTTP), direct framework calls (no shelling out, except temporary escape hatches if needed).\n\n⸻\n\n4) North-star compatibility\n\t•\tCompose v3 (single host): services, images/build, env, ports, volumes, depends_on (ordering/health), restart, healthcheck.\n\t•\tDocker CLI: version, info (minimal), images, pull, build, ps, create, start, stop, rm, logs, exec, inspect, run (via create+start).\n\t•\tMinimal networks/volumes that satisfy Compose semantics.\n\n⸻\n\n5) Phased plan (ruthless scope cut)\n\nPhase 0 — Spike \u0026 API skeleton (foundations)\n\t•\tSystem endpoints: /_ping, /version, /info (static/minimal).\n\t•\tImages: GET /images/json, POST /images/create?fromImage=… (pull), GET /images/{id}/json.\n\t•\tContainers: GET /containers/json, POST /containers/create, POST /containers/{id}/start, POST /containers/{id}/stop, DELETE /containers/{id}, GET /containers/{id}/json.\n\t•\tMapping: Docker container name → Apple container name; track IDs.\n\t•\tState store (in-proc + on-disk journal): container metadata, Apple IDs, assigned IPs, port proxies, mounts.\n\t•\tHappy-path demo: docker run --name hello nginx:alpine + port publish to localhost via proxy.\n\nDoD: docker run -d -p 8080:80 nginx works; docker ps/logs/stop/rm work.\n\n⸻\n\nPhase 1 — Compose MVP (run common stack)\n\t•\tNetworks (MVP):\n\t•\tPOST /networks/create, GET /networks, DELETE /networks/{id} → create logical networks (bookkeeping).\n\t•\tAll containers actually share Tahoe vmnet; service discovery provided by hosts-file injection per container (/etc/hosts), so names resolve (db, redis).\n\t•\tVolumes (MVP):\n\t•\tPOST /volumes/create, GET /volumes, DELETE /volumes/{name} → host dir at ~/.apple-docker/volumes/\u003cname\u003e; mount with --mount type=bind.\n\t•\tPorts:\n\t•\t-p host:container via embedded TCP proxy (SwiftNIO) per mapping (replace socat).\n\t•\tDepends_on / healthchecks:\n\t•\tOrdering: start deps first.\n\t•\tHealth: support container HEALTHCHECK probe reading Dockerfile or Compose; implement pollers to mark healthy before starting dependents (timeout/backoff).\n\t•\tRestart policies: support no, on-failure, always (simple supervisor loop).\n\t•\tLogs/exec:\n\t•\tGET /containers/{id}/logs (stream from vsock/pty tap).\n\t•\tPOST /containers/{id}/exec + …/start (interactive ok, basic TTY).\n\nDoD: docker compose up runs FastAPI+Postgres+Redis+worker unchanged; down cleans containers, ports, and volumes (if requested).\n\n⸻\n\nPhase 2 — Build \u0026 ergonomics\n\t•\tBuild: POST /build (context tar stream) → Apple build; stream progress to client. Cache on host path; tags applied.\n\t•\tAuth: POST /auth//images/create with registry creds; store in macOS Keychain.\n\t•\tdocker run parity for common flags: -e, -v, --name, --cpus, --memory, --restart, --health-*, --workdir, --entrypoint.\n\nDoD: Can build app images from repo and compose them (no Desktop needed).\n\n⸻\n\nPhase 3 — Observability \u0026 resilience\n\t•\tEvents: GET /events (limited: start/stop/die/pull/build).\n\t•\tBasic stats: GET /containers/{id}/stats (CPU/mem from VM process; approximate).\n\t•\tCrash recovery: reconcile on start (enumerate Apple containers, rebuild state).\n\t•\tGarbage collection: clean orphaned proxies/mounts on container removal.\n\n⸻\n\nPhase 4 — Networking/volume fidelity (iterative)\n\t•\tDNS stub (tiny resolver) instead of hosts hacks.\n\t•\tOptional per-network subnet emulation (policy routing/NAT) if Tahoe APIs permit.\n\t•\tVolume drivers SPI (later).\n\n⸻\n\n6) Architecture (SOLID, minimal)\n\nModules (single binary, clear seams):\n\t•\tApiServer (HTTP/JSON over Unix socket; request routing).\n\t•\tImageService (pull/list/inspect/build).\n\t•\tContainerService (spec translation; create/start/stop/rm/exec/logs).\n\t•\tNetworkService (logical networks, name resolution, IP bookkeeping).\n\t•\tVolumeService (named volume registry, host path allocator, mounts).\n\t•\tPortPublisher (SwiftNIO TCP forwarders; lifecycle tied to container).\n\t•\tStateStore (interface; file-backed journal + in-memory index; crash-safe).\n\t•\tAppleRuntime (facade over Containerization APIs; no CLI shell-outs).\n\nKey patterns:\n\t•\tInterfaces per domain (Dependency Inversion): ApiServer depends on service interfaces, not impls.\n\t•\tDTO mappers: Docker API JSON ↔ internal model ↔ Apple model.\n\t•\tIdempotent ops: re-apply desired state safely.\n\t•\tSupervisor per container for restart/health.\n\n⸻\n\n7) Mapping (high-level)\n\nCreate container → Apple VM spec\n\t•\tImage ref, env, cwd, entrypoint/cmd, mounts, CPU/mem.\n\t•\tLabels: com.appledocker.project, network=\u003cname\u003e, volumes=\u003c…\u003e for reconciliation.\n\nStart → launch VM\n\t•\tAttach stdout/stderr to a pty/pipe for logs; open vsock for exec.\n\nPort publish\n\t•\tRegister \u003chostIP:hostPort\u003e → \u003ccontainerIP:containerPort\u003e in PortPublisher.\n\nNetworks\n\t•\tMaintain network membership in StateStore.\n\t•\tOn container start/attach to networks: update /etc/hosts inside VM with all peers (or DNS stub later).\n\nVolumes\n\t•\tResolve named volumes → host dirs; validate permissions; mount bind.\n\n⸻\n\n8) API surface by phase (explicit)\n\nP0/P1 must-have\n\t•\t/_ping, /version, /info\n\t•\t/images/json, /images/create, /images/{id}/json\n\t•\t/containers/json, /containers/create, /containers/{id}/json, /containers/{id}/start, /containers/{id}/stop, /containers/{id}/kill, /containers/{id}/wait, /containers/{id}, /containers/{id}/logs, /containers/{id}/attach(optional), /containers/{id}/exec, /exec/{id}/start\n\t•\t/networks/create|list|inspect|delete (logical)\n\t•\t/volumes/create|list|inspect|delete\n\t•\t/build (P2)\n\nReturn 501/ignored gracefully for unsupported flags; document.\n\n⸻\n\n9) Compatibility contract (v1)\n\t•\tWorks: docker, docker compose (local), VS Code devcontainers.\n\t•\tDiffs (doc’d):\n\t•\tMultiple user networks share same underlying vmnet (isolation best-effort).\n\t•\tstats approximate; some resource flags no-op.\n\t•\tPrivileged/devices not supported initially.\n\t•\tBuildKit features limited (no cache-mount/secret-mount v1).\n\n⸻\n\n10) Security\n\t•\tLocal Unix socket (user perms); no TCP listener v1.\n\t•\tNo root escalation in guest; VM boundary is isolation.\n\t•\tKeychain for registry creds.\n\t•\tValidate bind mounts (block / and sensitive paths by default; allowlist config).\n\n⸻\n\n11) Testing strategy\n\t•\tConformance: run a curated subset of Docker Engine API tests (where practicable).\n\t•\tCompose suites: sample apps (FastAPI+Postgres+Redis, Rails+Postgres, Node+Mongo).\n\t•\tSoak: start/stop loops; port flaps; crash and reconcile.\n\t•\tFailure modes: image not found, port already in use, volume path invalid, exec on dead container.\n\n⸻\n\n12) Metrics for success\n\t•\tCompose MVP stack: zero file edits; up, logs -f, exec, down pass.\n\t•\tdocker run path: p50 container start \u003c 2s; p95 port-open \u003c 2.5s.\n\t•\tIdle CPU ≈ 0%, idle mem \u003c 50MB when no containers.\n\t•\tNo orphaned proxies/mounts after rm/down.\n\n⸻\n\n13) Risks \u0026 mitigations\n\t•\tNetworking fidelity: names may glitch → start with hosts injection; add DNS stub later.\n\t•\tBind-mount perf: document expectations; perf test common stacks; consider async file I/O hints.\n\t•\tCrash recovery: durable StateStore; reconcile on boot by querying Apple runtime.\n\t•\tAPI drift: pin Docker API version; gate unknown fields.\n\n⸻\n\n14) Open questions\n\t•\tCan Tahoe expose APIs for separate subnets/bridges? If yes, adjust NetworkService v2 to real isolation.\n\t•\tBest hook for in-guest file editing (hosts): via exec? cloud-init-like init? framework support?\n\t•\tRosetta policy toggles per-container: expose via labels or infer by arch?\n\n⸻\n\n15) Deliverables per phase\n\nP0 (4–6 slices, no dates):\n\t•\tDaemon with /var/run/docker.sock\n\t•\tImages: pull/list\n\t•\tContainers: create/start/stop/rm/inspect\n\t•\tPortPublisher for -p\n\t•\tLogs (non-TTY), Exec (non-interactive acceptable)\n\nP1:\n\t•\tCompose happy path (networks/volumes logical)\n\t•\tDepends_on ordering + basic health gate\n\t•\tRestart policies (no|on-failure|always)\n\t•\tInteractive exec + logs -f\n\nP2:\n\t•\tdocker build (streaming), auth, keychain\n\t•\tCrash reconciliation, GC, events (start/stop/pull/build)\n\n⸻\n\n16) Acceptance tests (for your stack)\n\t•\tdocker compose up -d (FastAPI 8000, Postgres 5432, Redis 6379, worker)\n\t•\tApp resolves db:5432 and redis:6379 from within containers.\n\t•\tcurl localhost:8000/health → 200.\n\t•\tRestart DB → app reconnects (restart policy honored).\n\t•\tdocker compose down -v cleans containers, proxies, and named volumes.\n\n⸻\n\n17) Minimal config\n\t•\tYAML: none required; everything defaults sane.\n\t•\tEnv:\n\t•\tAPPLE_DOCKER_STATE_DIR=~/.apple-docker\n\t•\tAPPLE_DOCKER_DEBUG=0|1\n\n⸻\n\n18) Docs to ship with MVP\n\t•\t“What works/What differs” page (one screen).\n\t•\tQuickstart: point Docker CLI to our socket (export DOCKER_HOST=unix:///var/run/docker.sock if needed).\n\t•\tTroubleshooting: ports in use, health timeouts, volume perms.\n\n⸻\n\nIf you want, I’ll turn this into GitHub issues (labels by phase), plus a skeletal Swift module layout and the JSON schemas for the few Docker endpoints we’ll implement first.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdbtreasure%2Fcontainer-shim","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdbtreasure%2Fcontainer-shim","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdbtreasure%2Fcontainer-shim/lists"}