This is the runbook for destroying and recreating an environment such as
staging.
- Run the rebuild from a Linux host that can apply the NixOS parts.
- Make sure the repo on that host contains the changes you want to deploy.
- Make sure
infra/<env>/secrets.yamlexists and can be decrypted. - Make sure
settings.yamlis ready fortoolbox secrets. - Expect a destructive rebuild to rotate the node SSH host key.
- Start a
tmuxsession before running the long-lived commands in this guide.terragrunt destroy --all,terragrunt apply --all, and thetoolboxpublish steps can take long enough that you do not want them tied to a single terminal or SSH connection.
For example in staging:
pushd ~/Documents/cloudlab/infra/staging
terragrunt destroy --all
popd
make infra bootstrap platform env=stagingDuring bootstrap, it will ask you to input some secrets, open tmux session to
do that (you may want to rotate your API keys as well).
Run the smoke tests:
make test env=stagingThis happened with cert-manager, dex, and the Istio stack during rebuilds.
The live workload was gone, but helm-controller still had the old release state
in flux-system.
Fix:
- Delete the stale
HelmRelease - Delete the matching Helm storage secret in
flux-system - Reconcile
platform
Example:
kubectl -n flux-system delete helmrelease dex
kubectl -n flux-system delete secret sh.helm.release.v1.dex.v1
kubectl -n flux-system annotate kustomization platform \
reconcile.fluxcd.io/requestedAt="$(date -u +%Y-%m-%dT%H:%M:%SZ)" \
--overwriteThis showed up with cert-manager. The workload was healthy, but
helm-controller refused to retry because the release was marked RetriesExceeded.
Fix:
ts=$(date -u +%Y-%m-%dT%H:%M:%SZ)
kubectl -n flux-system annotate helmrelease cert-manager \
reconcile.fluxcd.io/resetAt="$ts" \
reconcile.fluxcd.io/requestedAt="$ts" \
--overwriteThis means the Istio CNI state on the node survived, but the Istio workloads in
istio-system did not.
Symptoms:
- pods stay in
ContainerCreatingorInit - pod events contain
plugin type="istio-cni" ... Unauthorized istio-systemis empty or partially missing
Fix:
- Delete stale Istio
HelmReleaseobjects - Delete the matching Helm storage secrets
- Reconcile
platform - Recreate any pods that were created while CNI was broken
Forgejo uses the in-cluster Dex service for bootstrap instead of hairpinning through the public gateway.
If Forgejo init fails, check:
kubectl -n forgejo logs deploy/forgejo -c configure-gitea
kubectl get all -n dexThis showed up after restart when:
gateway-istiowas healthyHTTPRoutes were accepted- public
curltohttps://*.staging.khuedoan.comstill failed
Root cause:
- the host IPv6 DNAT rule for
2a01:4f9:c013:e5ee::1:443still pointed to an old gateway pod IP
Checks:
kubectl -n kube-system get pod -l svccontroller.k3s.cattle.io/svcname=gateway-istio -o wide
ip6tables -t nat -S | grep '2a01:4f9:c013:e5ee::1/128 -p tcp -m tcp --dport 443'If the DNAT target points at a dead pod IP, either recycle the svclb pod or
rewrite the top PREROUTING and OUTPUT rules to the live
gateway-istio Service ClusterIP.
platform/stagingis wrapped in Flux resources to avoid the earlier bootstrap deadlocks around namespaces and privileged resources- Dex client secrets and password hashes live in Vault, not plain YAML
- Forgejo bootstraps against the in-cluster Dex service