- 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
165 lines
5.2 KiB
Markdown
165 lines
5.2 KiB
Markdown
# 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.200–250` (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.
|