docs: document the analysis page and the CI deploy flow
The RUNBOOK still said the workflow did not deploy to the cluster. It does now - it builds, pushes, applies the manifests, rolls the pods and verifies the app from inside the pod. The manual deploy path is documented alongside it, along with the dry-run step that catches the schema errors kubectl apply silently swallows.
This commit is contained in:
@@ -42,6 +42,7 @@ The tests use `mongomock`, so they need no database and no network.
|
||||
| `/brews` | The brew process: record a reading, review every run |
|
||||
| `/active` | What is in the fermenter right now — tap, gravity, projected strength |
|
||||
| `/history` | How every brew has gone, with charts and the standard-vs-legacy ABV comparison |
|
||||
| `/analysis` | How consistently the brews ferment — attenuation, fermentation curves, brew timings |
|
||||
|
||||
### `/active` — the active beers page
|
||||
|
||||
@@ -59,6 +60,27 @@ A run with only one reading and no recorded original gravity has no reliable
|
||||
estimate, so the alcohol figure shows a dash rather than a misleading number.
|
||||
Record the OG on the run (or take a second reading) and it appears.
|
||||
|
||||
### `/analysis` — how the brews ferment
|
||||
|
||||
The page that turns the history into something you can brew better from:
|
||||
|
||||
- **Attenuation by brew** — what fraction of the original gravity was
|
||||
fermented away, for every finished brew.
|
||||
- **Fermentation curves** — the typical shape of a fermentation, drawn as a
|
||||
median curve with the min–max envelope behind it. Plotting every brew
|
||||
individually gives sixteen near-identical lines and an unreadable legend.
|
||||
- **Every finished brew** — OG, FG, ABV, attenuation, days in the fermenter,
|
||||
days to reach 1.010, and the finish date.
|
||||
- **Readings that need a second look** — readings outside the plausible
|
||||
hydrometer range.
|
||||
- Headline figures: average attenuation and its spread, average brew time,
|
||||
average time to 1.010.
|
||||
|
||||
A reading that is physically impossible — a final gravity below the original
|
||||
gravity by more than the wort itself could have — is excluded from the
|
||||
averages rather than silently distorting them, and the run is listed on the
|
||||
page so it can be corrected.
|
||||
|
||||
### Run metadata
|
||||
|
||||
Some details cannot be derived from the readings, so they are stored per run in
|
||||
@@ -94,7 +116,6 @@ src/flask/
|
||||
views/ blueprints: auth, brews, analysis
|
||||
mongo/repository.py Mongo access for the beer_data and beer_runs collections
|
||||
templates/ Jinja templates
|
||||
static/ CSS, JS, fonts, logo (all served locally — no CDN)
|
||||
static/ CSS, JS, fonts, logo (all served locally - no CDN)
|
||||
tests/ pytest suite
|
||||
scripts/ operational scripts (the run-metadata backfill)
|
||||
|
||||
+41
-3
@@ -69,15 +69,53 @@ env:
|
||||
|
||||
## Deploying
|
||||
|
||||
Pushing to `master` triggers `.gitea/workflows/build_push.yml`, which runs the
|
||||
test suite and then builds and pushes the image. **The workflow does not
|
||||
currently deploy to the cluster** — apply the manifests yourself:
|
||||
Pushing to `master` triggers `.gitea/workflows/build_push.yml`, which builds
|
||||
the image, pushes it, **deploys it to the cluster and verifies it**. There is
|
||||
no manual step.
|
||||
|
||||
The workflow is a single job, in this order:
|
||||
|
||||
1. **Checkout**
|
||||
2. **Create Kubeconfig** — writes `secrets.KUBEC_CONFIG_BUILDX_NEW_2` to
|
||||
`$HOME/.kube/config`. This is FIRST because the buildx `kubernetes` driver
|
||||
needs it to create its builder pod in the cluster.
|
||||
3. **Set up Docker Buildx** — `driver: kubernetes`, `namespace=gitea-runner`.
|
||||
4. **Login to the registry** — `secrets.REG_PASSWORD`.
|
||||
5. **Build and Push** — `linux/amd64` only. A multi-arch build runs qemu,
|
||||
which crashes the buildkit pod on this NUC (exit 255, `SandboxChanged`)
|
||||
and the build then hangs for many minutes.
|
||||
6. **Deploy** — installs kubectl, applies `kube/*.yaml`, creates the
|
||||
image-pull secret idempotently, then `rollout restart` + `rollout status`.
|
||||
The rollout restart is required: the image tag in the manifest is
|
||||
`:latest`, so `kubectl apply` alone does not roll the pods.
|
||||
7. **Verify the deployed app** — exercises `/healthz` and `/readyz` from
|
||||
inside the pod, using the pod's own python (there is no `curl` in the
|
||||
slim image).
|
||||
|
||||
> The deploy step does **not** delete the namespace. That would destroy the
|
||||
> hand-provisioned `beer-db` and `beer-app` Secrets.
|
||||
|
||||
### Deploying by hand
|
||||
|
||||
If you need to deploy without going through CI — for example to test a
|
||||
manifest change — do the same thing the workflow does:
|
||||
|
||||
```bash
|
||||
kubectl apply -f kube/beer_namespace.yaml
|
||||
kubectl apply -f kube/beer-deployment.yaml
|
||||
kubectl apply -f kube/beer-service.yaml
|
||||
kubectl -n beer rollout restart deployment/beer-deployment
|
||||
kubectl -n beer rollout status deployment/beer-deployment --timeout=180s
|
||||
```
|
||||
|
||||
Validate the manifests before applying them. `kubectl apply` **silently
|
||||
rejects** a manifest with a schema error, so a broken manifest leaves the
|
||||
old Deployment in place while the job still reports success:
|
||||
|
||||
```bash
|
||||
kubectl apply --dry-run=client -f kube/
|
||||
```
|
||||
|
||||
### Verify the deploy actually took
|
||||
|
||||
CI green and pods `Ready` do **not** prove the new code is running. Check the
|
||||
|
||||
Reference in New Issue
Block a user