fruitbox

module
v0.1.0 Latest Latest
Warning

This package is not in the latest version of its module.

Go to latest
Published: Jun 27, 2026 License: MIT

README

fruitbox

A docker compose for Apple's native container runtime.

Run your multi-container apps from a compose.yaml on Apple silicon — no Docker daemon required.

Go Compose Spec Status


fruitbox takes the Compose file you already have and runs it on Apple's container — the lightweight-VM container runtime built into macOS for Apple silicon. Same compose.yaml, same commands you know from docker compose, but each service runs in its own fast native VM instead of a Docker daemon.

$ fruitbox up -d
Creating network "myapp_default"
Starting myapp-db-1
Starting myapp-web-1

$ fruitbox ps
NAME          IMAGE          SERVICE  STATUS   PORTS
myapp-db-1    postgres:16    db       running
myapp-web-1   nginx:1.27     web      running  0.0.0.0:8080->80/tcp

Quick start

You need macOS 15+ on Apple silicon with Apple's container installed and started (container system start), plus Go 1.25+ to build.

# Install
go install github.com/urjitbhatia/fruitbox/cmd/fruitbox@latest

# …or build from source
git clone https://github.com/urjitbhatia/fruitbox && cd fruitbox
go build -o fruitbox ./cmd/fruitbox

Then, in any directory with a compose.yaml:

fruitbox up -d          # build, create, and start everything
fruitbox ps             # see what's running
fruitbox logs -f        # tail logs (multiplexed, color-prefixed per service)
fruitbox exec web sh    # shell into a service
fruitbox down           # tear it all down

Global flags mirror Docker Compose: -f/--file, -p/--project-name, --profile, --env-file, --project-directory. (--container-binary points at a non-default container.)

Why

docker compose talks to the Docker Engine API. Apple's container speaks a different CLI and runs each container in its own lightweight VM. fruitbox is the orchestration layer in between: it parses Compose files exactly the way Docker Compose does — using the same reference library — then translates the resolved model into container invocations and manages lifecycle, dependency ordering, health, restart policies, and resource grouping.

The headline benefit: keep your existing Compose workflow, drop the Docker daemon.

Status

fruitbox is early but already broadly usable — 32 of docker compose's commands are implemented and exercised against the real runtime, including up/down/ps/logs/exec/ build/run/watch and config-hash-based recreation. It is not yet at a 1.0; expect rough edges, and see COMPATIBILITY.md for a precise, machine-checked breakdown of exactly which commands and flags are supported and which can't be (and why).

Issues and PRs welcome — see Contributing.

How it works

fruitbox reuses the official Compose reference parser (compose-spec/compose-go — the same library Docker Compose itself uses) for loading, interpolation, merging, profiles and extends. That guarantees parsing fidelity with the latest spec. fruitbox owns the translation and orchestration:

Package Responsibility
internal/compose Loads compose files into a resolved types.Project (wraps compose-go)
internal/translate Converts services/networks/volumes → container argument vectors
internal/runner Executes the container CLI (mockable for tests)
internal/engine Orchestration: dependency order, recreate, health, restart, logs
internal/cli Cobra command tree mirroring docker compose

Resources carry the canonical com.docker.compose.* labels and a fruitbox-native io.fruitbox.* mirror, and containers are named <project>-<service>-<n> — so they stay compatible with Docker tooling while also being identifiable without it.

All 32 commands (click to expand)
Command Notes
config parse, resolve & render canonical YAML/JSON; --services/--networks/--volumes/--images/--profiles/--hash/--environment
up create + start in dependency order; recreate on config change; foreground log streaming + restart supervision
down stop & remove containers (reverse order), networks, optional volumes/images
ps live image/status/ports; --format json, --filter, --status, --all, --services
logs concurrent multiplexed streaming with color per-service prefixes; --tail/--follow/--timestamps
build build:container build; --build-arg/--no-cache/--pull/--push/--with-dependencies
run one-off with deps; --entrypoint/--user/--volume/--publish/--service-ports/--rm
exec run a command in a service container (-it, --index, --detach)
create / start / stop / restart / kill lifecycle control (dependency-ordered)
pull / push image transfer (--include-deps, --ignore-*-failures, --policy)
pause / unpause suspend/resume via SIGSTOP/SIGCONT
scale scale services up/down
cp copy files to/from a service container
port resolve the published host port
top in-container ps
images / volumes list images / volumes used by the project
ls list running compose projects (runtime-wide)
stats live resource usage (container stats)
export export a container filesystem to a tar
events stream lifecycle events
wait block until containers stop, print exit code
attach attach to a container's I/O
watch sync/restart/rebuild on source change (develop.watch)
version

