Diagnosed the vlan50-canary FailedCreatePodSandBox->net1-timeout failure as a stale Pod artifact of the Multus DaemonSet rollout race (sandbox created via a transient daemon/shim state mid-rollout; the current, fully-settled daemon's own logs show no ADD for that UID, only a DEL). No defect found in 02-daemonset.yaml or 10-nad-vlan50.yaml; both are unchanged. Independent of that diagnosis, harden the shared guard script per review: print safe interface/address/route diagnostics before every FATAL exit; validate net1 actually carries the workload's expected static /24 address rather than just existing; add arping-based duplicate-address and gateway-reachability checks before installing the net1 default route (exit-code semantics verified against arping's own source). Requires EXPECTED_VLAN50_IP and NET_RAW (for arping's raw ARP sockets) on every consumer - wired into 20-canary.yaml now, qbittorrent.yaml/jdownloader.yaml need the same when they're migrated. Document the canary's Pod lifecycle: restartPolicy: Never means a Failed canary never reruns on its own, and Argo "Synced" only reflects manifest match, not runtime success - recreate it (new UID) after any Multus/CNI change before trusting its result. Recommend keeping it a manually recreated, controller-less Pod rather than a Job/Deployment, since unattended auto-retry risks a duplicate-address race on its static .100 IP - the exact class of bug this diagnosis just walked through. Co-Authored-By: Claude Sonnet 5 <noreply@anthropic.com>
Kubernetes Manifests
This directory contains raw Kubernetes resources grouped by service area. Most
subdirectories are consumed by Argo CD Applications in argocd/apps.
Directories
| Directory | Contents |
|---|---|
argocd/ |
App-of-apps, Argo CD ingress, Argo CD OIDC sealed secret |
authentik/ |
Authentik ingress, public ingress, proxy outpost, middleware, secret scripts |
cert-manager/ |
Internal and Let's Encrypt ClusterIssuers, Porkbun secret script |
core/ |
Dashy, Glances, CoreDNS custom config, CA installer |
gitea/ |
Gitea storage, backup, public ingress, runner and OIDC/admin secrets |
home-services/ |
HA gateway, AI gateway, Discord bot, service TLS, registry secret |
homeassistant/ |
Home Assistant external service and ingress |
media/ |
Jellyfin, qBittorrent, JDownloader (sending links) |
monitoring/ |
Monitoring PVs, Grafana datasource, Grafana/Auth OIDC secrets |
network/ |
Pi-hole secrets, DDNS, Traefik dashboard, external host ingresses |
portfolio/ |
Portfolio deployment, ingress, registry pull secret |
Secrets
There are two patterns:
*-sealed.yamlfiles are safe to commit and are reconciled by Sealed Secrets.*.shscripts create runtime Secrets from.envdirectly in the cluster.
Use .env.example as the template for local secret names. kubeseal must point
at the in-cluster controller named sealed-secrets-controller in kube-system.
Regenerate committed sealed secrets with the matching script, then commit the resulting YAML. Runtime secret scripts should be run against the target cluster and should not produce committed plaintext.
Certificates
Internal services generally use internal-ca-issuer and home.arpa hostnames.
Public services use Let's Encrypt issuers and nik4nao.com hostnames.
The CA installer lives in core/ca-installer. Its ca-sync CronJob keeps the
served ca.crt and Apple mobileconfig in sync with the cert-manager CA secret.
DNS
Internal DNS records are configured in values/pihole.yaml and
values/pihole-debian.yaml. Add a new hostname to both files when adding a
home.arpa service.
Dashy
core/dashy.yaml defines the deployment and a placeholder ConfigMap. The real
dashboard config comes from config/dashy/conf.yaml:
bash manifests/core/apply-dashy-config.sh