feat: add home-assistant-dashboard-conventions skill + update multiple skills

- New: smart-home/home-assistant-dashboard-conventions (Mushroom cards, view tabs, no Bubble Cards)
- Updated: rke2, ceph, galera, proxmox, brainstorming, compound-learning, 1password-cli, smart-home-automation skills
- New references: ceph-cluster-administration, docker-volume-forensics, ceph-crush-weight, ceph-ec-mixed-size
This commit is contained in:
Debian
2026-07-14 18:35:16 +00:00
parent e9cc106625
commit 01bd921ced
37 changed files with 6133 additions and 126 deletions
@@ -0,0 +1,164 @@
# Traefik LXC → K8s Migration (2026-07-14)
## CT99999 Inventory (Source)
- **Location:** proxmox7, VLAN 60, IP `10.0.60.10/24`
- **Traefik version:** 3.4.1
- **Static config:** `/etc/traefik/traefik.yaml`
- **Dynamic config:** `/etc/traefik/conf.d/` (file provider, watch=true)
- **TLS:** Let's Encrypt via TLS challenge, `acme.json` at `/etc/traefik/ssl/acme.json`
- **Entry Points:** web (:80 → redirect to :443), websecure (:443), traefik (:8080 dashboard)
## Services on CT99999
| Router | Host | Backend | Port | Notes |
|--------|------|---------|------|-------|
| grafana | grafana.familie-schoen.com | 10.0.30.141 | 3000 | CT141 monitoring |
| librechat | chat.familie-schoen.com, chat.schoen.eu | 10.0.30.102 | 8080 | LibreChat VM |
| seafile_old | seafile.familie-schoen.com | 10.0.30.100 | 8081 | Seafile old |
| imkerei | imkerei.familie-schoen.com | 10.0.30.100 | 80 | Catchall forwarder |
| immich | immich.familie-schoen.com | 10.0.30.99 | 2283 | Immich |
| paperless | dokumente.familie-schoen.com | 10.0.30.101 | 8000 | CT104 paperless |
| homeassistant | homeassistant.familie-schoen.com | 10.0.30.10 | 8123 | VM106 HA |
| seafile | cloud.familie-schoen.com | 10.0.30.99 | 80 | Seafile |
| seadoc | cloud.familie-schoen.com + /sdoc-server | 10.0.30.99 | 8888 | SeaDoc, stripPrefix middleware |
| authelia | auth.familie-schoen.com | 192.168.100.11 | 9091 | CT112 authelia |
| authelia-admin | auth-admin.familie-schoen.com | 192.168.100.11 | 9092 | CT112 authelia admin |
| gitea | git.familie-schoen.com | 10.0.30.105 | 3000 | CT108 (being replaced by K8s) |
| catchall-tcp | HostSNI(`*`) passthrough | 10.0.30.100 | 80 | TCP catchall |
## K8s Traefik (Target)
- **Type:** DaemonSet `rke2-traefik` in `kube-system`
- **Ports:** hostPort 80 + 443 on all 6 nodes (10.0.30.51-53, .61-63)
- **IngressClass:** `traefik`
- **Existing Ingresses:** argocd-server (argocd ns), gitea (gitea ns)
- **Needs:** Let's Encrypt certResolver (not configured by default)
## HA Failover VIP via Cilium L2 (Implemented 2026-07-14)
### Architecture
Instead of pointing the firewall NAT at a single K8s node (SPOF), a
`LoadBalancer` Service requests a VIP from the existing Cilium LB IPAM
pool. Cilium announces the VIP via ARP on one node; auto-failover to
another node on failure (~1-2s).
```
Firewall NAT → 10.0.30.203 (Cilium VIP)
↓ L2 Announcement (ARP)
[aktiver K8s Node — Traefik DaemonSet]
Automatisches Failover bei Node-Ausfall (~1-2s)
```
### Components Deployed
| Component | File | Purpose |
|-----------|------|---------|
| `Service` (LoadBalancer) | `clusters/main/proxy/traefik-lb-service.yaml` | VIP `.203`, selects Traefik pods |
| `Namespace` | `clusters/main/proxy/namespace.yaml` | Shared proxy namespace |
| ArgoCD App | `clusters/main/apps/proxy.yaml` | GitOps for proxy namespace |
### traefik-lb-service.yaml
```yaml
apiVersion: v1
kind: Service
metadata:
name: traefik-lb
namespace: kube-system
spec:
type: LoadBalancer
loadBalancerIP: 10.0.30.203
selector:
app.kubernetes.io/instance: rke2-traefik-kube-system
app.kubernetes.io/name: rke2-traefik
ports:
- name: web
port: 80
targetPort: web
- name: websecure
port: 443
targetPort: websecure
```
### Why Cilium L2 (not MetalLB/keepalived)
- Cilium L2 LB IPAM already running (3 services use it: .200, .201, .202)
- No additional software needed
- Automatic failover — no manual VIP management
- Pool: `10.0.30.200250` (CiliumLoadBalancerIPPool `default-pool`)
- L2 policy: `default-l2-policy` announces LB IPs via ARP on `^eth[0-9]+`
### Verification
After deploying, tested from mgmt-runner (.124):
- `10.0.30.203:80/443` → 404 (no default route — correct)
- `git.schoen.codes` via VIP → Gitea 1.26.1 ✅
- `argocd` via VIP → ArgoCD UI ✅
### Firewall Cutover
Change NAT target: `10.0.60.10``10.0.30.203` (one rule, instant cutover).
Rollback: revert NAT to `10.0.60.10`. CT99999 stays running throughout.
## Pattern for External Backends (not in K8s)
Use `ExternalName` Service + `IngressRoute` CRD:
```yaml
apiVersion: traefik.io/v1alpha1
kind: IngressRoute
metadata:
name: grafana
namespace: proxy
spec:
entryPoints:
- websecure
routes:
- match: Host(`grafana.familie-schoen.com`)
kind: Rule
services:
- name: grafana-external
port: 3000
tls:
certResolver: letsencrypt
---
apiVersion: v1
kind: Service
metadata:
name: grafana-external
namespace: proxy
spec:
type: ExternalName
externalName: 10.0.30.141
```
## SeaDoc StripPath Middleware
```yaml
middlewares:
seadoc-strippath:
stripPrefix:
prefixes:
- /sdoc-server
```
## Accessing CT99999
```bash
# CT99999 is on proxmox7 (10.0.20.70)
ssh -i ~/.ssh/id_ed25519_proxmox root@10.0.20.70 "pct exec 99999 -- ..."
```
## Remaining Steps
1. Add Let's Encrypt certResolver via HelmChartConfig for `rke2-traefik`
2. Create IngressRoute + ExternalName Service for each of the 11 external backends
3. Handle catchall-TCP (make specific, not HostSNI(`*`) — see pitfall in SKILL.md)
4. Cutover firewall NAT: `10.0.60.10``10.0.30.203`
5. Verify each service, then decommission CT99999 after 1 week
## Reference
Full migration plan: `docs/plans/2026-07-14-traefik-ct99999-k8s-migration.md` in iac-homelab repo.