Reproducible path from a clean workstation to a demo-ready kind-kaddy-dev
cluster. Follow top to bottom. Every command uses the isolated kubeconfig at
.state/kubeconfig — never merge into an ambient shared kubeconfig.
Deeper substrate notes: local-substrate-handoff.md. Website claims: website-self-service.md.
| Artifact | Status |
|---|---|
Slidev deck (task deck:build) |
Available locally / CI deck workflow — deck Pages URL unavailable / not yet published |
Scorecard GitHub Pages (https://platformrelay.github.io/Kaddy/) |
Live — HTTP 200 (fixture scorecard HTML via scorecard-pages workflow) |
| GSK showcase stills | slides/public/surfaces/ — Argo CD, Backstage, Grafana, Upbound Marketplace (also linked from the root README Live demo) |
This guide + task demo* |
Available after the bring-up below |
| Tool | Notes |
|---|---|
| Task | task --version |
kind, kubectl, helm |
kind node image pinned in hack/cluster/kind/cluster.yaml |
| Container runtime | Docker Desktop, Colima, or Podman — required for task cluster:up |
yq, curl, jq |
smoke / demo helpers |
Optional: argocd CLI |
break-glass password + app sync |
No cloud credentials are required for phase 1.
cd /path/to/Kaddy
task cluster:up
export KUBECONFIG="$PWD/.state/kubeconfig"
kubectl config use-context kind-kaddy-dev
kubectl get nodestask cluster:up is idempotent. It creates only the kaddy-dev kind cluster
and the kind-kaddy-dev context in .state/kubeconfig. It never writes the
ambient shared kubeconfig.
If the kind API port drifted after a runtime restart:
kind export kubeconfig --name kaddy-dev --kubeconfig "$PWD/.state/kubeconfig"Readiness (substrate):
task test:smoke:e1eRun in this order. Each bootstrap task refuses non-kind-kaddy-dev contexts.
export KUBECONFIG="$PWD/.state/kubeconfig"
# E1 — Argo CD + Gateway NodePort 30443 (kind loopback mapping)
task bootstrap:argocd
# E1c — random Grafana admin Secret (before observability sync needs it)
task bootstrap:e1c
# E3 — app-of-apps (children sync from main)
task bootstrap:e3
# E6 — Crossplane + Website XRD / demo claim registration
task bootstrap:e6
# E7 — Argo Rollouts + mulligan workloads
task bootstrap:e7Optional identity (Dex + KSOPS) when you have an age key and GitHub OAuth app:
task bootstrap:e1d # needs SOPS_AGE_KEY_FILE / ~/.config/sops/age/keys.txtWait until Applications are Synced/Healthy, then prove the Website claim:
kubectl -n argocd get applications
# expect Synced / Healthy for root, platform-core, observability, workloads, …
kubectl -n websites get website putting-green
task test:smoke:e4 # clubhouse HTTPS through the real Cilium Gateway
task test:smoke:e6 # Website claim → composed workload + TLS route + ServiceMonitorRerunning this Getting Started path is idempotent — bootstrap tasks and
task cluster:up reconcile drift without requiring teardown first.
Honest local access only. Do not curl Cilium LB-IPAM addresses from macOS
(they are not host-routable). Do not kubectl port-forward selectorless
cilium-gateway-* Services — they have no pods to attach to. Use the kind
NodePort mappings, explicit backend port-forwards, or in-cluster smoke tasks.
| Surface | Purpose | Canonical URL / CLI | Local access / verify | Auth source | Path |
|---|---|---|---|---|---|
| Argo CD | GitOps UI + Applications | https://127.0.0.1:30443/applications |
kind NodePort 30443 (Gateway + HTTPRoute); accept local CA once |
argocd admin initial-password -n argocd (Secret; do not commit) or Dex when E1d is wired |
Cilium Gateway |
| clubhouse | Sample site (brief tenant) | https://clubhouse.kaddy.local/ |
Verify via task test:smoke:e4 (real TLS edge, in-cluster). Direct-backend preview (bypasses Gateway): kubectl -n gateway port-forward deploy/clubhouse 8080:8080 → http://127.0.0.1:8080/ — label this preview not the edge |
n/a (public lab content) | Gateway (canonical) / port-forward (preview) |
| Website demo | Composed claim putting-green |
https://clubhouse.kaddy.local/putting-green/ |
task test:smoke:e6 |
n/a | Gateway |
| Grafana | Dashboards + alert visibility | http://127.0.0.1:23000/ |
kubectl -n monitoring port-forward svc/kube-prometheus-stack-grafana "${E5_GRAFANA_PORT:-23000}:80" |
Secret monitoring/grafana-admin (admin-user / admin-password) — derive with kubectl … jsonpath, never print into git |
port-forward |
| Prometheus | PromQL / targets | http://127.0.0.1:29090/ |
kubectl -n monitoring port-forward svc/kps-prometheus "${E5_PROM_PORT:-29090}:9090" |
none (local PF) | port-forward |
| Alertmanager | Firing / resolved alerts | http://127.0.0.1:29093/ |
kubectl -n monitoring port-forward svc/kps-alertmanager "${E5_AM_PORT:-29093}:9093" |
none (local PF) | port-forward |
| mulligan | Progressive delivery | CLI + HTTPRoute weights | task demo (canary weights); abort/rollback is Act 4 in Demo; observe kubectl -n mulligan get httproute,rollout |
n/a | Gateway plugin + CLI |
Crossplane is API-only (kubectl get xrd,composition,website -A) — there is
no browser URL.
Credential helpers (print locally if needed; never commit output):
# Grafana
kubectl -n monitoring get secret grafana-admin \
-o jsonpath='{.data.admin-user}' | base64 -d; echo
kubectl -n monitoring get secret grafana-admin \
-o jsonpath='{.data.admin-password}' | base64 -d; echo
# Argo CD break-glass (when Dex is not yet used)
argocd admin initial-password -n argocdRecord a healthy baseline, then run the acts in order. Each act lists what to show, expected duration, success signal, and a shorter fallback.
export KUBECONFIG="$PWD/.state/kubeconfig"
kubectl -n argocd get applications
kubectl -n websites get website putting-green
kubectl -n gateway get deploy/clubhouseSuccess: Applications Synced/Healthy; Website Ready; clubhouse replicas ≥ 1. Duration: ~30s. Fallback: re-run the bootstrap block above.
Show: Website → composed Deployment/Service/HTTPRoute/ServiceMonitor; path
served at https://clubhouse.kaddy.local/putting-green/.
task test:smoke:e6
kubectl -n websites describe website putting-greenDuration: ~1–2 minutes. Success: smoke exits 0; composed resources Ready.
Fallback: kubectl -n websites get website,deploy,httproute,servicemonitor and
see website-self-service.md.
Show: serve → scrape → ClubhouseDown firing in Alertmanager → restore → resolve.
# optional: keep AM visible
kubectl -n monitoring port-forward svc/kps-alertmanager "${E5_AM_PORT:-29093}:9093" &
task demo:fireDuration: ~3–6 minutes (for: 1m + scrape/eval). Success: script prints firing
then resolved; Alertmanager briefly shows ClubhouseDown.
Fallback: task test:smoke:e5 (bundle) or inspect PrometheusRule
marshal.http only.
Show: blue/green promotion + live canary HTTPRoute weight shifts.
task demo
kubectl -n mulligan get httproute mulligan -o yaml | yq '.spec.rules[0].backendRefs'Duration: ~2–4 minutes. Success: task demo exits 0; weights move
100/0 → 20 → 50 → 100.
Fallback: kubectl -n mulligan get rollout and narrate from
ADR-0201.
Show: failed canary abort → stable-weight rollback.
task demo:chaosDuration: ~1–3 minutes. Success: canary HTTPRoute weight returns to 0 after abort.
Fallback: narrate hack/demo/mulligan-abort.sh and show Rollout status only.
Override the collision-avoiding defaults:
export E5_GRAFANA_PORT=23100
export E5_PROM_PORT=29190
export E5_AM_PORT=29193
# demo:fire also honors PROM_PORT / AM_PORT
export PROM_PORT=29190 AM_PORT=29193Restore the clubhouse replica and tear down stale port-forwards:
kubectl -n gateway scale deploy/clubhouse --replicas=1
pkill -f 'port-forward.*(kps-prometheus|kps-alertmanager|kube-prometheus-stack-grafana)' || trueRe-run the abort path to snap stable weights, or re-apply workloads:
task demo:chaos
# or
kubectl -n mulligan apply -f deploy/workloads/mulligan/kubectl -n argocd get applications
kubectl -n gateway get gateway,httproute,certificate,deploy
kubectl -n monitoring get prometheus,alertmanager,pods
kubectl get events -A --field-selector type=Warning | tail -40Stops temporary port-forwards first, then destroys the kind cluster (no hidden local state beyond the container runtime):
pkill -f 'kubectl.*port-forward' || true
task cluster:downAfter teardown, the Getting Started path from §1 is safe to rerun (idempotent).
- Five-minute reviewer path: repo-root
README.md(not part of this MkDocs tree) - Scorecard evidence: repo-root
evidence/README.md - Architecture: ARCHITECTURE.md