feat(infra): add dev.sh wrapper for the local-dev compose stack (#68)
## Summary Two recurring frictions on the local-dev stack: 1. **Compose-profile asymmetry** — `docker compose down` only operates on services whose profile is currently active. Anything brought up with `--profile X` keeps running unless the same flag is passed on `down`. pgweb and Jaeger silently survived several `down -v` invocations before we noticed (#67 documented the gotcha; this PR makes it impossible to hit if you use the wrapper). 2. **Verbose invocations** — typing `docker compose -f infra/local/dev.compose.yml --profile … <verb>` for routine ops gets old fast. Add [`infra/local/dev.sh`](infra/local/dev.sh) as a thin wrapper. Always passes every profile in scope on teardown / status / log commands, exposes ergonomic verbs: | Command | Effect | | --------------------------------------------- | --------------------------------------------------------------- | | `./infra/local/dev.sh up` | Core only (postgres + redis + otel-collector) | | `./infra/local/dev.sh up all` | Core + every profile | | `./infra/local/dev.sh up dbtools` | Core + pgweb | | `./infra/local/dev.sh up observability` | Core + Jaeger | | `./infra/local/dev.sh down [-v]` | Tear down (every profile in scope, no orphaned services) | | `./infra/local/dev.sh stop <service>` | Stop one service (containers stay around) | | `./infra/local/dev.sh restart <service>` | Restart one service | | `./infra/local/dev.sh status` | `ps` with every profile visible | | `./infra/local/dev.sh logs [service]` | Follow logs | | `./infra/local/dev.sh exec <service> <cmd>` | Run a command inside a container | Anything not matching one of the named verbs is passed through to `docker compose -f dev.compose.yml ...` (with every profile flagged in), so the full Compose surface remains available. ## Doc updates - **`infra/README.md`** — new "Convenience script" subsection with the cheat-sheet table; "First-time setup" rewritten to use the script; the standalone "Profile symmetry" tip from #67 is collapsed into a one-liner since the script now handles it (the note remains as a fallback for direct `docker compose` users). - **`docs/development.md` §3** — points at the script for the typical setup flow. The compose file itself is unchanged. ## Test plan - [ ] `./infra/local/dev.sh help` prints the usage block. - [ ] `./infra/local/dev.sh up` brings up the 3 core services (no pgweb / no jaeger). - [ ] `./infra/local/dev.sh up all` adds pgweb and Jaeger. - [ ] `./infra/local/dev.sh down -v` stops and removes all 5 containers (incl. pgweb and Jaeger), wipes the postgres-data and redis-data volumes. - [ ] `./infra/local/dev.sh stop pgweb` stops just pgweb. - [ ] `./infra/local/dev.sh logs otel-collector` follows that service's logs. - [ ] `./infra/local/dev.sh exec postgres psql -U "$POSTGRES_USER" -d "$POSTGRES_DB" -c "\du"` lists the audit roles. - [ ] `./infra/local/dev.sh stop` (no arg) errors with a clear message. --------- Co-authored-by: Julien Gautier <julien.gautier@apf.asso.fr> Reviewed-on: #68
This commit was merged in pull request #68.
This commit is contained in:
+35
-20
@@ -127,6 +127,7 @@ A Docker Compose recipe spinning up the runtime services the BFF and ADRs assume
|
||||
|
||||
| File | Role |
|
||||
| -------------------------------------------------------------------- | ---------------------------------------------------------------------------------------------------- |
|
||||
| [`local/dev.sh`](local/dev.sh) | Convenience wrapper around `docker compose` — see "Convenience script" below |
|
||||
| [`local/dev.compose.yml`](local/dev.compose.yml) | Service definitions: postgres, redis, otel-collector, plus pgweb and jaeger behind profiles |
|
||||
| [`local/.env.example`](local/.env.example) | Credentials + ports template (copy to `.env`, which is git-ignored) |
|
||||
| [`local/init/postgres/01-init.sql`](local/init/postgres/01-init.sql) | Bootstrap SQL for ADR-0013: audit roles + schema, applied on first boot only |
|
||||
@@ -135,27 +136,51 @@ A Docker Compose recipe spinning up the runtime services the BFF and ADRs assume
|
||||
### First-time setup
|
||||
|
||||
```bash
|
||||
cd infra/local
|
||||
|
||||
# 1. Configure local secrets (copy template, edit, do not commit).
|
||||
cp .env.example .env
|
||||
$EDITOR .env
|
||||
cp infra/local/.env.example infra/local/.env
|
||||
$EDITOR infra/local/.env
|
||||
# Set strong dev values for POSTGRES_PASSWORD and REDIS_PASSWORD
|
||||
# (defaults in the template are placeholders that the compose
|
||||
# rejects with `must be set in infra/local/.env` if left as-is).
|
||||
|
||||
# 2. Bring up the core stack (postgres + redis + otel-collector).
|
||||
docker compose -f dev.compose.yml up -d
|
||||
./infra/local/dev.sh up
|
||||
|
||||
# 3. (Optional) Activate viewers when needed:
|
||||
docker compose -f dev.compose.yml --profile dbtools up -d # pgweb
|
||||
docker compose -f dev.compose.yml --profile observability up -d # Jaeger UI
|
||||
docker compose -f dev.compose.yml --profile dbtools --profile observability up -d # both
|
||||
./infra/local/dev.sh up dbtools # adds pgweb
|
||||
./infra/local/dev.sh up observability # adds Jaeger UI
|
||||
./infra/local/dev.sh up all # core + every profile
|
||||
|
||||
# 4. Verify health.
|
||||
docker compose -f dev.compose.yml ps
|
||||
./infra/local/dev.sh status
|
||||
```
|
||||
|
||||
### Convenience script — `dev.sh`
|
||||
|
||||
[`local/dev.sh`](local/dev.sh) is a thin wrapper around `docker compose -f dev.compose.yml ...` with two reasons to exist:
|
||||
|
||||
1. **Hides the Compose-profile gotcha.** `docker compose down` only operates on services whose profile is currently active — anything started under `--profile X` keeps running unless the same flag is on `down`. The script always passes every profile in scope on teardown / status / log commands, so profile-gated services (pgweb, Jaeger) are never accidentally orphaned.
|
||||
2. **Ergonomic verbs** for the common workflows. `./dev.sh up all`, `./dev.sh stop pgweb`, `./dev.sh logs otel-collector`, etc.
|
||||
|
||||
Run `./infra/local/dev.sh help` for the full reference. Cheat-sheet:
|
||||
|
||||
| Command | Effect |
|
||||
| ------------------------------------------------------------------------------- | ------------------------------------------------------------ |
|
||||
| `./infra/local/dev.sh up` | Core only (postgres + redis + otel-collector) |
|
||||
| `./infra/local/dev.sh up all` | Core + every profile |
|
||||
| `./infra/local/dev.sh up dbtools` | Core + pgweb |
|
||||
| `./infra/local/dev.sh up observability` | Core + Jaeger |
|
||||
| `./infra/local/dev.sh down` | Tear down the whole stack (every profile in scope) |
|
||||
| `./infra/local/dev.sh down -v` | Tear down + wipe named volumes (incl. audit-roles bootstrap) |
|
||||
| `./infra/local/dev.sh stop pgweb` | Stop one service (containers stay around) |
|
||||
| `./infra/local/dev.sh status` | `docker compose ps`, with every profile visible |
|
||||
| `./infra/local/dev.sh logs otel-collector` | Follow logs |
|
||||
| `./infra/local/dev.sh exec postgres psql -U "$POSTGRES_USER" -d "$POSTGRES_DB"` | Run a command inside a service |
|
||||
|
||||
Anything not matching one of the named verbs is passed through to `docker compose -f dev.compose.yml ...` (with every profile flagged in), so you keep the full Compose surface available — `./dev.sh config`, `./dev.sh top`, `./dev.sh inspect …`, etc.
|
||||
|
||||
If you prefer to call `docker compose` directly, every example below shows the raw command alongside the script form.
|
||||
|
||||
### Service endpoints (defaults)
|
||||
|
||||
| Service | Host port | Purpose |
|
||||
@@ -172,17 +197,7 @@ All ports are overridable via `.env` if the host machine has conflicts.
|
||||
### Operational tips
|
||||
|
||||
- **Persistence** — state lives in named Docker volumes (`apf-portal-postgres-data`, `apf-portal-redis-data`). Survives `docker compose down`. Use `docker compose -f dev.compose.yml down -v` to wipe (also wipes the audit-roles bootstrap, which re-runs on the next fresh boot).
|
||||
- **Profiles must match on `down` as on `up`** — `docker compose down` only acts on services whose profile is currently active. If you brought the stack up with `--profile dbtools --profile observability`, those same flags are required on `down` to also stop pgweb and Jaeger; otherwise they keep running until the next reboot. Two pragmatic patterns:
|
||||
|
||||
```bash
|
||||
# Either pass the same flags on each command:
|
||||
docker compose -f dev.compose.yml --profile dbtools --profile observability down -v
|
||||
|
||||
# Or set COMPOSE_PROFILES once (e.g. in your shell or in infra/local/.env)
|
||||
# so every `up` / `down` / `ps` sees the right scope:
|
||||
export COMPOSE_PROFILES=dbtools,observability
|
||||
docker compose -f dev.compose.yml down -v
|
||||
```
|
||||
- **Profile symmetry** — `dev.sh down` (and `status`, `logs`, …) always include every profile in scope, so profile-gated services are caught. If you bypass the script and call `docker compose down` directly, you must pass the same `--profile` flags as on `up`, otherwise pgweb and Jaeger keep running silently. Either pass them again, or `export COMPOSE_PROFILES=dbtools,observability` in your shell or `infra/local/.env`.
|
||||
|
||||
- **Bootstrap re-run** — the SQL in `local/init/postgres/` only runs on a **fresh** Postgres data volume. To replay after editing the file, `down -v` (loses all dev data) or run the SQL manually with `docker compose exec postgres psql -U portal -d portal_dev -f /docker-entrypoint-initdb.d/01-init.sql`.
|
||||
- **Logs** — `docker compose -f dev.compose.yml logs -f <service>` to follow a single service. `otel-collector` is the loudest — its `debug` exporter prints every span / metric / log it receives.
|
||||
|
||||
Reference in New Issue
Block a user