added glance dashboard
This commit is contained in:
90
cluster/applications/the-hub/README.md
Normal file
90
cluster/applications/the-hub/README.md
Normal file
@@ -0,0 +1,90 @@
|
||||
# the-hub
|
||||
|
||||
**Glance** dashboard for mk-labs, deployed on `fastpass` (Talos/Kubernetes).
|
||||
Managed by ArgoCD. All config is code. No manual kubectl required after initial bootstrap.
|
||||
|
||||
---
|
||||
|
||||
## Repo layout
|
||||
|
||||
```
|
||||
cluster/
|
||||
argocd/
|
||||
the-hub-application.yaml # ArgoCD Application — drop this in with your platform apps
|
||||
applications/
|
||||
the-hub/
|
||||
namespace.yaml
|
||||
rbac.yaml # ServiceAccount + ClusterRole (read-only K8s access)
|
||||
externalsecret.yaml # ESO ExternalSecret — pulls tokens from 1Password
|
||||
deployment.yaml
|
||||
service.yaml
|
||||
ingress.yaml
|
||||
configmap.yaml # glance.yml lives here — this is where you edit the dashboard
|
||||
```
|
||||
|
||||
---
|
||||
|
||||
## URL
|
||||
|
||||
`https://the-hub.local.mk-labs.cloud`
|
||||
|
||||
TLS via cert-manager + Cloudflare DNS-01 (`letsencrypt-prod` ClusterIssuer).
|
||||
|
||||
---
|
||||
|
||||
## Secrets (1Password → ESO)
|
||||
|
||||
Create a 1Password vault item named **`the-hub`** with these fields:
|
||||
|
||||
| Field | Value |
|
||||
|---|---|
|
||||
| `proxmox_token` | `user@pam!token-name=<uuid>` |
|
||||
| `pbs_token` | `PBSAPIToken=user@pam!token-name=<uuid>` |
|
||||
| `grafana_token` | Grafana service account token (read-only) |
|
||||
| `gitea_token` | Gitea personal access token (read-only) |
|
||||
|
||||
ESO syncs these into the `the-hub-secrets` Kubernetes Secret. The Deployment mounts
|
||||
them as environment variables, which `glance.yml` references via `${VAR_NAME}` syntax.
|
||||
|
||||
---
|
||||
|
||||
## Proxmox API token setup
|
||||
|
||||
Create a **read-only** API token in Proxmox:
|
||||
|
||||
1. Datacenter → Permissions → API Tokens → Add
|
||||
2. User: any read-only user (or `root@pam` for lab use)
|
||||
3. Token ID: `glance`
|
||||
4. Uncheck "Privilege Separation" only if you want full access
|
||||
5. Assign role `PVEAuditor` to the token at the `/` path
|
||||
|
||||
Token format in 1Password: `user@pam!glance=xxxxxxxx-xxxx-xxxx-xxxx-xxxxxxxxxxxx`
|
||||
|
||||
---
|
||||
|
||||
## SSO (Authentik forward-auth)
|
||||
|
||||
SSO annotations are present but commented out in `ingress.yaml`. Uncomment when
|
||||
`guest-relations` Authentik SSO is configured for `fastpass` ingress.
|
||||
|
||||
---
|
||||
|
||||
## Editing the dashboard
|
||||
|
||||
The entire dashboard lives in `configmap.yaml` under the `glance.yml` key.
|
||||
|
||||
1. Edit `cluster/applications/the-hub/configmap.yaml`
|
||||
2. Commit + push
|
||||
3. ArgoCD syncs automatically (or `argocd app sync the-hub`)
|
||||
4. Glance hot-reloads the config — no pod restart needed for content changes
|
||||
(pod restarts only needed when env var secrets change)
|
||||
|
||||
---
|
||||
|
||||
## Pages
|
||||
|
||||
| Page | Purpose |
|
||||
|---|---|
|
||||
| **Overview** | Service health monitors + bookmarks + Gitea repo activity |
|
||||
| **Infrastructure** | Proxmox node stats, PBS status, Grafana iframe |
|
||||
| **Updates** | Homelab YouTuber RSS, K8s/Argo release tracking, tech news |
|
||||
29
cluster/applications/the-hub/application.yaml
Normal file
29
cluster/applications/the-hub/application.yaml
Normal file
@@ -0,0 +1,29 @@
|
||||
apiVersion: argoproj.io/v1alpha1
|
||||
kind: Application
|
||||
metadata:
|
||||
name: the-hub
|
||||
namespace: argocd
|
||||
labels:
|
||||
app.kubernetes.io/name: the-hub
|
||||
app.kubernetes.io/part-of: mk-labs
|
||||
annotations:
|
||||
argocd.argoproj.io/sync-wave: "20" # Wave 20 — applications tier
|
||||
spec:
|
||||
project: default
|
||||
source:
|
||||
repoURL: ssh://git@gitea.mk-labs.cloud/rblundon/homelab.git
|
||||
targetRevision: HEAD
|
||||
path: cluster/applications/the-hub
|
||||
directory:
|
||||
recurse: false
|
||||
exclude: application.yaml # prevent self-reference loop
|
||||
destination:
|
||||
server: https://kubernetes.default.svc
|
||||
namespace: the-hub
|
||||
syncPolicy:
|
||||
automated:
|
||||
prune: true
|
||||
selfHeal: true
|
||||
syncOptions:
|
||||
- CreateNamespace=true
|
||||
- ApplyOutOfSyncOnly=true
|
||||
388
cluster/applications/the-hub/configmap.yaml
Normal file
388
cluster/applications/the-hub/configmap.yaml
Normal file
@@ -0,0 +1,388 @@
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: the-hub-config
|
||||
namespace: the-hub
|
||||
labels:
|
||||
app.kubernetes.io/name: the-hub
|
||||
app.kubernetes.io/part-of: mk-labs
|
||||
data:
|
||||
glance.yml: |
|
||||
# ============================================================
|
||||
# the-hub — mk-labs dashboard
|
||||
# Managed by ArgoCD. Edit here, commit, let ArgoCD sync.
|
||||
# Secrets injected as env vars from the-hub-secrets (ESO/1Password)
|
||||
# ============================================================
|
||||
|
||||
server:
|
||||
port: 8080
|
||||
proxied: true # behind ingress-nginx; use X-Forwarded-* headers
|
||||
|
||||
branding:
|
||||
app-name: "mk-labs | the hub"
|
||||
logo-text: "MK"
|
||||
hide-footer: false
|
||||
|
||||
theme:
|
||||
# Deep dark — feels right for a server room
|
||||
background-color: 220 13 10
|
||||
primary-color: 213 80 60
|
||||
contrast-multiplier: 1.1
|
||||
|
||||
# ============================================================
|
||||
# PAGE 1 — OVERVIEW
|
||||
# The park map. One pane of glass for the whole kingdom.
|
||||
# ============================================================
|
||||
pages:
|
||||
- name: Overview
|
||||
columns:
|
||||
|
||||
# --- LEFT: fastpass cluster + uptime monitors ---
|
||||
- size: small
|
||||
widgets:
|
||||
|
||||
- type: monitor
|
||||
title: fastpass — Control Plane
|
||||
cache: 1m
|
||||
sites:
|
||||
- title: space-mountain
|
||||
url: https://10.1.71.66:6443/healthz
|
||||
icon: di:kubernetes
|
||||
allow-insecure: true
|
||||
- title: big-thunder-mountain
|
||||
url: https://10.1.71.67:6443/healthz
|
||||
icon: di:kubernetes
|
||||
allow-insecure: true
|
||||
- title: splash-mountain
|
||||
url: https://10.1.71.68:6443/healthz
|
||||
icon: di:kubernetes
|
||||
allow-insecure: true
|
||||
|
||||
- type: monitor
|
||||
title: fastpass — Workers
|
||||
cache: 1m
|
||||
sites:
|
||||
- title: jungle-cruise
|
||||
url: http://10.1.71.69:10248/healthz
|
||||
icon: di:kubernetes
|
||||
- title: haunted-mansion
|
||||
url: http://10.1.71.70:10248/healthz
|
||||
icon: di:kubernetes
|
||||
- title: peter-pans-flight
|
||||
url: http://10.1.71.71:10248/healthz
|
||||
icon: di:kubernetes
|
||||
|
||||
- type: monitor
|
||||
title: magic-kingdom — Proxmox
|
||||
cache: 2m
|
||||
sites:
|
||||
- title: main-street-usa
|
||||
url: https://10.1.71.11:8006
|
||||
icon: di:proxmox
|
||||
allow-insecure: true
|
||||
- title: tomorrowland
|
||||
url: https://10.1.71.12:8006
|
||||
icon: di:proxmox
|
||||
allow-insecure: true
|
||||
- title: fantasyland
|
||||
url: https://10.1.71.13:8006
|
||||
icon: di:proxmox
|
||||
allow-insecure: true
|
||||
|
||||
- type: monitor
|
||||
title: utilidor — Storage
|
||||
cache: 2m
|
||||
sites:
|
||||
- title: emporium (Synology)
|
||||
url: https://10.1.71.9:5001
|
||||
icon: di:synology
|
||||
allow-insecure: true
|
||||
- title: utilidor (FlashArray)
|
||||
url: https://10.1.71.28
|
||||
icon: mdi:database
|
||||
allow-insecure: true
|
||||
|
||||
# --- CENTER: Core services health ---
|
||||
- size: full
|
||||
widgets:
|
||||
|
||||
- type: monitor
|
||||
title: Platform Services
|
||||
cache: 1m
|
||||
sites:
|
||||
- title: lightning-lane (Traefik)
|
||||
url: https://traefik.local.mk-labs.cloud/ping
|
||||
icon: di:traefik
|
||||
- title: guest-relations (Authentik)
|
||||
url: https://authentik.local.mk-labs.cloud/-/health/live/
|
||||
icon: di:authentik
|
||||
- title: monorail (DNS)
|
||||
url: http://10.1.71.32:5380
|
||||
icon: di:technitium
|
||||
- title: fire-station (NetBox)
|
||||
url: https://netbox.local.mk-labs.cloud/api/
|
||||
icon: di:netbox
|
||||
- title: mad-tea-party (Gitea)
|
||||
url: https://gitea.mk-labs.cloud/-/health
|
||||
icon: di:gitea
|
||||
- title: city-hall (Control Node)
|
||||
url: http://10.1.71.38:8080
|
||||
icon: mdi:ansible
|
||||
- title: imagineering (Semaphore)
|
||||
url: https://semaphore.local.mk-labs.cloud/api/ping
|
||||
icon: di:semaphore
|
||||
- title: tiki-room (n8n)
|
||||
url: https://n8n.local.mk-labs.cloud/healthz
|
||||
icon: di:n8n
|
||||
- title: cinderella-castle (Grafana)
|
||||
url: https://grafana.local.mk-labs.cloud/api/health
|
||||
icon: di:grafana
|
||||
- title: turnstile (step-ca)
|
||||
url: https://10.1.71.34:8443/health
|
||||
icon: mdi:certificate
|
||||
allow-insecure: true
|
||||
- title: the-grid (Nextcloud)
|
||||
url: https://nextcloud.local.mk-labs.cloud/status.php
|
||||
icon: di:nextcloud
|
||||
- title: timekeeper (PBS)
|
||||
url: https://pbs.local.mk-labs.cloud
|
||||
icon: di:proxmox
|
||||
allow-insecure: true
|
||||
|
||||
- type: bookmarks
|
||||
title: Navigation
|
||||
groups:
|
||||
- title: Cluster
|
||||
links:
|
||||
- title: ArgoCD
|
||||
url: https://argocd.local.mk-labs.cloud
|
||||
icon: di:argocd
|
||||
- title: Grafana
|
||||
url: https://grafana.local.mk-labs.cloud
|
||||
icon: di:grafana
|
||||
- title: Prometheus
|
||||
url: https://prometheus.local.mk-labs.cloud
|
||||
icon: di:prometheus
|
||||
- title: Infrastructure
|
||||
links:
|
||||
- title: Proxmox (main-street-usa)
|
||||
url: https://10.1.71.11:8006
|
||||
icon: di:proxmox
|
||||
- title: Proxmox (tomorrowland)
|
||||
url: https://10.1.71.12:8006
|
||||
icon: di:proxmox
|
||||
- title: Proxmox (fantasyland)
|
||||
url: https://10.1.71.13:8006
|
||||
icon: di:proxmox
|
||||
- title: NetBox
|
||||
url: https://netbox.local.mk-labs.cloud
|
||||
icon: di:netbox
|
||||
- title: Technitium DNS
|
||||
url: http://10.1.71.32:5380
|
||||
icon: di:technitium
|
||||
- title: Apps
|
||||
links:
|
||||
- title: Gitea
|
||||
url: https://gitea.mk-labs.cloud
|
||||
icon: di:gitea
|
||||
- title: Semaphore
|
||||
url: https://semaphore.local.mk-labs.cloud
|
||||
icon: di:semaphore
|
||||
- title: n8n
|
||||
url: https://n8n.local.mk-labs.cloud
|
||||
icon: di:n8n
|
||||
- title: Nextcloud
|
||||
url: https://nextcloud.local.mk-labs.cloud
|
||||
icon: di:nextcloud
|
||||
- title: Authentik
|
||||
url: https://authentik.local.mk-labs.cloud
|
||||
icon: di:authentik
|
||||
|
||||
# --- RIGHT: Gitea repo activity + releases ---
|
||||
- size: small
|
||||
widgets:
|
||||
|
||||
- type: repository
|
||||
title: homelab repo
|
||||
repository: rblundon/homelab
|
||||
# Uses Gitea (self-hosted) — point at your instance
|
||||
# Once Gitea mirroring from GitHub is live, switch url here
|
||||
url: https://gitea.mk-labs.cloud
|
||||
token: ${GITEA_TOKEN}
|
||||
pull-requests-limit: 5
|
||||
issues-limit: 5
|
||||
commits-limit: 5
|
||||
|
||||
- type: releases
|
||||
title: Stack Releases
|
||||
cache: 6h
|
||||
releases:
|
||||
- repository: argoproj/argo-cd
|
||||
- repository: cilium/cilium
|
||||
- repository: cert-manager/cert-manager
|
||||
- repository: kubernetes/kubernetes
|
||||
- repository: glanceapp/glance
|
||||
- repository: talos-systems/talos
|
||||
- repository: traefik/traefik
|
||||
|
||||
# ============================================================
|
||||
# PAGE 2 — INFRA
|
||||
# Proxmox cluster stats via community custom-api widgets
|
||||
# ============================================================
|
||||
- name: Infrastructure
|
||||
columns:
|
||||
|
||||
- size: full
|
||||
widgets:
|
||||
|
||||
- type: custom-api
|
||||
title: magic-kingdom — Cluster Overview
|
||||
cache: 2m
|
||||
allow-insecure: true
|
||||
url: https://10.1.71.11:8006/api2/json/cluster/resources
|
||||
headers:
|
||||
Authorization: "PVEAPIToken=${PROXMOX_TOKEN}"
|
||||
template: |
|
||||
{{ $vms := 0 }}{{ $lxcs := 0 }}{{ $running := 0 }}
|
||||
{{ range .JSON.Array "data" }}
|
||||
{{ if eq (.String "type") "qemu" }}{{ $vms = add $vms 1 }}{{ end }}
|
||||
{{ if eq (.String "type") "lxc" }}{{ $lxcs = add $lxcs 1 }}{{ end }}
|
||||
{{ if eq (.String "status") "running" }}{{ $running = add $running 1 }}{{ end }}
|
||||
{{ end }}
|
||||
<div class="flex gap-4 justify-around">
|
||||
<div class="text-center">
|
||||
<div class="text-2xl font-bold">{{ $vms }}</div>
|
||||
<div class="text-sm text-muted">VMs</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="text-2xl font-bold">{{ $lxcs }}</div>
|
||||
<div class="text-sm text-muted">LXCs</div>
|
||||
</div>
|
||||
<div class="text-center">
|
||||
<div class="text-2xl font-bold text-ok">{{ $running }}</div>
|
||||
<div class="text-sm text-muted">Running</div>
|
||||
</div>
|
||||
</div>
|
||||
|
||||
# Proxmox VE node stats (community widget pattern)
|
||||
# One block per node — copy and adjust IP for each
|
||||
- type: custom-api
|
||||
title: main-street-usa (10.1.71.11)
|
||||
cache: 1m
|
||||
allow-insecure: true
|
||||
url: https://10.1.71.11:8006/api2/json/nodes/main-street-usa/status
|
||||
headers:
|
||||
Authorization: "PVEAPIToken=${PROXMOX_TOKEN}"
|
||||
template: |
|
||||
{{ $cpu := mul (.JSON.Float "data.cpu") 100.0 }}
|
||||
{{ $memUsed := .JSON.Float "data.memory.used" }}
|
||||
{{ $memTotal := .JSON.Float "data.memory.total" }}
|
||||
{{ $memPct := mul (div $memUsed $memTotal) 100.0 }}
|
||||
<div class="flex gap-4">
|
||||
<div>CPU: <strong>{{ printf "%.1f" $cpu }}%</strong></div>
|
||||
<div>RAM: <strong>{{ printf "%.1f" $memPct }}%</strong></div>
|
||||
</div>
|
||||
|
||||
- type: custom-api
|
||||
title: tomorrowland (10.1.71.12)
|
||||
cache: 1m
|
||||
allow-insecure: true
|
||||
url: https://10.1.71.12:8006/api2/json/nodes/tomorrowland/status
|
||||
headers:
|
||||
Authorization: "PVEAPIToken=${PROXMOX_TOKEN}"
|
||||
template: |
|
||||
{{ $cpu := mul (.JSON.Float "data.cpu") 100.0 }}
|
||||
{{ $memUsed := .JSON.Float "data.memory.used" }}
|
||||
{{ $memTotal := .JSON.Float "data.memory.total" }}
|
||||
{{ $memPct := mul (div $memUsed $memTotal) 100.0 }}
|
||||
<div class="flex gap-4">
|
||||
<div>CPU: <strong>{{ printf "%.1f" $cpu }}%</strong></div>
|
||||
<div>RAM: <strong>{{ printf "%.1f" $memPct }}%</strong></div>
|
||||
</div>
|
||||
|
||||
- type: custom-api
|
||||
title: fantasyland (10.1.71.13)
|
||||
cache: 1m
|
||||
allow-insecure: true
|
||||
url: https://10.1.71.13:8006/api2/json/nodes/fantasyland/status
|
||||
headers:
|
||||
Authorization: "PVEAPIToken=${PROXMOX_TOKEN}"
|
||||
template: |
|
||||
{{ $cpu := mul (.JSON.Float "data.cpu") 100.0 }}
|
||||
{{ $memUsed := .JSON.Float "data.memory.used" }}
|
||||
{{ $memTotal := .JSON.Float "data.memory.total" }}
|
||||
{{ $memPct := mul (div $memUsed $memTotal) 100.0 }}
|
||||
<div class="flex gap-4">
|
||||
<div>CPU: <strong>{{ printf "%.1f" $cpu }}%</strong></div>
|
||||
<div>RAM: <strong>{{ printf "%.1f" $memPct }}%</strong></div>
|
||||
</div>
|
||||
|
||||
- size: small
|
||||
widgets:
|
||||
|
||||
# Proxmox Backup Server — community widget
|
||||
# Requires PBS_TOKEN env var (PBSAPIToken=user@pam!token=<secret>)
|
||||
- type: custom-api
|
||||
title: timekeeper (PBS)
|
||||
cache: 5m
|
||||
allow-insecure: true
|
||||
url: https://pbs.local.mk-labs.cloud:8007/api2/json/nodes/localhost/status
|
||||
headers:
|
||||
Authorization: "${PBS_TOKEN}"
|
||||
template: |
|
||||
{{ $cpu := mul (.JSON.Float "data.cpu") 100.0 }}
|
||||
{{ $memUsed := .JSON.Float "data.memory.used" }}
|
||||
{{ $memTotal := .JSON.Float "data.memory.total" }}
|
||||
{{ $memPct := mul (div $memUsed $memTotal) 100.0 }}
|
||||
<div class="flex gap-4">
|
||||
<div>CPU: <strong>{{ printf "%.1f" $cpu }}%</strong></div>
|
||||
<div>RAM: <strong>{{ printf "%.1f" $memPct }}%</strong></div>
|
||||
</div>
|
||||
|
||||
- type: iframe
|
||||
title: cinderella-castle — Grafana
|
||||
source: https://grafana.local.mk-labs.cloud/d/rYdddlPWk/node-exporter-full?orgId=1&kiosk
|
||||
height: 400
|
||||
|
||||
# ============================================================
|
||||
# PAGE 3 — HOMELAB RSS
|
||||
# Stay current. Jarvis reads the feeds so you don't have to.
|
||||
# ============================================================
|
||||
- name: Updates
|
||||
columns:
|
||||
- size: full
|
||||
widgets:
|
||||
|
||||
- type: rss
|
||||
title: Homelab Community
|
||||
style: horizontal-cards
|
||||
feeds:
|
||||
- url: https://www.youtube.com/feeds/videos.xml?channel_id=UCZNhwA1B5YqiY1nLzmM0ZRg
|
||||
title: Christian Lempa
|
||||
- url: https://www.youtube.com/feeds/videos.xml?channel_id=UCOk-gHyjcWZNj3Br4oxwh0A
|
||||
title: Techno Tim
|
||||
- url: https://www.youtube.com/feeds/videos.xml?channel_id=UCg6gPGh8HU2U01vaFCAsvmQ
|
||||
title: Network Chuck
|
||||
- url: https://www.youtube.com/feeds/videos.xml?channel_id=UCrRQxEQyp3H2aCMYmXTMfhQ
|
||||
title: Jim's Garage
|
||||
limit: 6
|
||||
collapse-after: 4
|
||||
|
||||
- type: releases
|
||||
title: Pure Storage
|
||||
cache: 12h
|
||||
releases:
|
||||
- repository: pure-storage/purity-fb-python-client
|
||||
- repository: portworx/px-backup
|
||||
|
||||
- type: rss
|
||||
title: Tech / Ops News
|
||||
feeds:
|
||||
- url: https://feeds.feedburner.com/TheHackersNews
|
||||
title: The Hacker News
|
||||
- url: https://kubernetes.io/feed.xml
|
||||
title: Kubernetes Blog
|
||||
- url: https://blog.argoproj.io/feed
|
||||
title: Argo Blog
|
||||
limit: 8
|
||||
collapse-after: 5
|
||||
92
cluster/applications/the-hub/deployment.yaml
Normal file
92
cluster/applications/the-hub/deployment.yaml
Normal file
@@ -0,0 +1,92 @@
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: the-hub
|
||||
namespace: the-hub
|
||||
labels:
|
||||
app.kubernetes.io/name: the-hub
|
||||
app.kubernetes.io/part-of: mk-labs
|
||||
spec:
|
||||
replicas: 1
|
||||
revisionHistoryLimit: 3
|
||||
selector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: the-hub
|
||||
strategy:
|
||||
type: RollingUpdate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: the-hub
|
||||
annotations:
|
||||
# Force pod restart when the glance config ConfigMap changes
|
||||
# (Kubernetes does not automatically restart pods on ConfigMap updates)
|
||||
checksum/config: "{{ include (print $.Template.BasePath \"/configmap.yaml\") . | sha256sum }}"
|
||||
spec:
|
||||
serviceAccountName: the-hub
|
||||
automountServiceAccountToken: true
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 1000
|
||||
runAsGroup: 1000
|
||||
fsGroup: 1000
|
||||
containers:
|
||||
- name: glance
|
||||
image: glanceapp/glance:latest
|
||||
imagePullPolicy: Always
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: 8080
|
||||
protocol: TCP
|
||||
env:
|
||||
# Injected from ExternalSecret — API tokens used in glance.yml
|
||||
# via ${ENV_VAR} syntax
|
||||
- name: PROXMOX_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: the-hub-secrets
|
||||
key: PROXMOX_TOKEN
|
||||
- name: PBS_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: the-hub-secrets
|
||||
key: PBS_TOKEN
|
||||
- name: GRAFANA_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: the-hub-secrets
|
||||
key: GRAFANA_TOKEN
|
||||
- name: GITEA_TOKEN
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: the-hub-secrets
|
||||
key: GITEA_TOKEN
|
||||
volumeMounts:
|
||||
- name: config
|
||||
mountPath: /app/config/glance.yml
|
||||
subPath: glance.yml
|
||||
readOnly: true
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 64Mi
|
||||
limits:
|
||||
cpu: 200m
|
||||
memory: 128Mi
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
initialDelaySeconds: 15
|
||||
periodSeconds: 30
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: http
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
volumes:
|
||||
- name: config
|
||||
configMap:
|
||||
name: the-hub-config
|
||||
47
cluster/applications/the-hub/externalsecret.yaml
Normal file
47
cluster/applications/the-hub/externalsecret.yaml
Normal file
@@ -0,0 +1,47 @@
|
||||
---
|
||||
# ExternalSecret pulls credentials from 1Password Connect
|
||||
# and creates a standard Kubernetes Secret that Glance reads
|
||||
# as environment variables injected into the container.
|
||||
#
|
||||
# Prerequisites: ESO + 1Password Connect installed in fastpass
|
||||
# 1Password vault item: "the-hub" with fields matching below
|
||||
apiVersion: external-secrets.io/v1beta1
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: the-hub-secrets
|
||||
namespace: the-hub
|
||||
labels:
|
||||
app.kubernetes.io/name: the-hub
|
||||
app.kubernetes.io/part-of: mk-labs
|
||||
spec:
|
||||
refreshInterval: 1h
|
||||
secretStoreRef:
|
||||
name: onepassword-connect # ClusterSecretStore name from your ESO bootstrap
|
||||
kind: ClusterSecretStore
|
||||
target:
|
||||
name: the-hub-secrets
|
||||
creationPolicy: Owner
|
||||
data:
|
||||
# Proxmox API token (read-only, created in Datacenter > API Tokens)
|
||||
- secretKey: PROXMOX_TOKEN
|
||||
remoteRef:
|
||||
key: the-hub
|
||||
property: proxmox_token
|
||||
|
||||
# Proxmox Backup Server API token
|
||||
- secretKey: PBS_TOKEN
|
||||
remoteRef:
|
||||
key: the-hub
|
||||
property: pbs_token
|
||||
|
||||
# Grafana service account token (read-only)
|
||||
- secretKey: GRAFANA_TOKEN
|
||||
remoteRef:
|
||||
key: the-hub
|
||||
property: grafana_token
|
||||
|
||||
# Gitea personal access token (read-only)
|
||||
- secretKey: GITEA_TOKEN
|
||||
remoteRef:
|
||||
key: the-hub
|
||||
property: gitea_token
|
||||
35
cluster/applications/the-hub/ingress.yaml
Normal file
35
cluster/applications/the-hub/ingress.yaml
Normal file
@@ -0,0 +1,35 @@
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: the-hub
|
||||
namespace: the-hub
|
||||
labels:
|
||||
app.kubernetes.io/name: the-hub
|
||||
app.kubernetes.io/part-of: mk-labs
|
||||
annotations:
|
||||
# TLS certificate managed by cert-manager + Cloudflare DNS-01
|
||||
cert-manager.io/cluster-issuer: letsencrypt-prod
|
||||
|
||||
# When Authentik forward-auth is ready, uncomment these:
|
||||
# nginx.ingress.kubernetes.io/auth-url: "https://guest-relations.local.mk-labs.cloud/outpost.goauthentik.io/auth/nginx"
|
||||
# nginx.ingress.kubernetes.io/auth-signin: "https://guest-relations.local.mk-labs.cloud/outpost.goauthentik.io/start?rd=$escaped_request_uri"
|
||||
# nginx.ingress.kubernetes.io/auth-response-headers: "Set-Cookie,X-authentik-username,X-authentik-groups,X-authentik-email,X-authentik-name,X-authentik-uid"
|
||||
# nginx.ingress.kubernetes.io/auth-snippet: |
|
||||
# proxy_set_header X-Original-URL $scheme://$http_host$request_uri;
|
||||
spec:
|
||||
ingressClassName: nginx
|
||||
tls:
|
||||
- hosts:
|
||||
- the-hub.local.mk-labs.cloud
|
||||
secretName: the-hub-tls
|
||||
rules:
|
||||
- host: the-hub.local.mk-labs.cloud
|
||||
http:
|
||||
paths:
|
||||
- path: /
|
||||
pathType: Prefix
|
||||
backend:
|
||||
service:
|
||||
name: the-hub
|
||||
port:
|
||||
name: http
|
||||
7
cluster/applications/the-hub/namespace.yaml
Normal file
7
cluster/applications/the-hub/namespace.yaml
Normal file
@@ -0,0 +1,7 @@
|
||||
apiVersion: v1
|
||||
kind: Namespace
|
||||
metadata:
|
||||
name: the-hub
|
||||
labels:
|
||||
app.kubernetes.io/name: the-hub
|
||||
app.kubernetes.io/part-of: mk-labs
|
||||
57
cluster/applications/the-hub/rbac.yaml
Normal file
57
cluster/applications/the-hub/rbac.yaml
Normal file
@@ -0,0 +1,57 @@
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: the-hub
|
||||
namespace: the-hub
|
||||
labels:
|
||||
app.kubernetes.io/name: the-hub
|
||||
app.kubernetes.io/part-of: mk-labs
|
||||
---
|
||||
# ClusterRole grants read-only access to cluster resources
|
||||
# required for the Glance Kubernetes community widget
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRole
|
||||
metadata:
|
||||
name: the-hub
|
||||
labels:
|
||||
app.kubernetes.io/name: the-hub
|
||||
app.kubernetes.io/part-of: mk-labs
|
||||
rules:
|
||||
- apiGroups: [""]
|
||||
resources:
|
||||
- nodes
|
||||
- pods
|
||||
- services
|
||||
- namespaces
|
||||
- persistentvolumes
|
||||
- persistentvolumeclaims
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["apps"]
|
||||
resources:
|
||||
- deployments
|
||||
- replicasets
|
||||
- statefulsets
|
||||
- daemonsets
|
||||
verbs: ["get", "list", "watch"]
|
||||
- apiGroups: ["metrics.k8s.io"]
|
||||
resources:
|
||||
- nodes
|
||||
- pods
|
||||
verbs: ["get", "list"]
|
||||
---
|
||||
apiVersion: rbac.authorization.k8s.io/v1
|
||||
kind: ClusterRoleBinding
|
||||
metadata:
|
||||
name: the-hub
|
||||
labels:
|
||||
app.kubernetes.io/name: the-hub
|
||||
app.kubernetes.io/part-of: mk-labs
|
||||
roleRef:
|
||||
apiGroup: rbac.authorization.k8s.io
|
||||
kind: ClusterRole
|
||||
name: the-hub
|
||||
subjects:
|
||||
- kind: ServiceAccount
|
||||
name: the-hub
|
||||
namespace: the-hub
|
||||
17
cluster/applications/the-hub/service.yaml
Normal file
17
cluster/applications/the-hub/service.yaml
Normal file
@@ -0,0 +1,17 @@
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: the-hub
|
||||
namespace: the-hub
|
||||
labels:
|
||||
app.kubernetes.io/name: the-hub
|
||||
app.kubernetes.io/part-of: mk-labs
|
||||
spec:
|
||||
type: ClusterIP
|
||||
selector:
|
||||
app.kubernetes.io/name: the-hub
|
||||
ports:
|
||||
- name: http
|
||||
port: 80
|
||||
targetPort: http
|
||||
protocol: TCP
|
||||
Reference in New Issue
Block a user