docker-compose like tool for apple container.
Load docker-compose.yaml as-is.
brew tap ieee0824/tap
brew install apricotgo install github.com/ieee0824/apricot/cmd/apricot@latestgo build -o /usr/local/bin/apricot ./cmd/apricot/Run in the directory containing docker-compose.yaml.
Start services.
apricot up # foreground
apricot up -d # background
apricot up --build # force rebuild of build: services
apricot up --scale web=3 # start 3 instances of web
apricot up --scale web=3 --scale db=2 # scale multiple services
apricot up -f path/to/docker-compose.yaml # specify file
apricot up -p myproject # specify project nameScaled containers are named <project>-<service>-<index> (e.g. myapp-web-1, myapp-web-2).
Services with build: are built only when their image does not exist yet (same as docker-compose); pass --build to force a rebuild, or use apricot build.
Build images defined in docker-compose.yaml.
apricot build # build all services
apricot build web # build specific serviceStop and remove services.
apricot down # stop and remove containers
apricot down -v # also remove volumesList containers for the current project.
apricot ps
apricot ps -a # include stopped containersShow container logs.
apricot logs # all services
apricot logs web # specific service
apricot logs -f web # followRun a command in a running service container.
apricot exec web sh # start sh
apricot exec -it web bash # interactive + TTY
apricot exec -u 1000 web whoami # specify user
apricot exec -w /app web pwd # specify working directory| Option | Description |
|---|---|
-t |
Allocate TTY |
-i |
Keep stdin open |
-d |
Detached mode |
-u <user> |
Specify user |
-w <dir> |
Specify working directory |
| Option | Description | Default |
|---|---|---|
-f <file> |
Path to docker-compose.yaml | docker-compose.yaml |
-p <project> |
Project name | current directory name |
| Field | Supported |
|---|---|
image |
✅ |
build |
✅ |
ports |
✅ (short and long syntax) |
volumes |
✅ (short and long syntax) |
environment |
✅ |
env_file |
✅ |
working_dir |
✅ |
user |
✅ |
entrypoint |
✅ |
command |
✅ |
platform |
✅ |
networks |
|
labels |
✅ |
cpus |
✅ |
mem_limit |
✅ |
stdin_open |
✅ |
tty |
✅ |
read_only |
✅ |
tmpfs |
✅ |
dns |
✅ |
dns_search |
✅ |
dns_opt |
✅ |
init |
✅ (maps to container run --init) |
ulimits |
✅ (maps to container run --ulimit) |
cap_add |
✅ (maps to container run --cap-add) |
cap_drop |
✅ (maps to container run --cap-drop) |
depends_on |
✅ (startup order + condition: service_healthy) |
healthcheck |
✅ (used for service_healthy waits) |
container_name |
✅ |
restart |
❌ (not supported) |
security_opt |
❌ (Apple Container has no equivalent) |
- networks: Non-default network configuration requires macOS 26 or newer (Apple Container runtime limitation). On older macOS versions,
networkssettings are automatically skipped with a warning. - Service discovery: Apple Container has no container-to-container DNS on its networks (apple/container#1809), so containers cannot resolve each other by name out of the box. apricot emulates docker-compose service discovery by appending entries mapping each service name and container name to its IP to
/etc/hostsof every container on a shared network duringup. Services started earlier (depends_onorder) are resolvable from later ones at startup; later ones become resolvable from earlier ones as soon as they start. With--scale N, the bare service name points at the first replica; other replicas are reachable by container name (<project>-<service>-<n>). Injection needs/bin/shand a writable/etc/hostsin the image (fails with a warning otherwise) and can be disabled withAPRICOT_DISABLE_HOSTS_INJECT=1. Entries are tagged with a# apricot:<container>comment and replaced in place, so a partialapricot up <service>propagates the recreated service's new IP to the project's running containers as well. If a container is restarted outside of apricot and gets a new IP, stale entries remain until the nextapricot uprecreates the affected service. - init:
init: trueis passed through ascontainer run --init, which runs an init process that forwards signals and reaps zombie processes (Apple Container v1.1.0+). - ulimits: Both the shorthand (
nofile: 1024) and long form (nofile: {soft: 1024, hard: 2048}) are passed through ascontainer run --ulimit <type>=<soft>[:<hard>](Apple Container v1.1.0+). - cap_add / cap_drop: Passed through as
container run --cap-add/--cap-drop(Apple Container v0.12.0+). Both prefixed (CAP_NET_RAW) and unprefixed (NET_RAW) capability names work, as doesALL. - security_opt: The Apple Container CLI has no
--security-optequivalent (seccomp/AppArmor profiles do not apply to its VM-per-container isolation model), so this setting is ignored with a warning. - healthcheck: Apple Container has no native healthcheck, so apricot runs the
testcommand inside the container viacontainer exec(honoringinterval/timeout/retries/start_period). It is used to satisfydepends_on: { x: { condition: service_healthy } }, which makesupwait for a dependency to become healthy before starting dependents.condition: service_completed_successfullyis not yet supported. - Unsupported keys: Any service key apricot does not handle (e.g.
deploy,restart,extends,profiles) is reported with a warning when the compose file is loaded, instead of being silently dropped. - Named volumes: Named volumes are project-scoped as
<project>_<name>, matching docker-compose (this is also whatapricot down -vdeletes). Whenupcreates a new volume, it is seeded once from the service image — contents, ownership and mode of the directory it mounts over — emulating docker's copy-on-first-use, because Apple Container mounts a bare volume as a root-owned empty directory that non-root users cannot write to (apple/container#729). Seeding needs/bin/shin the image and can be disabled withAPRICOT_DISABLE_VOLUME_INIT=1. Volumes created by apricot ≤ v1.2.2 under bare names (e.g.datainstead ofmyproject_data) are no longer used; copy data over or remove them manually if needed. - tty / stdin_open:
container run -t -irequires stdin to be a real terminal (it fails withOperation not supported by deviceotherwise, even detached). When apricot runs without a terminal on stdin (CI, scripts),stdin_openis dropped with a warning so the service still starts. - Build context filtering:
container buildscans every file in the build context — even ones excluded by.dockerignore— at a per-file CPU cost (apple/container#2026), which adds minutes for contexts with large ignored trees (target/,node_modules, ...). As a workaround, when the context has a.dockerignore, apricot builds from a temporary copy containing only the non-ignored files (created with APFS clonefile, so it is fast and consumes no extra disk space, and removed after the build). SetAPRICOT_DISABLE_CONTEXT_FILTER=1to build from the original context directory.