From 34471433ac1159961d571296ddc153bf99730735 Mon Sep 17 00:00:00 2001 From: Hoid Date: Fri, 20 Feb 2026 12:29:13 +0000 Subject: [PATCH] Move CI/CD kubeconfig lessons to k3s-infra skill, remove from MEMORY.md --- MEMORY.md | 7 ------- skills/k3s-infra/SKILL.md | 29 +++++++++++++++++++++++++++++ 2 files changed, 29 insertions(+), 7 deletions(-) diff --git a/MEMORY.md b/MEMORY.md index d5a4025..0103489 100644 --- a/MEMORY.md +++ b/MEMORY.md @@ -30,13 +30,6 @@ - **Note**: Deployment patches to system components (CoreDNS, CNPG operator) are runtime changes. Document in infra notes so they can be re-applied if needed. - **Note**: CNPG Pooler CRD supports `spec.template.spec.affinity` but requires `containers` field too (name+image of pgbouncer) -## CI/CD Kubeconfig Lessons -- **Always use the PUBLIC IP** (188.34.201.101:6443) in deployer kubeconfigs — CI runners run externally and can't reach private IPs (10.0.1.5) -- **Kubeconfig for Forgejo must be base64-encoded** — the workflow does `base64 -d` before use -- **Use `kubectl config` commands** to build kubeconfig (not heredoc interpolation) — avoids CA cert corruption -- **Each deployer SA needs cross-namespace RoleBinding** — staging SA needs binding in prod namespace and vice versa -- **Never read kubeconfig contents** — generate on k3s-mgr, base64 encode, scp to /tmp, let user paste into Forgejo - ## Game Save Files - `memory/d2r.json` — Diablo II: Resurrected progress (Necro "Baltasar", Summoner build) - `memory/bg3.json` — Baldur's Gate 3 progress (Act 1, level 3) diff --git a/skills/k3s-infra/SKILL.md b/skills/k3s-infra/SKILL.md index 52fe3e2..bca046c 100644 --- a/skills/k3s-infra/SKILL.md +++ b/skills/k3s-infra/SKILL.md @@ -277,3 +277,32 @@ traefik.ingress.kubernetes.io/router.middlewares: -staging-staging-ipwh - DaemonSet updateStrategy must be patched to `maxUnavailable: 1` after each helm upgrade (helm resets it) **Note:** If openclaw-vm's public IP changes, update ALL staging-ipwhitelist middlewares. + +## CI/CD Deployer Kubeconfigs + +**Critical rules when generating deployer kubeconfigs:** + +1. **Always use PUBLIC IP** (188.34.201.101:6443) — CI runners run externally and can't reach private IPs (10.0.1.5) +2. **Must be base64-encoded** for Forgejo secrets — workflow does `base64 -d` before use +3. **Use `kubectl config` commands** to build kubeconfig, NOT heredoc interpolation — avoids CA cert corruption +4. **Cross-namespace RoleBindings** — each deployer SA needs access to both staging and prod namespaces (e.g. docfast SA in `docfast` namespace needs RoleBinding in `docfast-staging` too) +5. **Never read kubeconfig contents** — generate on k3s-mgr, base64 encode, scp to /tmp on openclaw-vm, let user paste into Forgejo + +**Generation script pattern (run on k3s-mgr):** +```bash +export KUBECONFIG=/etc/rancher/k3s/k3s.yaml +TOKEN=$(kubectl -n get secret deployer-token -o jsonpath="{.data.token}" | base64 -d) +kubectl -n get secret deployer-token -o jsonpath="{.data.ca\.crt}" | base64 -d > /tmp/ca.crt + +KUBECONFIG=/tmp/deployer.yaml kubectl config set-cluster k3s --server=https://188.34.201.101:6443 --certificate-authority=/tmp/ca.crt --embed-certs=true +KUBECONFIG=/tmp/deployer.yaml kubectl config set-credentials deployer --token="$TOKEN" +KUBECONFIG=/tmp/deployer.yaml kubectl config set-context deployer --cluster=k3s --user=deployer +KUBECONFIG=/tmp/deployer.yaml kubectl config use-context deployer + +# Verify before encoding +kubectl --kubeconfig=/tmp/deployer.yaml -n get pods + +# Encode for Forgejo +base64 -w0 /tmp/deployer.yaml > /tmp/kubeconfig-b64.txt +rm /tmp/ca.crt /tmp/deployer.yaml +```