Files
Debian 01bd921ced 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
2026-07-14 18:35:16 +00:00

165 lines
5.2 KiB
Markdown
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
# 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.