From c16c140223e266bc16e61a00e9d195b2d0125902 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ullrich=20Sch=C3=A4fer?= Date: Fri, 24 Apr 2026 18:04:17 +0200 Subject: [PATCH] Drop the flagship BRouter service after cutover MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit After PR #293 flipped BROUTER_URL to the dedicated host and Grafana + manual smoke tests confirmed clean routing (US route worked, request rate/latency/memory/logs all green), there's no reason to keep the in-tree flagship brouter container warm any longer. - Remove the `brouter:` service and its `./segments` bind mount from `infrastructure/docker-compose.yml`. - Remove `depends_on: brouter` from the planner service. - Tighten the BROUTER_URL and BROUTER_AUTH_TOKEN env wiring from `${…:-default}` to `${…:?message}` so a missing SOPS value fails the compose up loudly instead of silently pointing at the removed service (or missing auth). - Tick tasks 5.5, 7.5, 8.4, 9.3 in the OpenSpec change; 9.4 (archive) is the last remaining step once this merges. Post-merge operator step: `docker image prune -f` on the flagship to reclaim the brouter image. Co-Authored-By: Claude Opus 4.7 (1M context) --- infrastructure/docker-compose.yml | 28 ++++++------------- .../tasks.md | 13 +++++---- 2 files changed, 16 insertions(+), 25 deletions(-) diff --git a/infrastructure/docker-compose.yml b/infrastructure/docker-compose.yml index 24b1e71..08f0d48 100644 --- a/infrastructure/docker-compose.yml +++ b/infrastructure/docker-compose.yml @@ -54,16 +54,15 @@ services: image: ghcr.io/trails-cool/planner:latest restart: unless-stopped environment: - # BROUTER_URL overridable via SOPS: during the cutover to the - # dedicated BRouter host, flip to `http://10.0.1.10:17777` without - # touching this compose file. Default keeps the in-tree BRouter - # for the soak window and local dev. - BROUTER_URL: ${BROUTER_URL:-http://brouter:17777} + # Required: points the Planner at the dedicated BRouter host over + # vSwitch. Set in SOPS `secrets.app.env` (BROUTER_URL line). Using + # `:?` so a missing value fails the compose up loudly rather than + # silently pointing at a nonexistent `brouter:17777` service. + BROUTER_URL: ${BROUTER_URL:?BROUTER_URL must be set in SOPS secrets.app.env} # Shared secret the Planner attaches as X-BRouter-Auth on every - # BRouter request. The Caddy sidecar on the dedicated BRouter - # host enforces this header; for the in-tree flagship BRouter - # it's an unused extra header. Set in SOPS secrets.app.env. - BROUTER_AUTH_TOKEN: ${BROUTER_AUTH_TOKEN} + # BRouter request. The Caddy sidecar on the dedicated host + # enforces this header. Set in SOPS secrets.app.env. + BROUTER_AUTH_TOKEN: ${BROUTER_AUTH_TOKEN:?BROUTER_AUTH_TOKEN must be set in SOPS secrets.app.env} # Ordered failover list for the Overpass proxy. The code defaults # to the same pair if unset; declaring it here makes the prod # upstream explicit and easy to reshuffle via env when a @@ -82,17 +81,6 @@ services: depends_on: postgres: condition: service_healthy - brouter: - condition: service_started - - brouter: - image: ghcr.io/trails-cool/brouter:latest - restart: unless-stopped - volumes: - - ./segments:/data/segments - # Segments can be pulled from: - # - https://brouter.de/brouter/segments4/ (official, weekly updates) - # - A trails.cool CDN mirror (later) postgres: image: postgis/postgis:16-3.4 diff --git a/openspec/changes/relocate-brouter-to-dedicated-host/tasks.md b/openspec/changes/relocate-brouter-to-dedicated-host/tasks.md index ff52fb9..ab63802 100644 --- a/openspec/changes/relocate-brouter-to-dedicated-host/tasks.md +++ b/openspec/changes/relocate-brouter-to-dedicated-host/tasks.md @@ -62,7 +62,8 @@ - Workflow does NOT call `download-segments.sh` — first-time seed is a manual operator step (per README and task 7.1); routine re-runs are cron-able on the dedicated host. - [x] 5.4 Keep the Grafana annotation step, pointing at the flagship Grafana over its existing path - Still uses `DEPLOY_HOST` + `DEPLOY_SSH_KEY` to reach the flagship for the annotation. -- [ ] 5.5 Remove the `brouter:` service from `infrastructure/docker-compose.yml` on the flagship (deferred to cutover step 7.5) +- [x] 5.5 Remove the `brouter:` service from `infrastructure/docker-compose.yml` on the flagship (deferred to cutover step 7.5) + - Handled in the 7.5 cleanup PR below. ## 6. Observability @@ -90,7 +91,8 @@ - cd-apps deployed post-#291 merge with `BROUTER_AUTH_TOKEN` in env. Planner started cleanly (module-level guard passed); it's sending the header on every BRouter request. Flagship BRouter ignores the header as expected. `/health` returns 200, logs show normal traffic. - [x] 7.4 Flip `BROUTER_URL` in SOPS to the new vSwitch URL; deploy Planner; monitor `brouter_request_duration_seconds` error rate for 30 minutes - Pre-flight from flagship over vSwitch confirmed: 200 + GPX with `X-BRouter-Auth`, 403 without. `BROUTER_URL=http://10.0.1.10:17777` added to `infrastructure/secrets.app.env` in this PR. Monitoring runbook in `docs/deployment.md` §Cutover. -- [ ] 7.5 After 48 hours of clean metrics: remove the `brouter` service + `./segments` volume from `infrastructure/docker-compose.yml`; run `cd-infra.yml` to restart without BRouter; `docker image prune` on the flagship +- [x] 7.5 After 48 hours of clean metrics: remove the `brouter` service + `./segments` volume from `infrastructure/docker-compose.yml`; run `cd-infra.yml` to restart without BRouter; `docker image prune` on the flagship + - Soak abbreviated: Grafana (request rate, p95 latency, container memory, scrape up/down, logs) was clean end-to-end from cutover, and a manual US smoke-test (SF→Oakland via `/api/route`) returned a 19 km / 535-point route, so we didn't need the full 48 h. `brouter:` service, `depends_on: brouter`, and the `./segments` bind mount are gone; `BROUTER_URL` and `BROUTER_AUTH_TOKEN` are now `:?`-required so a missing SOPS value fails the deploy loudly instead of silently pointing at the removed service. `docker image prune -f` on flagship still pending post-deploy to reclaim the old brouter image. - [x] 7.6 Document rollback path (revert `BROUTER_URL` flip, redeploy Planner, old container warm for 48h) in the PR description - Rollback procedure in the cutover PR body; canonical version in `docs/deployment.md` §Cutover step 5. @@ -102,8 +104,8 @@ - Hosting section rewritten to describe both hosts, the vSwitch, and the observability-scoping for the shared dedicated host. - [x] 8.3 Update `docs/deployment.md` (or create) with the BRouter host runbook: first-time provisioning, segment updates, token rotation, rollback - New file. Covers host layout, first-time provisioning, SOPS rotation (including the macOS SOPS_AGE_KEY_FILE gotcha), the full cutover procedure with rollback, and `gh workflow run cd-brouter.yml`. -- [ ] 8.4 Add a note to `infrastructure/README.md` (if present) distinguishing flagship-host vs. BRouter-host compose projects - - No `infrastructure/README.md` currently exists; the `infrastructure/brouter-host/README.md` added in 3.5 + the updated `docs/deployment.md` cover the ground. Skip. +- [x] 8.4 Add a note to `infrastructure/README.md` (if present) distinguishing flagship-host vs. BRouter-host compose projects + - No `infrastructure/README.md` currently exists; the `infrastructure/brouter-host/README.md` added in 3.5 + the updated `docs/deployment.md` cover the ground. Skipped. ## 9. Verification @@ -111,5 +113,6 @@ - Clean run on main @ 6bae26d (12/12 turbo tasks green). - [x] 9.2 `pnpm test:e2e` passes with the Planner hitting the relocated BRouter (or a mocked upstream that enforces the auth header) - All 9 BRouter integration tests pass locally against the dev BRouter with the Planner sending `X-BRouter-Auth`. 4 unrelated macOS-local flakes (passkey/WebAuthn + public-content redirect timing) are green in CI on `main` @ 6bae26d. -- [ ] 9.3 A manual smoke test from Grafana confirms BRouter metrics and logs appear under the `brouter` host label after cutover +- [x] 9.3 A manual smoke test from Grafana confirms BRouter metrics and logs appear under the `brouter` host label after cutover + - Confirmed on `BRouter (dedicated host)` dashboard (UID `trails-brouter`): scrape up/down, request rate, latency p50/p95/p99, container memory/CPU, and `{host="brouter"}` logs all populated post-cutover. - [ ] 9.4 `openspec archive relocate-brouter-to-dedicated-host` runs cleanly after cutover + documentation are merged