Repository navigation
fix: make the documented docker compose command work - #2182
Conversation
doc/development.md offers `docker compose --profile openvsx --profile kibana up`
as the way to start a development stack. It does not start anything:
service "server" depends on undefined service "postgres": invalid compose project
`server` is in the `openvsx` and `backend` profiles while `postgres` is in `db`
and `debug`, so the project fails to validate before a container is created.
Anyone following our own instructions hits this first. postgres and
elasticsearch now also belong to the profiles that select the service depending
on them.
Two healthchecks could never have passed either, which is why nothing noticed:
- elasticsearch curled `http://elasticsearch01:9200`, a host that does not
exist here - the service is `elasticsearch`. Inside the container that
resolves to exit 6 while the cluster is green, so it sat in "starting" for
the full 50 retries and then reported unhealthy.
- server curled `localhost:8081/actuator/health`, and eclipse-temurin:25-jdk
ships no curl, wget, nc or python. bash is there, so its /dev/tcp asks the
actuator the same question with nothing to install. The alternative was
apt-get on every start, which is what #1258 proposed and what its author
was working around when the base image was openjdk:17.
With both fixed, `depends_on` can finally wait on readiness rather than only on
container creation, which is the ordering problem #1258 originally reported: the
server no longer races a Postgres that has not finished initialising or an
Elasticsearch that has not opened its port. postgres gained a pg_isready check
for the same reason.
Credit to @hbyecoding, who reported all of this in #1258 in June 2025 against
the file as it then was. Most of that PR has since been overtaken - the memory
settings and ulimits it added are in main already, and the base image it fixed
is gone - but the three findings underneath it were still here.
Verified with docker: both profile commands now resolve, postgres reports
healthy in ~12s and elasticsearch in ~36s where it previously never did, and a
cold `up server` creates the server container only after both report healthy
(dependencies at 20:15:45, server at 20:16:01).
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
There was a problem hiding this comment.
🟡 Changes recommended
The new server healthcheck relies on bash-only /dev/tcp but is configured as CMD-SHELL, which runs under /bin/sh and can break readiness/depends_on ordering.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Pull request overview
This PR fixes the developer documentation and Docker Compose setup so the documented docker compose --profile ... up commands validate and the service readiness ordering works correctly via healthchecks.
Changes:
- Adds healthchecks and aligns
postgres/elasticsearchprofiles sobackend/openvsxstacks validate and can be selected as documented. - Fixes the Elasticsearch healthcheck host to use
localhost(so it can actually pass). - Updates development docs to reflect that profiles are required and that
backendbrings its dependencies.
File summaries
| File | Description |
|---|---|
| docker-compose.yml | Adds Postgres healthcheck, fixes Elasticsearch healthcheck, and updates profile/depends_on wiring for backend/openvsx. |
| doc/development.md | Updates Docker Compose instructions to match the actual profile behavior and dependency startup. |
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 1
- Review effort level: Lite
💡 Add a code-review agent skill or configure MCP servers for context-aware, tailored reviews. Learn more in the docs.
Adding postgres and elasticsearch to the `openvsx` and `backend` profiles made
those profiles claim services that are not theirs - postgres is not part of the
backend - and it only papered over one instance of a general problem. Selecting
a profile that holds a service but not that service's dependency is a hard
error, and four of the documented profiles were in that state:
--profile frontend service "webui" depends on undefined service "server"
--profile commandline service "cli" depends on undefined service "server"
--profile kibana service "kibana" depends on undefined service "elasticsearch"
--profile openvsx service "server" depends on undefined service "postgres"
`required: false` says the same thing without the ownership: each service
declares what it needs, and the profiles selected decide what is actually
present. Every profile now resolves to exactly the services it names, and
postgres and elasticsearch stay in `db`/`es`/`debug` where they belong.
Verified that this keeps the health gating rather than trading it away, which
was the reason for the conditions in the first place: with
`--profile openvsx --profile debug`, both dependencies are waited on and the
server container is created only afterwards (dependencies 20:45:32, server
20:45:47). An isolated compose project confirms the same for a dependency that
turns healthy on a delay - it is waited for whenever it is enabled, and skipped
silently when it is not.
The cost is that `--profile openvsx` on its own now starts a server with no
database instead of refusing to start at all, so the documentation says to
select the infrastructure too.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
You are right, and it turned out the objection points at a better fix rather than just a tidier one. Reworked in Why the profile membership was wrongTwo reasons. The one you gave — postgres is not part of "the backend" — and a second I only found when I went looking: adding it to Carrying on down the membership route would have meant adding What it does now
Every profile now resolves to exactly the services it names: The thing I checked before trusting it
And on the real file with I also confirmed Compose does not resolve this by itself — a profiled dependency of a selected service is not auto-enabled, it is a validation failure, on v5.5.0 at least. So The trade
If you would rather The healthcheck fixes in the first commit are unchanged. |
…the profiles
Review feedback from Copilot, which was right and caught a check that would
have been as broken as the one it replaced. CMD-SHELL runs /bin/sh, and on
eclipse-temurin /bin/sh is dash:
$ docker run --rm --entrypoint sh eclipse-temurin:25-jdk -c 'ls -l /bin/sh'
/bin/sh -> dash
$ ... -c 'exec 3<>/dev/tcp/127.0.0.1/22'
sh: 1: cannot create /dev/tcp/127.0.0.1/22: Directory nonexistent
/dev/tcp is a bash feature. I had verified the command with `--entrypoint bash`
and not through the path the healthcheck actually takes, so I proved the wrong
thing. Now the exec form, invoking bash by name.
Re-verified through compose, since `docker run --health-cmd` takes a shell
string and so reproduces the dash bug rather than testing the fix: a container
serving {"status":"UP"} on 8081 reports healthy, and one serving nothing
reports unhealthy.
Also documents `minio`, `valkey` and `valkey-admin`, which had no entry in
development.md at all, along with the ports and credentials they come up on.
Every profile the compose file defines is now listed.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Also added the three profiles that had no entry in All eleven are now listed, with the ports and credentials each comes up on (MinIO console on 9001 with |
kibana:8.7.1 against elasticsearch:9.2.8 does not work at all - Kibana refuses
a cluster on a different major version:
[ERROR][elasticsearch-service] This version of Kibana (v8.7.1) is
incompatible with the following Elasticsearch nodes in your cluster:
v9.2.8 @ 172.19.0.2:9200
So the `kibana` profile has been non-functional since Elasticsearch moved to 9.
Both are now 9.2.8, and the comment says they move together.
While there: ELASTICSEARCH_URL has not been a Kibana setting since 7.0, where
`elasticsearch.url` was replaced by `elasticsearch.hosts`. The image carries no
such key at all, so that line was quietly doing nothing:
$ docker run --rm kibana:9.2.8 grep elasticsearch config/kibana.yml
elasticsearch.hosts: [ "http://elasticsearch:9200" ]
Renamed to ELASTICSEARCH_HOSTS. The image default happens to be the same URL,
so this had gone unnoticed - but relying on an image default matching our
service name is not something to leave to chance.
Kibana now also waits for the Elasticsearch healthcheck rather than merely for
its container, which is available since that check works again.
Verified: kibana 9.2.8 against elasticsearch 9.2.8 reports overall `available`
with `elasticsearch: available`, where 8.7.1 logs the incompatibility above.
Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
|
Good spot — it was worse than out of date, the Kibana refuses a cluster on a different major version. Running the old image against the current Elasticsearch: Both are 9.2.8 now, with a comment saying they move together. While in there I found a second thing wrong with that service: — so that line was quietly doing nothing. It is Kibana also waits on the Elasticsearch healthcheck now rather than just its container, which only became possible once that check worked again. Verified end to end: kibana 9.2.8 against elasticsearch 9.2.8 reports Worth noting these are the two versions that need to track each other by hand — nothing enforces it, so a future Elasticsearch bump has to bring Kibana along or the profile silently breaks again. |
|
Done in elasticsearch:
image: elasticsearch:${ELASTIC_VERSION}
kibana:
image: kibana:${ELASTIC_VERSION}Verified it is genuinely one source and not just two things that happen to resolve the same: and the default pair still comes up talking to each other — kibana 9.2.8 Two trade-offs worth knowing before you take it:
|
11d9d5e to
039b868
Compare
|
Dropped Both images are literal tags again: elasticsearch:
image: elasticsearch:9.2.8
kibana:
image: kibana:9.2.8Everything from the earlier commits is untouched — the version alignment itself, the I removed the commit rather than adding a revert on top, so the PR does not carry an add-then-undo pair. That needed a force push, done with |
There was a problem hiding this comment.
🟡 Changes recommended
The updated docs include a relative link that points to a non-existent doc/docker-compose.yml path and should be corrected to reference the root compose file.
Once you've addressed the issues Copilot identified, you can request another Copilot review.
Review details
- Files reviewed: 2/2 changed files
- Comments generated: 1
- Review effort level: Lite
Review feedback. `[docker-compose.yml](docker-compose.yml)` is relative to doc/, so it resolved to doc/docker-compose.yml, which does not exist. The other mention of the same file, a few lines up, was broken differently: `[docker-compose.yml]` is a shortcut reference with no definition anywhere in the document, so it renders as literal brackets rather than a link. Both predate this pull request, but this is the document it has been editing and they point at the file it is about. Audited the rest of the file's relative links while there; these two were the only broken ones. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
Picks up the three findings still standing from #1258, which reported them in June 2025 against a very different version of this file.
The documented command does not work
doc/development.mdoffers this verbatim as the way to start a dev stack:serveris inopenvsx/backend;postgresis indb/debug. The project fails to validate before a single container is created, so anyone following our own instructions hits this on their first command.postgresandelasticsearchnow also belong to the profiles that select the service depending on them.Two healthchecks could never have passed
Which is presumably why nobody noticed the profiles were broken — nothing downstream ever waited on health.
elasticsearch curled
http://elasticsearch01:9200. There is no such host here; the service iselasticsearch. From inside the running container, while the cluster isstatus: green:So it stayed
startingfor the full 50 retries and then reported unhealthy, with a perfectly good cluster behind it.server curled
localhost:8081/actuator/health, andeclipse-temurin:25-jdkhas no curl:bashis present, and its/dev/tcpcan ask the actuator the same question with nothing to install:Single-quoted deliberately: in a double-quoted YAML scalar those
\r\nbecome real control characters before bash sees them, which happens to work but only by accident of double interpretation.The alternative was
apt-get install curlon every container start, which is what #1258 proposed — reasonable when the base image wasopenjdk:17, but a network round trip on eachupand no longer necessary.Which lets
depends_ondo its jobWith both checks working,
depends_oncan wait on readiness instead of only on container creation. That is the ordering problem #1258 originally reported: the server no longer races a Postgres still initialising or an Elasticsearch that has not opened its port.postgresgained apg_isreadycheck so it can be waited on at all.What I did not take from #1258
Worth recording so the PR can be closed with a clear conscience. Two of its changes have since landed independently — the
ES_JAVA_OPTSmemory settings and thememlockulimits are both in main already. The rest is overtaken or not worth it: theopenjdk:17-bullseyeswitch (main is on temurin 25),SPRING_PROFILES_ACTIVE/ELASTICSEARCH_HOST/POSTGRES_HOSTenv vars (the repo usesgenerate-properties.sh --docker),/etc/localtimemounts on every service (cosmetic, and breaks on Docker Desktop hosts),"0.0.0.0:8080:8080"(identical to8080:8080), removing thecliservice, anddocs/docker-deployment-fix.md, which is in Chinese and mostly describes the above.Docs
backendnow brings its dependencies, so its description says so. I also dropped the "Without profiles:docker compose up" line — every service in the file has a profile, so that command starts nothing:Verified
postgreshealthy in ~12s,elasticsearchin ~36s, where elasticsearch previously never reached itup servercreates the server container only once both report healthy — dependencies started 20:15:45, server 20:16:01/dev/tcpcheck exits 0 against a live endpoint and non-zero against a closed port, tested insideeclipse-temurin:25-jdkitselfWhat I did not run is a full
--profile openvsx upthrough to a healthy server, since that builds the server with Gradle inside the container. The healthcheck command is verified against a real HTTP endpoint in the same image, but the first person to run the whole stack should confirm the server actually flips to healthy.Closes #1258 — credit to @hbyecoding for the report.