docs(deploy): add Flux/Talos deploy guide + sibling-repos PAT helper script
Validate Flux manifests / kustomize-build (pull_request) Failing after 26s
Validate Flux manifests / kustomize-build (pull_request) Failing after 26s
This commit is contained in:
@@ -0,0 +1,120 @@
|
|||||||
|
# Deploying the APIs (Flux GitOps → Talos)
|
||||||
|
|
||||||
|
> Handoff doc. The APIs are **not** deployed by Gitea Actions — they are deployed
|
||||||
|
> by **Flux** running on the Talos Kubernetes cluster. The Gitea Actions in this
|
||||||
|
> repo only build the docs-site image, validate Flux manifests, and publish
|
||||||
|
> OpenAPI specs to RapidAPI.
|
||||||
|
|
||||||
|
## How a deploy actually happens
|
||||||
|
|
||||||
|
```
|
||||||
|
API repo (e.g. leeworks-agents/zip-enrichment)
|
||||||
|
└─ its own CI builds & pushes registry.leeworks.dev/zip-enrichment/server:<tag>
|
||||||
|
└─ Flux image-automation (flux/image-automation/) rewrites the
|
||||||
|
{"$imagepolicy": "flux-system:<api>"} marker in flux/<api>/helmrelease.yaml
|
||||||
|
└─ Flux GitRepository "api-company" (polls main every 5m)
|
||||||
|
└─ HelmRelease per API (flux/<api>/helmrelease.yaml, bedag/raw chart)
|
||||||
|
└─ Deployment rolls out in the cluster namespace
|
||||||
|
```
|
||||||
|
|
||||||
|
Each API has its own directory under `flux/`:
|
||||||
|
|
||||||
|
| API | Namespace | HelmRelease path | Image |
|
||||||
|
|---|---|---|---|
|
||||||
|
| zip-enrichment | `zip-enrichment` | `flux/zip-enrichment/helmrelease.yaml` | `registry.leeworks.dev/zip-enrichment/server` |
|
||||||
|
| holidays | `holidays` | `flux/holidays/helmrelease.yaml` | `registry.leeworks.dev/holidays/server` |
|
||||||
|
| air-quality | `air-quality` | `flux/air-quality/helmrelease.yaml` | `registry.leeworks.dev/air-quality/server` |
|
||||||
|
| vin-decoder | `vin-decoder` | `flux/vin-decoder/helmrelease.yaml` | `registry.leeworks.dev/vin-decoder/server` |
|
||||||
|
|
||||||
|
(Confirm each path's exact image with `grep -r imagepolicy flux/`.)
|
||||||
|
|
||||||
|
## Prerequisite: the manifests must be live in the cluster's Flux source
|
||||||
|
|
||||||
|
`flux/api-company-source/gitrepository.yaml` is **reference only**. The
|
||||||
|
*authoritative* copy must be committed to **`0xWheatyz/Talos`** at:
|
||||||
|
|
||||||
|
```
|
||||||
|
testing1/first-cluster/cluster/flux/api-company/
|
||||||
|
```
|
||||||
|
|
||||||
|
If that path does not point Flux at this repo's `flux/` directory, Flux never
|
||||||
|
sees these HelmReleases and nothing deploys. Verify the Talos repo references
|
||||||
|
this repo's `main` branch and that a Flux `Kustomization` includes the
|
||||||
|
`api-company` path.
|
||||||
|
|
||||||
|
Per-API the cluster also needs (already templated under `flux/<api>/`):
|
||||||
|
- `namespace.yaml` — the target namespace
|
||||||
|
- the `gitea-registry` imagePullSecret in that namespace
|
||||||
|
- `externalsecret.yaml` — pulls API keys (e.g. RapidAPI) via external-secrets
|
||||||
|
- `servicemonitor.yaml` — Prometheus scraping (optional for deploy)
|
||||||
|
|
||||||
|
## One-time local setup (machine with cluster access)
|
||||||
|
|
||||||
|
You need tools that are **not** installed on the dev machine yet:
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Talos kubeconfig — export from the Talos controlplane, e.g.:
|
||||||
|
# talosctl kubeconfig ~/.kube/talos-leeworks
|
||||||
|
export KUBECONFIG=~/.kube/talos-leeworks
|
||||||
|
kubectl cluster-info # must succeed before continuing
|
||||||
|
|
||||||
|
# Flux CLI
|
||||||
|
brew install fluxcd/tap/flux
|
||||||
|
# Helm (optional, for debugging charts)
|
||||||
|
brew install helm
|
||||||
|
|
||||||
|
flux check # confirm Flux is installed & healthy in-cluster
|
||||||
|
```
|
||||||
|
|
||||||
|
## Deploy / sync all APIs
|
||||||
|
|
||||||
|
```bash
|
||||||
|
export KUBECONFIG=~/.kube/talos-leeworks
|
||||||
|
|
||||||
|
# 1. Pull the latest main into the cluster's Git source
|
||||||
|
flux reconcile source git api-company -n flux-system
|
||||||
|
|
||||||
|
# 2. Apply the manifests (name may differ — check: flux get kustomizations -A)
|
||||||
|
flux reconcile kustomization api-company -n flux-system
|
||||||
|
|
||||||
|
# 3. Reconcile each API's HelmRelease
|
||||||
|
flux reconcile helmrelease zip-enrichment -n zip-enrichment
|
||||||
|
flux reconcile helmrelease holidays -n holidays
|
||||||
|
flux reconcile helmrelease air-quality -n air-quality
|
||||||
|
flux reconcile helmrelease vin-decoder -n vin-decoder
|
||||||
|
|
||||||
|
# 4. Verify everything is Ready
|
||||||
|
flux get helmreleases -A
|
||||||
|
kubectl get pods -A | grep -E 'zip-enrichment|holidays|air-quality|vin-decoder'
|
||||||
|
```
|
||||||
|
|
||||||
|
## Troubleshooting
|
||||||
|
|
||||||
|
```bash
|
||||||
|
# Why is a release not Ready?
|
||||||
|
flux get helmrelease <name> -n <ns>
|
||||||
|
kubectl describe helmrelease <name> -n <ns>
|
||||||
|
|
||||||
|
# Is image automation picking up new tags?
|
||||||
|
flux get image policy -n flux-system
|
||||||
|
flux get image update -A
|
||||||
|
|
||||||
|
# Pod won't start (image pull / secret issues)
|
||||||
|
kubectl describe pod <pod> -n <ns>
|
||||||
|
kubectl get events -n <ns> --sort-by=.lastTimestamp | tail -20
|
||||||
|
```
|
||||||
|
|
||||||
|
## Force a fresh deploy of a single API
|
||||||
|
|
||||||
|
```bash
|
||||||
|
flux suspend helmrelease <name> -n <ns>
|
||||||
|
flux resume helmrelease <name> -n <ns> # triggers a fresh reconcile
|
||||||
|
# or restart the workload directly:
|
||||||
|
kubectl rollout restart deployment/<name> -n <ns>
|
||||||
|
```
|
||||||
|
|
||||||
|
## Related docs in this repo
|
||||||
|
- `docs/operator-runbook.md` — day-2 operations
|
||||||
|
- `docs/registry.md` — container registry (`registry.leeworks.dev`) setup
|
||||||
|
- `docs/secrets-checklist.md` — required cluster secrets
|
||||||
|
- `flux/image-automation/` — automatic image tag bumping
|
||||||
Executable
+55
@@ -0,0 +1,55 @@
|
|||||||
|
#!/usr/bin/env bash
|
||||||
|
# Create a Gitea PAT with read access to the sibling API repos and store it as
|
||||||
|
# the SIBLING_REPOS_TOKEN action secret on leeworks-agents/api-company.
|
||||||
|
#
|
||||||
|
# Why this script exists:
|
||||||
|
# - Gitea's build-docs workflow checks out sibling repos. The auto-injected
|
||||||
|
# GITEA_TOKEN is scoped to THIS repo only and cannot read them, and
|
||||||
|
# GITEA_TOKEN is a reserved secret name that cannot be overridden.
|
||||||
|
# - `tea` cannot CREATE a PAT (no such command), and Gitea's token-creation
|
||||||
|
# API requires BASIC AUTH (your password) — a token cannot mint a token.
|
||||||
|
# - `tea` CAN set the action secret using its existing login.
|
||||||
|
#
|
||||||
|
# So: this prompts for your password ONCE, mints the PAT via the API, and pipes
|
||||||
|
# it straight into `tea` as the secret. The PAT value is never written to disk.
|
||||||
|
#
|
||||||
|
# Usage: bash scripts/setup-sibling-repos-token.sh
|
||||||
|
set -euo pipefail
|
||||||
|
|
||||||
|
GITEA_URL="https://gitea.leeworks.dev"
|
||||||
|
GITEA_USER="0xWheatyz"
|
||||||
|
REPO="leeworks-agents/api-company"
|
||||||
|
SECRET_NAME="SIBLING_REPOS_TOKEN"
|
||||||
|
TOKEN_NAME="sibling-repos-readonly-$(date +%Y%m%d)"
|
||||||
|
|
||||||
|
command -v curl >/dev/null || { echo "curl required"; exit 1; }
|
||||||
|
command -v tea >/dev/null || { echo "tea required"; exit 1; }
|
||||||
|
command -v python3 >/dev/null || { echo "python3 required"; exit 1; }
|
||||||
|
|
||||||
|
echo "Gitea user: $GITEA_USER ($GITEA_URL)"
|
||||||
|
read -r -s -p "Gitea password (for $GITEA_USER): " GITEA_PASS
|
||||||
|
echo
|
||||||
|
|
||||||
|
# Create a read-only PAT. scope read:repository lets the build-docs workflow
|
||||||
|
# clone the sibling repos. Adjust scopes here if your Gitea version differs.
|
||||||
|
resp="$(curl -fsS -X POST \
|
||||||
|
-u "${GITEA_USER}:${GITEA_PASS}" \
|
||||||
|
-H 'Content-Type: application/json' \
|
||||||
|
-d "{\"name\":\"${TOKEN_NAME}\",\"scopes\":[\"read:repository\"]}" \
|
||||||
|
"${GITEA_URL}/api/v1/users/${GITEA_USER}/tokens")" || {
|
||||||
|
echo "Token creation failed. Check password / 2FA (2FA blocks basic-auth token creation)." >&2
|
||||||
|
exit 1
|
||||||
|
}
|
||||||
|
unset GITEA_PASS
|
||||||
|
|
||||||
|
PAT="$(printf '%s' "$resp" | python3 -c 'import sys,json; print(json.load(sys.stdin)["sha1"])')"
|
||||||
|
[ -n "$PAT" ] || { echo "Could not parse token from response: $resp" >&2; exit 1; }
|
||||||
|
echo "PAT '${TOKEN_NAME}' created."
|
||||||
|
|
||||||
|
# Store it as the action secret via tea (overwrites if it already exists).
|
||||||
|
printf '%s' "$PAT" | tea actions secrets create "$SECRET_NAME" --repo "$REPO" --stdin
|
||||||
|
unset PAT
|
||||||
|
|
||||||
|
echo "Secret '${SECRET_NAME}' set on ${REPO}."
|
||||||
|
echo "Verify: tea actions secrets list --repo ${REPO}"
|
||||||
|
echo "Then re-run build-docs: tea actions runs ... (or push to main / workflow_dispatch)"
|
||||||
Reference in New Issue
Block a user