I would love to use Apple/container with WordPress's docker environment. I ran into several issues and will apologize in advance for the AI details below.
Fundamentally I believe the primary issue is missing exec / port / ps / logs subcommands. What follows is the full AI testing report.
Issue: container-compose cannot run @wordpress/env (wp-env) multi-service stacks
Summary
Container-Compose 1.1.0 (Homebrew homebrew/core; upstream
github.com/Mcrich23/Container-Compose) cannot bring up a
@wordpress/env ("wp-env") environment. wp-env emits a standard
docker-compose.yml (~7 services: 2 MariaDB, 2 WordPress, 2 CLI,
2 phpMyAdmin) and drives it through the docker / docker compose
CLI. Three gaps block it:
- Missing
exec / port / ps / logs subcommands — wp-env
calls docker compose exec (for wp-env run) and docker compose port
(to read the mapped MySQL host port). container-compose exposes only
up / down / build / version.
- Host-port collision when two services bind the same host port —
booting the dev + tests MariaDB together with identical port mappings
deterministically fails with
bind(descriptor:ptr:bytes:): Address already in use (errno: 48).
- No
pull subcommand — wp-env calls docker compose pull;
container-compose auto-pulls inside up, so pull is a no-op
workaround, but the missing surface is still a parity gap.
Note: this report was produced while evaluating container-compose as a
replacement for Podman / Docker Desktop. The environment was reverted to
Podman afterward. Findings below are reproducible on a clean
Apple container 1.1.0 + container-compose 1.1.0 install.
Environment (exact)
| Component |
Version |
| macOS |
26.5.2 (Tahoe) |
Apple container |
1.1.0 (Homebrew homebrew/core, release unspecified) |
container-compose |
1.1.0 (Homebrew homebrew/core) |
@wordpress/env |
^10.0 |
| Test driver |
composer wp-env-start → wp-env start --xdebug=coverage |
The docker CLI is shimmed to container-compose (a thin
bin/docker wrapper translating docker compose … → container-compose …).
No Docker Desktop, no Podman involved in the Apple path.
Issue 1 (blocker): Missing exec / port / ps / logs
What wp-env needs
wp-env's runtime
(@wordpress/env/lib/runtime/docker/index.js) shells out to:
docker compose up -d mysql then
docker compose up -d wordpress tests-wordpress cli tests-cli
docker compose port <svc> <port> — to read the mapped MySQL port
(e.g. docker compose port mysql 3306 → 0.0.0.0:46239)
docker compose exec <svc> … — for wp-env run tests-cli …
(the composer test flow)
docker compose down / ps / logs
What container-compose provides
$ container-compose --help
SUBCOMMANDS:
up Start containers with compose
down Stop containers with compose
build Build images from a compose file without starting containers
version Display the version information
There is no exec, port, ps, or logs. Consequently, even
if up succeeds, these wp-env flows are impossible:
wp-env run tests-cli wp --version → needs compose exec → no such command
- Port discovery (
_getPublicDockerPort) → needs compose port → no such command
- Any
composer test invocation → routes through compose exec → fails
Expected behavior
For wp-env compatibility, container-compose needs at minimum
exec and port subcommands mirroring docker compose exec /
docker compose port semantics (including -f <file> handling and the
<service> <container_port> argument shape wp-env emits).
Issue 2 (blocker for the tests stack): Host-port collision
Verbatim reproduction
Clean slate, then boot both database services together (this is what
wp-env does internally — it brings up mysql first, then the full
wordpress tests-wordpress cli tests-cli set which pulls in tests-mysql
as a dependency):
container-compose -f ~/.wp-env/<hash>/docker-compose.yml \
up -d mysql tests-mysql
With both services mapped to the same host port (e.g.
WP_ENV_MYSQL_PORT=17888 WP_ENV_TESTS_MYSQL_PORT=17888):
Note: Service 'mysql' is not explicitly connected to any networks.
It will likely use the default bridge network.
Starting service: mysql
Starting mysql
----------------------------------------
mysql: [6/6] Starting container [0s]
mysql: [6/6] Starting container [0s]
mysql: git-updater-mysql
Note: Service 'tests-mysql' is not explicitly connected to any networks.
It will likely use the default bridge network.
Starting service: tests-mysql
Starting tests-mysql
----------------------------------------
tests-mysql: [6/6] Starting container [0s]
Error: failed to bootstrap container
(cause: "internalError: "failed to bootstrap container git-updater-tests-mysql
(cause: "unknown: "bind(descriptor:ptr:bytes:): Address already in use
(errno: 48)"")")
(errno: 48 = EADDRINUSE.)
Root-cause distinction (important)
The compose file maps both DB services to distinct host ports via
env vars, with distinct internal 3306:
mysql:
ports:
- '${WP_ENV_MYSQL_PORT:-}:3306'
tests-mysql:
ports:
- '${WP_ENV_TESTS_MYSQL_PORT:-}:3306'
Two separate failure modes were observed and should not be conflated:
- (a) Same port → 100% collision (deterministic). When both
WP_ENV_MYSQL_PORT and WP_ENV_TESTS_MYSQL_PORT resolve to the
same value, tests-mysql fails to boot every time with the
errno: 48 error above. Reproduced 5/5 attempts.
- (b) Distinct ports → reliable success. With
WP_ENV_MYSQL_PORT=17701 WP_ENV_TESTS_MYSQL_PORT=17702,
both containers booted cleanly across 5/5 attempts.
- (c) Apple
container service crash (separate issue). The stock
homebrew/core container formula does not register a launchd
service the way the stephenlclarke/container fork does. The API
server intermittently dies mid-run with
XPC connection error: Connection invalid, after which
container ls itself errors and no containers start. This was a
separate source of "nothing booted" that initially looked like a
port collision. Restarting with container system start recovers it.
Expected behavior
Each service's ${VAR:-} port mapping should resolve to a distinct,
free host port (or honor the explicit WP_ENV_TESTS_MYSQL_PORT
value) without colliding with the sibling DB service — matching
Docker Compose / Podman behavior, where the distinct-port case boots
reliably every time.
Issue 3 (minor parity gap): No pull subcommand
wp-env's start flow calls docker compose pull (via the
docker-compose npm package's pullAll). container-compose has
no pull subcommand:
$ container-compose pull
Error: Unexpected argument 'pull'
Usage: container-compose [--file <file>] [--profile <profile>] ...] <subcommand>
In practice up auto-pulls images, so mapping pull → no-op works
as a shim around wp-env — but the missing surface is still a parity
gap versus docker compose.
Additional observation: port-default mismatch in wp-env's generated file
wp-env's generated docker-compose.yml uses these port defaults:
wordpress:
ports:
- '${WP_ENV_PORT:-8888}:80' # NOTE: 8888, not 7778
tests-wordpress:
ports:
- '${WP_ENV_TESTS_PORT:-8889}:80' # NOTE: 8889, not 7779
The npm script sets WP_ENV_PORT=7778 WP_ENV_TESTS_PORT=7779,
but the compose file's own :- fallback is 8888 / 8889.
container-compose interpolates ${VAR:-default} from the shell
environment at up time. When the var is absent it falls back to
8888 (which happened to be free, so up succeeded). This is a
wp-env-side quirk, but it interacts with Issue 2: if any two
port variables ever resolve to the same value (explicit or via
fallback), container-compose has no collision-avoidance and fails
hard with errno: 48 rather than reallocating like Docker Compose.
What does work (for completeness)
Against stock Apple container 1.1.0 via container-compose 1.1.0:
- ✅
container-compose -f <file> up -d mysql — dev DB starts
- ✅
container-compose -f <file> down — teardown
- ✅ Named-volume creation is idempotent (no "already exists" error
on re-up), unlike the stephenlclarke/container-compose fork
which fails here
- ✅ Project name defaults to the compose-file directory name
(not the wp-env hash) — fine
So container-compose is closer to wp-env-usable than the
stephenlclarke fork was, but the three gaps above still block a full
@wordpress/env run (and the container service-crash in (c) is a
separate environment fragility).
Addendum: can the port collision be worked around?
Partially, and it does NOT unblock wp-env.
The host-port collision (Issue 2a) is avoidable: when the two MariaDB
services map to distinct host ports it boots reliably. Verified
5/5 attempts with WP_ENV_MYSQL_PORT=17901 WP_ENV_TESTS_MYSQL_PORT=17902:
--- attempt 1: mysql=17901 tests-mysql=17902 ---
OK both booted
... (attempts 2-5 identical: OK both booted)
So forcing distinct ports removes the errno: 48 collision
deterministically. But wp-env still cannot complete, because the
missing exec / port subcommands (Issue 1) are the real
blocker, independent of ports:
wp-env start calls docker compose port mysql 3306 to discover
the mapped MySQL host port and print "MySQL is listening on port X".
container-compose has no port subcommand → this step fails.
wp-env run / composer test route through
docker compose exec <svc> … → no exec subcommand → impossible.
Conclusion: fixing the port mapping (Issue 2a) is a nice-to-have,
but wp-env only becomes usable once Issue 1 (exec + port) is
resolved upstream. Until then, Podman remains the only functional
backend, and the port-collision detail is secondary context for the
maintainer rather than a standalone fix.
Suggested minimal fix set for wp-env support
- Add
exec and port subcommands (highest priority — without
these, wp-env run / port discovery are impossible).
- Fix same-port collision in
up (Issue 2a) — either detect /
reject duplicate host-port mappings up front, or allocate a free
port like Docker Compose when the mapping conflicts.
- Add
pull (or accept + ignore pull for Docker-Compose
compatibility).
- (Nice-to-have)
ps / logs for parity.
Happy to test a build / --HEAD install if any of these land.
I would love to use Apple/container with WordPress's docker environment. I ran into several issues and will apologize in advance for the AI details below.
Fundamentally I believe the primary issue is missing
exec/port/ps/logssubcommands. What follows is the full AI testing report.Issue:
container-composecannot run@wordpress/env(wp-env) multi-service stacksSummary
Container-Compose1.1.0 (Homebrewhomebrew/core; upstreamgithub.com/Mcrich23/Container-Compose) cannot bring up a@wordpress/env("wp-env") environment. wp-env emits a standarddocker-compose.yml(~7 services: 2 MariaDB, 2 WordPress, 2 CLI,2 phpMyAdmin) and drives it through the
docker/docker composeCLI. Three gaps block it:
exec/port/ps/logssubcommands — wp-envcalls
docker compose exec(forwp-env run) anddocker compose port(to read the mapped MySQL host port).
container-composeexposes onlyup/down/build/version.booting the dev + tests MariaDB together with identical port mappings
deterministically fails with
bind(descriptor:ptr:bytes:): Address already in use (errno: 48).pullsubcommand — wp-env callsdocker compose pull;container-composeauto-pulls insideup, sopullis a no-opworkaround, but the missing surface is still a parity gap.
Environment (exact)
containerhomebrew/core,release unspecified)container-composehomebrew/core)@wordpress/envcomposer wp-env-start→wp-env start --xdebug=coverageThe
dockerCLI is shimmed tocontainer-compose(a thinbin/dockerwrapper translatingdocker compose …→container-compose …).No Docker Desktop, no Podman involved in the Apple path.
Issue 1 (blocker): Missing
exec/port/ps/logsWhat wp-env needs
wp-env's runtime
(
@wordpress/env/lib/runtime/docker/index.js) shells out to:docker compose up -d mysqlthendocker compose up -d wordpress tests-wordpress cli tests-clidocker compose port <svc> <port>— to read the mapped MySQL port(e.g.
docker compose port mysql 3306→0.0.0.0:46239)docker compose exec <svc> …— forwp-env run tests-cli …(the
composer testflow)docker compose down/ps/logsWhat
container-composeprovidesThere is no
exec,port,ps, orlogs. Consequently, evenif
upsucceeds, these wp-env flows are impossible:wp-env run tests-cli wp --version→ needscompose exec→ no such command_getPublicDockerPort) → needscompose port→ no such commandcomposer testinvocation → routes throughcompose exec→ failsExpected behavior
For wp-env compatibility,
container-composeneeds at minimumexecandportsubcommands mirroringdocker compose exec/docker compose portsemantics (including-f <file>handling and the<service> <container_port>argument shape wp-env emits).Issue 2 (blocker for the tests stack): Host-port collision
Verbatim reproduction
Clean slate, then boot both database services together (this is what
wp-env does internally — it brings up
mysqlfirst, then the fullwordpress tests-wordpress cli tests-cliset which pulls intests-mysqlas a dependency):
With both services mapped to the same host port (e.g.
WP_ENV_MYSQL_PORT=17888 WP_ENV_TESTS_MYSQL_PORT=17888):(
errno: 48=EADDRINUSE.)Root-cause distinction (important)
The compose file maps both DB services to distinct host ports via
env vars, with distinct internal
3306:Two separate failure modes were observed and should not be conflated:
WP_ENV_MYSQL_PORTandWP_ENV_TESTS_MYSQL_PORTresolve to thesame value,
tests-mysqlfails to boot every time with theerrno: 48error above. Reproduced 5/5 attempts.WP_ENV_MYSQL_PORT=17701 WP_ENV_TESTS_MYSQL_PORT=17702,both containers booted cleanly across 5/5 attempts.
containerservice crash (separate issue). The stockhomebrew/corecontainerformula does not register a launchdservice the way the
stephenlclarke/containerfork does. The APIserver intermittently dies mid-run with
XPC connection error: Connection invalid, after whichcontainer lsitself errors and no containers start. This was aseparate source of "nothing booted" that initially looked like a
port collision. Restarting with
container system startrecovers it.Expected behavior
Each service's
${VAR:-}port mapping should resolve to a distinct,free host port (or honor the explicit
WP_ENV_TESTS_MYSQL_PORTvalue) without colliding with the sibling DB service — matching
Docker Compose / Podman behavior, where the distinct-port case boots
reliably every time.
Issue 3 (minor parity gap): No
pullsubcommandwp-env's start flow calls
docker compose pull(via thedocker-composenpm package'spullAll).container-composehasno
pullsubcommand:In practice
upauto-pulls images, so mappingpull→ no-op worksas a shim around wp-env — but the missing surface is still a parity
gap versus
docker compose.Additional observation: port-default mismatch in wp-env's generated file
wp-env's generated
docker-compose.ymluses these port defaults:The npm script sets
WP_ENV_PORT=7778 WP_ENV_TESTS_PORT=7779,but the compose file's own
:-fallback is8888/8889.container-composeinterpolates${VAR:-default}from the shellenvironment at
uptime. When the var is absent it falls back to8888(which happened to be free, soupsucceeded). This is awp-env-side quirk, but it interacts with Issue 2: if any two
port variables ever resolve to the same value (explicit or via
fallback),
container-composehas no collision-avoidance and failshard with
errno: 48rather than reallocating like Docker Compose.What does work (for completeness)
Against stock Apple
container1.1.0 viacontainer-compose1.1.0:container-compose -f <file> up -d mysql— dev DB startscontainer-compose -f <file> down— teardownon re-
up), unlike thestephenlclarke/container-composeforkwhich fails here
(not the wp-env hash) — fine
So
container-composeis closer to wp-env-usable than thestephenlclarke fork was, but the three gaps above still block a full
@wordpress/envrun (and thecontainerservice-crash in (c) is aseparate environment fragility).
Addendum: can the port collision be worked around?
Partially, and it does NOT unblock wp-env.
The host-port collision (Issue 2a) is avoidable: when the two MariaDB
services map to distinct host ports it boots reliably. Verified
5/5 attempts with
WP_ENV_MYSQL_PORT=17901 WP_ENV_TESTS_MYSQL_PORT=17902:So forcing distinct ports removes the
errno: 48collisiondeterministically. But wp-env still cannot complete, because the
missing
exec/portsubcommands (Issue 1) are the realblocker, independent of ports:
wp-env startcallsdocker compose port mysql 3306to discoverthe mapped MySQL host port and print "MySQL is listening on port X".
container-composehas noportsubcommand → this step fails.wp-env run/composer testroute throughdocker compose exec <svc> …→ noexecsubcommand → impossible.Conclusion: fixing the port mapping (Issue 2a) is a nice-to-have,
but wp-env only becomes usable once Issue 1 (
exec+port) isresolved upstream. Until then, Podman remains the only functional
backend, and the port-collision detail is secondary context for the
maintainer rather than a standalone fix.
Suggested minimal fix set for wp-env support
execandportsubcommands (highest priority — withoutthese,
wp-env run/ port discovery are impossible).up(Issue 2a) — either detect /reject duplicate host-port mappings up front, or allocate a free
port like Docker Compose when the mapping conflicts.
pull(or accept + ignorepullfor Docker-Composecompatibility).
ps/logsfor parity.Happy to test a
build/--HEADinstall if any of these land.