ci(deploy): deploy the stack to Talos on merge to main (refs #175)
CI / k8s (pull_request) Successful in 5s
CI / lint (pull_request) Successful in 1m25s
CI / build (pull_request) Successful in 1m22s
CI / unit (pull_request) Successful in 1m24s
CI / frontend (pull_request) Successful in 1m45s
CI / mutation (pull_request) Successful in 3m1s
CI / verify-stack (pull_request) Successful in 6m22s
CI / k8s (pull_request) Successful in 5s
CI / lint (pull_request) Successful in 1m25s
CI / build (pull_request) Successful in 1m22s
CI / unit (pull_request) Successful in 1m24s
CI / frontend (pull_request) Successful in 1m45s
CI / mutation (pull_request) Successful in 3m1s
CI / verify-stack (pull_request) Successful in 6m22s
The chart has been deployable by hand since #25 and linted in CI since #168; this makes a merged PR actually ship it to the lab server's Talos VM. Neither the Kubernetes API nor the in-cluster registry is publicly reachable, so the job forwards 6443, 30500 and 30141 over the same SSH hop into the Fedora host that the Gitea-runner pipeline uses. That splits the registry into two names for one store: images are pushed through the tunnel to localhost:30500, and the node pulls them from its own NodePort — the address its registry-mirror patch trusts over plain HTTP. It deploys with `make k8s-reseed` rather than `make k8s-up`: the bootstrap Jobs are idempotent, and deleting them first is what stops a changed Job template from wedging `helm upgrade`. The nine deployments are then rolled explicitly, because `dev` is a mutable tag and helm sees an unchanged pod template. PR CI is the merge gate, so this workflow does not re-run the checks. Deploys queue instead of cancelling: a `helm upgrade` killed half-way leaves the release in `pending-upgrade` and needs unwedging by hand. Co-Authored-By: Claude Opus 5 (1M context) <noreply@anthropic.com>
This commit is contained in:
@@ -360,6 +360,47 @@ immutable, so `helm upgrade` is rejected with `cannot patch "…" with kind Job`
|
||||
| Pods `Evicted` / `OOMKilled` | the VM is too small (§0) |
|
||||
| A Job shows `BackoffLimitExceeded` | read it: `kubectl -n big logs job/<name>` |
|
||||
|
||||
## 9. Deploying on merge to main
|
||||
|
||||
`.gitea/workflows/deploy.yaml` runs the §3–§4 steps against the **lab server's** Talos VM
|
||||
every time a PR is squash-merged to `main` (and on demand via *Run workflow*). PR CI is the
|
||||
merge gate, so the workflow deploys without re-running the checks.
|
||||
|
||||
The cluster's API and registry are not exposed publicly, so the job forwards them over the
|
||||
same SSH hop the Gitea-runner pipeline uses:
|
||||
|
||||
```
|
||||
ssh -p 6667 user@labs.respellion.tech -L 6443 -L 30500 -L 30141 → <TALOS_VM_IP>
|
||||
```
|
||||
|
||||
Consequences worth knowing:
|
||||
|
||||
- Images are **pushed** to `localhost:30500` (the tunnel) and **pulled** by the node from
|
||||
`<TALOS_VM_IP>:30500` (its own NodePort, the address in the Talos registry-mirror patch).
|
||||
Same registry, two names — hence the two `K8S_REGISTRY` values in the workflow.
|
||||
- It calls `make k8s-reseed`, not `make k8s-up`: the bootstrap Jobs are idempotent, and
|
||||
deleting them first is what stops a changed Job template from wedging `helm upgrade` (§7).
|
||||
- `dev` is a mutable tag, so a `rollout restart` of the nine repo deployments is what
|
||||
actually puts the new images in the pods.
|
||||
- Deploys **queue** (`cancel-in-progress: false`): a helm upgrade killed half-way leaves the
|
||||
release in `pending-upgrade`, which has to be unwedged by hand.
|
||||
|
||||
Settings, all on the repository in Gitea:
|
||||
|
||||
| Kind | Name | What |
|
||||
|---|---|---|
|
||||
| Secret | `TALOS_SSH_KEY` | private key for `user@labs.respellion.tech` (the Fedora host) |
|
||||
| Secret | `TALOS_KUBECONFIG` | base64 of the kubeconfig, **`server: https://127.0.0.1:6443`** — Talos puts `127.0.0.1` in the apiserver cert SANs, so TLS still verifies through the tunnel |
|
||||
| Variable | `TALOS_VM_IP` | the VM's libvirt address (default `192.168.122.173`) |
|
||||
| Variable | `TALOS_HOST` | the browser-facing host baked into Keycloak's issuer (default `localhost`, see §5) |
|
||||
|
||||
The last step smokes `GET /openbaar/register` through the openbaar portal, which exercises
|
||||
portal → Caddy → BFF → projection. An empty register passes; a 502 does not.
|
||||
|
||||
Not covered: the portals still need `make k8s-portals` (or an SSH forward) to be usable in a
|
||||
browser, because PKCE needs a secure context (§5). Giving the server a hostname + TLS is the
|
||||
upgrade path.
|
||||
|
||||
## What is not ported
|
||||
|
||||
- **Observability** (Tempo, Prometheus, Grafana) is defined but disabled — those are built
|
||||
|
||||
Reference in New Issue
Block a user