working internal traefik

This commit is contained in:
Alvin Wang 2026-04-20 10:31:49 -04:00
parent f537e5c9cb
commit 1ec6e3b383
7 changed files with 109 additions and 40 deletions

View File

@ -4,3 +4,8 @@ mac-worker Ready <none> 3h13m v1.34.6+k3s1 192.168.139.12 <n
The mac-worker is running inside orbstack linux VM if that matters.
I have a DNS rewrite pointing *.internal to 10.0.1.250 which is traefik-internal.
/dogstore/ is a NFS path that's available to all nodes

129
README.md
View File

@ -1,41 +1,107 @@
# Homelab — k3s Cluster
2-node k3s cluster (1 manager, 1 worker) running a self-hosted homelab stack.
2-node k3s cluster (1 manager, 1 worker) running a self-hosted homelab stack on `ratboo.me`.
## Architecture
### Nodes
| Node | Role | OS | IP | Runtime |
|------|------|----|----|---------|
| **dogbox** | control-plane | Fedora 40 Server | `10.0.1.2` | k3s server + containerd |
| **mac-worker** | worker | Ubuntu 25.10 (OrbStack VM) | `192.168.139.12` | k3s agent + containerd |
### Overview
```
Manager Node Worker Node
┌──────────────┐ ┌──────────────┐
│ k3s server │────────────│ k3s agent │
│ Traefik │ │ │
│ Longhorn │ │ Longhorn │
└──────┬───────┘ └──────┬───────┘
│ │
└───────── NFS ─────────────┘
/dogstore
Internet
Cloudflare DNS
*.ratboo.me
┌──────────────────────────┼──────────────────────────┐
│ dogbox (manager) │
│ Fedora 40 · 10.0.1.2 │
│ │
│ ┌─────────────────┐ ┌──────────────────────┐ │
│ │ k3s server │ │ Traefik (k3s) │ │
│ │ control-plane │ │ :443 websecure │ │
│ └─────────────────┘ │ Let's Encrypt + CF │ │
│ └──────────┬───────────┘ │
│ ┌─────────────────┐ │ │
│ │ traefik-internal │ Routes to pods across │
│ │ :80 LB 10.0.1.250│ both nodes via CNI │
│ │ (MetalLB L2) │ │ │
│ └─────────────────┘ │ │
│ Longhorn │ │
└──────────────┬─────────────────────┼─────────────────┘
│ │
NFS /dogstore k3s cluster
│ │
┌──────────────┴─────────────────────┼─────────────────┐
│ mac-worker (worker) │
│ Ubuntu 25.10 · OrbStack VM │
│ 192.168.139.12 │
│ │
│ Longhorn · workload pods │
└──────────────────────────────────────────────────────┘
```
**Storage strategy:**
### Networking
- `/dogstore` (NFS) — mounted on both nodes, used via hostPath for large media/data volumes
- Longhorn — replicated block storage for small config/state volumes
**Public ingress** — k3s bundles Traefik, configured via `HelmChartConfig` in `traefik-config`. TLS terminates at Traefik using Let's Encrypt with Cloudflare DNS-01 challenge. HTTP automatically redirects to HTTPS.
**Ingress:** k3s built-in Traefik with Let's Encrypt via Cloudflare DNS challenge.
| Public hostname | Service |
|-----------------|---------|
| `plex.ratboo.me` | Plex |
| `sonarr.ratboo.me` | Sonarr |
| `radarr.ratboo.me` | Radarr |
| `paperless.ratboo.me` | Paperless-ngx |
| `mealie.ratboo.me` | Mealie |
| `watch.ratboo.me` | Seerr |
**Secrets:** SOPS + age encryption. Secrets live in `secrets/secrets.enc.yaml`, encrypted at rest.
**Internal ingress** — A separate Traefik instance (`traefik-internal`) listens on `10.0.1.250:80`, served by MetalLB L2. A DNS rewrite points `*.internal` to that IP. Internal services use Traefik `IngressRoute` CRDs with `ingressClass: traefik-internal`.
| Internal hostname | Service |
|-------------------|---------|
| `homepage.rat` | Homepage |
| `glance.rat` | Glance |
**Cluster-only (no ingress):** Prowlarr, Bazarr, qBittorrent, Zerobyte.
### Storage
| Mechanism | Use |
|-----------|-----|
| **Longhorn** (`storageClass: longhorn`, replica count 2) | Small config/state PVCs — Traefik ACME (128Mi), app configs (120Gi), Paperless Postgres/Redis, Mealie data, Seerr, Zerobyte |
| **NFS via hostPath `/dogstore`** | Large/shared data — Plex media + transcode, Sonarr/Radarr/qBittorrent/unpackerr data trees, Paperless documents, Homepage/Glance configs |
### Secrets
SOPS + age encryption. All secrets live in `secrets/secrets.enc.yaml`, encrypted at rest. The age key lives at `/etc/sops/age/keys.txt` on each node. Referenced secrets include Cloudflare API tokens, database passwords, Plex claim tokens, and application API keys.
## Namespaces
| Namespace | Contents |
|-----------|----------|
| `kube-system` | k3s Traefik, `traefik-config` (HelmChartConfig + redirect middleware) |
| `longhorn-system` | Longhorn storage |
| `media` | Plex, Sonarr, Radarr, Bazarr, Prowlarr, qBittorrent, unpackerr |
| `paperless` | Paperless-ngx, Redis, PostgreSQL |
| `apps` | Mealie, Homepage, Glance, Seerr, Zerobyte |
## Services
| Chart | Namespace | Services |
| -------------- | ----------- | -------------------------------------------------------------- |
| traefik-config | kube-system | Traefik HelmChartConfig overlay |
| media | media | Plex, Sonarr, Radarr, Bazarr, Prowlarr, qBittorrent, unpackerr |
| paperless | paperless | Paperless-ngx, Redis, PostgreSQL |
| mealie | apps | Mealie |
| dashboards | apps | Homepage, Glance |
| utils | apps | Zerobyte, Seerr |
| Chart | Namespace | Services | Notes |
|-------|-----------|----------|-------|
| traefik-config | kube-system | Traefik HelmChartConfig overlay | Cloudflare DNS-01, ACME on Longhorn |
| traefik-internal | — | Internal Traefik instance | LB via MetalLB at `10.0.1.250` |
| metallb | — | MetalLB L2 pool | Single-IP pool for internal LB |
| media | media | Plex, Sonarr, Radarr, Bazarr, Prowlarr, qBittorrent, unpackerr | Media stack with `/dogstore` data paths |
| paperless | paperless | Paperless-ngx, Redis, PostgreSQL | Postgres 15, Redis 7 |
| mealie | apps | Mealie (v3.14.0) | Gemini API integration for recipes |
| dashboards | apps | Homepage, Glance | Internal-only via `traefik-internal` |
| utils | apps | Seerr, Zerobyte | Seerr public, Zerobyte cluster-only |
## Prerequisites
@ -136,16 +202,19 @@ curl -I https://mealie.ratboo.me
```
homelab/
├── README.md
├── AGENTS.md
├── .sops.yaml
├── scripts/
│ └── bootstrap.sh
├── charts/
│ ├── traefik-config/
│ ├── media/
│ ├── paperless/
│ ├── mealie/
│ ├── dashboards/
│ └── utils/
│ ├── traefik-config/ # k3s Traefik overrides (HelmChartConfig)
│ ├── traefik-internal/ # Separate internal Traefik instance
│ ├── metallb/ # MetalLB L2 for internal LB IP
│ ├── media/ # Plex, *arr stack, qBittorrent, unpackerr
│ ├── paperless/ # Paperless-ngx + Postgres + Redis
│ ├── mealie/ # Mealie recipe manager
│ ├── dashboards/ # Homepage + Glance (internal only)
│ └── utils/ # Seerr + Zerobyte
└── secrets/
└── secrets.enc.yaml
```

View File

@ -8,7 +8,7 @@ spec:
entryPoints:
- web
routes:
- match: Host(`glance.internal`)
- match: Host(`glance.{{ .Values.internalDomain }}`)
kind: Rule
services:
- name: glance

View File

@ -17,10 +17,7 @@ spec:
app: glance
spec:
nodeSelector:
node-role.kubernetes.io/control-plane: "true"
tolerations:
- key: node-role.kubernetes.io/control-plane
effect: NoSchedule
homelab/node-role: worker
containers:
- name: glance
image: {{ .Values.glance.image }}

View File

@ -8,7 +8,7 @@ spec:
entryPoints:
- web
routes:
- match: Host(`homepage.internal`)
- match: Host(`homepage.{{ .Values.internalDomain }}`)
kind: Rule
services:
- name: homepage

View File

@ -17,10 +17,7 @@ spec:
app: homepage
spec:
nodeSelector:
node-role.kubernetes.io/control-plane: "true"
tolerations:
- key: node-role.kubernetes.io/control-plane
effect: NoSchedule
homelab/node-role: worker
containers:
- name: homepage
image: {{ .Values.homepage.image }}

View File

@ -1,4 +1,5 @@
domain: ratboo.me
internalDomain: dog
hostIp: "10.0.1.2"