working internal traefik
This commit is contained in:
parent
f537e5c9cb
commit
1ec6e3b383
@ -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
129
README.md
@ -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 (1–20Gi), 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
|
||||
```
|
||||
|
||||
@ -8,7 +8,7 @@ spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`glance.internal`)
|
||||
- match: Host(`glance.{{ .Values.internalDomain }}`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: glance
|
||||
|
||||
@ -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 }}
|
||||
|
||||
@ -8,7 +8,7 @@ spec:
|
||||
entryPoints:
|
||||
- web
|
||||
routes:
|
||||
- match: Host(`homepage.internal`)
|
||||
- match: Host(`homepage.{{ .Values.internalDomain }}`)
|
||||
kind: Rule
|
||||
services:
|
||||
- name: homepage
|
||||
|
||||
@ -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 }}
|
||||
|
||||
@ -1,4 +1,5 @@
|
||||
domain: ratboo.me
|
||||
internalDomain: dog
|
||||
hostIp: "10.0.1.2"
|
||||
|
||||
|
||||
|
||||
Loading…
x
Reference in New Issue
Block a user