Consolidate Docker Compose into base + thin overrides - #140
Conversation
It previously lived only in the droplet's backend/.env, so prod's frame-worker tuning was invisible in git and could not be inherited by the compose overrides this consolidation introduces. Moving the non-secret value into the base makes it explicit; secrets stay in .env.
The laptop stack is moving onto start.sh (the prod entrypoint) but start.sh only knew how to swap in the staging nginx config; the general NGINX_PROFILE selection lived only in the legacy start-test.sh. Absorbing it here lets the laptop pick the cert-free nginx-local.conf and is the prerequisite for deleting start-test.sh. Staging is unchanged (NGINX_PROFILE defaults to RETINA_ENV). Paths are parameterised so the selection is unit-testable outside the container.
… base The old docker-compose.test.yml diverged from the deploy on three axes (legacy start-test.sh entrypoint, tar1090 UI, an 8s stress fleet) and docker-compose.local.yml existed only to paper over it. The laptop stack now layers a thin override directly on the production base, inheriting its fleet shape, resource limits and start.sh verbatim, so it is a faithful pre-deploy mirror. The justfile 'testmap' profile sourced the deleted file and its stress shape is dropped, so it is removed (prod covers the 40s shape). git records the old test.yml as deleted and the new one as added under the reused name.
Follow-up to 4b85e43, which removed the testmap fleet profile but left three user- and reader-facing strings still naming it: the success echo advertised `testmap (8s)` as a usable profile (the case statement now rejects it), and two comments described `testmap/prod` and the deleted docker-compose.test.yml as the extraction source. Reworded to name only the surviving local and prod profiles. Frontend-view mentions (testmap.localhost URL, .testmap-run dir, testmap.retina.fm hostname) are unrelated and left as-is.
start-test.sh's only remaining logic (nginx-profile selection) moved into start.sh, so the legacy entrypoint is dead. nginx-test.conf served the old tar1090 static HTML map that the React frontend replaced; it and the tar1090/html copy are the only place that UI was built, and nothing serves it now. deploy-test-network.sh drove a test-network droplet that no longer exists. The tar1090 JSON data format and its API routes are untouched.
Staging was a full standalone copy that drifted from production. It becomes a delta over docker-compose.yml, and the deploy-staging CI job layers the base first. The resolved config is unchanged (verified by diffing docker compose config before and after: the two are byte-for-byte identical), so the staging gate's behaviour is identical; only the duplication is gone. Beyond the base's data-volume, retina-edge-network and fleet .env attributes, the base also pins explicit `image:` names for rollback tooling that standalone staging never had. Reset those back to null on both staging services so staging keeps its former implicit auto-named images rather than sharing prod's tags. Also drops the two CI steps that cloned wiedehopf/tar1090 into tar1090/html: the Dockerfile no longer copies that directory (the tar1090 static UI was removed), so the clone fetched an external repo nothing consumes.
The test override's fleet service inherited the prod base's required backend/.env and its retina-prod-fleet container name, so `up` failed on a fresh clone without that file and the container name was misleading on a laptop. Make the env_file optional (mirroring the tower-finder override) and give it a distinct container name. Also correct the nginx-local.conf header, which still pointed at start-test.sh and docker-compose.local.yml; both were deleted earlier on this branch in favour of deploy/start.sh and docker-compose.test.yml.
Previously, a non-empty NGINX_PROFILE (or RETINA_ENV) whose nginx-<profile>.conf was missing silently fell through and left the baked-in default in place, which is the PRODUCTION nginx config. This happened for real when NGINX_PROFILE=test was set but nginx-test.conf had been deleted: the container looked like it was running the "test" profile while actually serving prod server_names, TLS and security headers. Missing a profile config is a misconfiguration, not a no-op, so we now exit 1 rather than mask it.
|
Claude finished @Babissimo's task in 6m 1s —— View job Code ReviewTasks
Overall this is a clean, well-documented consolidation. The base/override split checks out: One gap worth fixing:
Minor/non-blocking notes:
|
Follow-up tidy-up on the compose consolidation, addressing a high-effort review plus four naming/design questions. Naming and coupling (RETINA_ENV / NGINX_PROFILE): - Rename nginx-local.conf -> nginx-test.conf and drop NGINX_PROFILE=local from the test override. The laptop stack already runs RETINA_ENV=test, and start.sh's profile default (NGINX_PROFILE:-RETINA_ENV) now selects nginx-test.conf on its own, so the separate "local" name and the explicit override are both redundant. "test" is now used ubiquitously for this stack. - Keep NGINX_PROFILE as an overridable axis rather than hard-coupling it to RETINA_ENV: nginx can still be swapped without changing the app's auth environment. The unit test now covers the default mapping, the override, and a fail-closed unknown profile. - Defaulting to prod when both are unset is deliberate and fail-closed (strict backend auth + baked prod nginx.conf); no change needed there. Review findings: - Re-add RADAR_TCP_PORT=3012 to the test override so the ingest port matches the fleet's FLEET_PORT on a fresh clone with no backend/.env (the app default is already 3012; this is belt-and-braces). - Record the Compose >= 2.24 requirement for the staging override's !reset / !override merge tags (staging droplet runs 2.40, prod runs the base alone). - Reword the "not X, it is Y" comment and cross-reference the duplicated retina-edge neutralisation between the two overrides. - Trim the most verbose comments across the compose files and start.sh. FRAME_WORKERS=8 in the base matches prod's backend/.env, so the surfacing is faithful (verified on the droplet). Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Claude finished @Babissimo's task in 1m 55s —— View job Code Review — updated after latest pushTasks
The latest commit ( Previously flagged, still open:
Previously flagged, minor/non-blocking, unchanged:
Nothing new introduced by this round of changes looks problematic — the fixes for the four naming/design questions and the |
|
Follow-up commit (8ba88df) resolves the five review findings and folds in four naming/design refinements raised in review:
Coupling: by default, not hard-wired. Defaulting to prod is deliberate/fail-closed — unset Findings: re-added Verified: profile unit test passes; both merged configs render; staging resolved config byte-identical to HEAD (my staging edits are comment-only); fresh-clone render with no |
- Wire deploy/tests/test_nginx_profile.sh into the docker-build job so a regression in start.sh's profile selection (including the fail-closed branch) is caught in CI rather than only on a manual run. Placed before the image build for fast feedback. - Drop the "if Compose rejects an empty !override list" hedge next to `env_file: !override []` in the staging override: the empty override renders cleanly (verified via `docker compose config`), so the untested fallback note is no longer warranted. - Restore an explicit container_name (retina-test-server) on the test tower-finder service, matching retina-test-fleet and the staging server's naming; it was dropped in the consolidation and left the container auto-named. Co-Authored-By: Claude Opus 4.8 <noreply@anthropic.com>
|
Claude finished @Babissimo's task in 59s —— View job Code Review — updated after latest pushTasks
Commit
No new issues introduced by this commit — the diff is small (3 files, +6/-2) and each change is a direct, correctly-scoped fix for a previously-raised point. I don't have a way to execute This PR is in good shape — all substantive and minor review feedback across both prior rounds has been addressed. |
|
Thanks — addressed in 69357f1. CI gap (the main one): added a Staging hedge comment: dropped the "if Compose rejects an empty Test One note on the review's profile-selection trace: it predates the earlier follow-up commit (8ba88df), which renamed |
|
Force-pushed a rewritten branch (was Two substantive changes since the last review:
Also folded in (unchanged from the prior push, now in one commit): re-added |
What & why
Consolidates the repo's four standalone Docker Compose files into one production base plus thin per-environment overrides, leaving a single container entrypoint and a single UI. Motivation: the four files were near-complete copies that drifted, and the old
docker-compose.test.ymldiverged from the deploy on three axes at once (a legacystart-test.shentrypoint, the old tar1090 static HTML UI, and an 8s/x4 stress fleet), so the laptop stack was not a faithful mirror of production. The aim is a laptop stack that reproduces production's optimisation and configuration behaviour, which local Docker previously could not.Result
docker-compose.ymlstays the base (= production; a baredocker compose upis unchanged).docker-compose.staging.ymlanddocker-compose.test.ymlbecome thin overrides layered on it (-f docker-compose.yml -f <override>.yml), so they inherit the base and cannot drift.NGINX_PROFILEselection logic moved from the legacystart-test.shintostart.sh;start-test.shdeleted.nginx-test.conf,COPY tar1090/html) is removed. The tar1090 JSON data format and API routes (tar1090_data,tar1090_aircraft/tar1090_receiver, aircraft.json generation) are untouched.docker compose -f docker-compose.yml -f docker-compose.test.yml up -d --build: production, minus certs, on port 8080, withRETINA_ENV=testauth.Notable specifics
FRAME_WORKERS=8surfaced from the droplet'sbackend/.envinto the base so it is visible in git and inheritable (staging overrides to 6).docker compose configis byte-identical to the previous standalone file (verified before/after), so the staging->prod promotion gate behaviour is unchanged. The fivedeploy-stagingCI invocations are prefixed with the base; the production deploy job is untouched. Two orphaned tar1090 clone steps removed from CI.deploy/deploy-test-network.shretired (its test-network droplet no longer exists).FLEET_INTERVAL/FLEET_NODES.start.shnow fails closed ifNGINX_PROFILEnames a profile with no matchingnginx-<profile>.conf, instead of silently falling back to the baked production nginx config. Production itself runs with an empty profile and is unaffected.Tests
deploy/tests/test_nginx_profile.shcovers profile selection (staging/local/production) and the fail-closed case./api/radar/nodes, clean teardown.docker build .succeeds after the Dockerfile trims; all three compose files render.Follow-on (not in this PR)
justfileup-recipe revamp (this PR made only the minimal change forced by the file deletion: removing the deadtestmapprofile).🤖 Generated with Claude Code