Compatibility & the honest bits

The goal is to run your existing compose.yaml unchanged. fruitbox supports the full Compose service model the runtime can express — image, build, command, entrypoint, environment, ports, volumes, networks, depends_on (incl. service_healthy / service_completed_successfully), healthcheck, restart, secrets/configs, cpus, mem_limit, cap_add/drop, dns, scale, and more.

Some things Apple's runtime simply can't do, and fruitbox is upfront about them rather than faking them:

  • Healthchecks aren't run by the runtime, so fruitbox supervises them itself.
  • restart: policies have no daemon, so a foreground up supervises and restarts.
  • A few attributes have no runtime equivalent — hostname, extra_hosts, sysctls are emulated (generated /etc/hosts, post-start sysctl, …); privileged, devices, mac_address, group_add are true VM-isolation boundaries and emit an explicit WARNING.
  • A handful of docker compose flags map to runtime features that don't exist (e.g. logs --since — the runtime stores no per-line timestamps). These are documented, not silently ignored.

The full, machine-verified breakdown — including a TestFlagParity ratchet and a differential test against a real docker compose install — lives in COMPATIBILITY.md.

Robustness

  • Concurrency-safe: lifecycle commands take a per-project advisory flock, so two mutating commands on the same project can't race; a blocked one fails fast with the holder's PID, and read-only commands never lock.
  • Graceful Ctrl-C: a foreground up stops the project's containers on the first SIGINT and force-quits on the second — just like docker compose.
  • Idempotent: re-running up reuses up-to-date containers (config-hash) and skips already-created networks/volumes.

Development

go build ./cmd/fruitbox   # build
go test ./...             # hermetic unit suite (no container runtime needed)
make test-integration     # integration lane against the real `container` runtime
make compat               # differential flag-audit vs. a local `docker compose`

The unit suite is hermetic — translation and orchestration run against a fake runner, so no container install is required to hack on fruitbox. The integration lane (build-tagged integration) drives the real runtime end-to-end and skips automatically when it's unavailable.

Contributing

Contributions are very welcome — bug reports, compose files that don't work, and PRs.

  • Run go test ./... (and make test-integration if you have the runtime) before opening a PR.
  • New behavior is test-first: translation/orchestration changes get a runner.Fake test; flag changes update the TestFlagParity ratchet in internal/cli.
  • Keep gofmt/go vet clean.

See CONTRIBUTING.md for the longer version.

License

MIT © fruitbox contributors.

Acknowledgements


fruitbox is an independent project, not affiliated with, endorsed by, or sponsored by Apple Inc. or Docker, Inc. "Apple" and "container" are referenced descriptively to indicate runtime compatibility; "Docker" and "Docker Compose" are trademarks of Docker, Inc.

Directories

Path Synopsis
cmd
fruitbox command
Command fruitbox is a Docker Compose-compatible orchestrator for Apple's native `container` runtime.
Command fruitbox is a Docker Compose-compatible orchestrator for Apple's native `container` runtime.
internal
cli
Package cli implements the fruitbox command-line interface, a Docker Compose-compatible front end that drives Apple's `container` runtime.
Package cli implements the fruitbox command-line interface, a Docker Compose-compatible front end that drives Apple's `container` runtime.
compose
Package compose loads Docker Compose files into a fully-resolved project model.
Package compose loads Docker Compose files into a fully-resolved project model.
engine
Package engine orchestrates a compose project against the container runtime: creating networks and volumes, then starting/stopping service containers in dependency order.
Package engine orchestrates a compose project against the container runtime: creating networks and volumes, then starting/stopping service containers in dependency order.
runner
Package runner abstracts execution of Apple's `container` CLI so that the orchestration engine can be unit-tested without the binary present.
Package runner abstracts execution of Apple's `container` CLI so that the orchestration engine can be unit-tested without the binary present.
translate
Package translate converts a resolved Docker Compose project model into the argument vectors understood by Apple's `container` CLI.
Package translate converts a resolved Docker Compose project model into the argument vectors understood by Apple's `container` CLI.

Jump to

Keyboard shortcuts

? : This menu
/ : Search site
f or F : Jump to
y or Y : Canonical URL