From 815cd85b9ab95e8f1c5f273b7d76fa65bab78e81 Mon Sep 17 00:00:00 2001 From: mr-forust Date: Tue, 6 Oct 2026 11:27:35 +0200 Subject: [PATCH] feat(homarr): deploy dashboard to k8s on home subdomain Local-only IngressRoute (home.workstation.internal, home.gigaforust.internal), prod commented out. Compose stack for test stand. --- homarr/.env.example | 4 ++ homarr/compose.yaml | 38 ++++++++++++++++ homarr/k8s/certificates.yaml | 28 ++++++++++++ homarr/k8s/config.yaml | 9 ++++ homarr/k8s/homarr.yaml | 81 +++++++++++++++++++++++++++++++++ homarr/k8s/ingress.yaml | 33 ++++++++++++++ homarr/k8s/namespace.yaml | 4 ++ homarr/k8s/rbac.yaml | 58 +++++++++++++++++++++++ homarr/k8s/secrets.yaml.example | 9 ++++ 9 files changed, 264 insertions(+) create mode 100644 homarr/.env.example create mode 100644 homarr/compose.yaml create mode 100644 homarr/k8s/certificates.yaml create mode 100644 homarr/k8s/config.yaml create mode 100644 homarr/k8s/homarr.yaml create mode 100644 homarr/k8s/ingress.yaml create mode 100644 homarr/k8s/namespace.yaml create mode 100644 homarr/k8s/rbac.yaml create mode 100644 homarr/k8s/secrets.yaml.example diff --git a/homarr/.env.example b/homarr/.env.example new file mode 100644 index 0000000..09011ad --- /dev/null +++ b/homarr/.env.example @@ -0,0 +1,4 @@ +SECRET_ENCRYPTION_KEY="REPLACE_ME" +TZ="Europe/Bratislava" +PUID="1000" +PGID="1000" diff --git a/homarr/compose.yaml b/homarr/compose.yaml new file mode 100644 index 0000000..527b488 --- /dev/null +++ b/homarr/compose.yaml @@ -0,0 +1,38 @@ +services: + homarr: + container_name: homarr + image: ghcr.io/homarr-labs/homarr:v2.1.2 + restart: unless-stopped + volumes: + - ./appdata:/appdata + - /var/run/docker.sock:/var/run/docker.sock:ro + - ./kubeconfig:/app/config/kubeconfig:ro + env_file: .env + ports: + - 80:7575 + - 81:3000 + environment: + - TZ=${TZ:-Europe/Bratislava} + - TURBO_TELEMETRY_DISABLED=1 + - KUBECONFIG=/app/config/kubeconfig + labels: + - "traefik.enable=true" + - "traefik.http.services.homarr.loadbalancer.server.port=7575" + + # Prod Router + - "traefik.http.routers.homarr.rule=Host(`homarr.forust.xyz`)" + - "traefik.http.routers.homarr.entrypoints=websecure" + - "traefik.http.routers.homarr.tls.certresolver=letsencrypt" + # Local Router + - "traefik.http.routers.homarr-local.rule=Host(`homarr.workstation.internal`)" + - "traefik.http.routers.homarr-local.entrypoints=websecure" + - "traefik.http.routers.homarr-local.tls=true" + # Dev Router + - "traefik.http.routers.homarr-dev.rule=Host(`homarr.gigaforust.internal`)" + - "traefik.http.routers.homarr-dev.entrypoints=websecure" + - "traefik.http.routers.homarr-dev.tls=true" + networks: + - proxy +networks: + proxy: + external: true diff --git a/homarr/k8s/certificates.yaml b/homarr/k8s/certificates.yaml new file mode 100644 index 0000000..887023c --- /dev/null +++ b/homarr/k8s/certificates.yaml @@ -0,0 +1,28 @@ +# apiVersion: cert-manager.io/v1 +# kind: Certificate +# metadata: +# name: home-prod-tls +# namespace: homarr +# spec: +# secretName: home-prod-tls +# dnsNames: +# - home.forust.xyz +# issuerRef: +# name: letsencrypt-prod +# kind: ClusterIssuer +# --- +apiVersion: cert-manager.io/v1 +kind: Certificate +metadata: + name: internal-wildcard-tls + namespace: homarr +spec: + secretName: internal-wildcard-tls + dnsNames: + - "*.workstation.internal" + - "*.gigaforust.internal" + - workstation.internal + - gigaforust.internal + issuerRef: + name: internal-ca + kind: ClusterIssuer diff --git a/homarr/k8s/config.yaml b/homarr/k8s/config.yaml new file mode 100644 index 0000000..3a37acb --- /dev/null +++ b/homarr/k8s/config.yaml @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: homarr-config + namespace: homarr +data: + TZ: "Europe/Bratislava" + TURBO_TELEMETRY_DISABLED: "1" + ENABLE_KUBERNETES: "true" diff --git a/homarr/k8s/homarr.yaml b/homarr/k8s/homarr.yaml new file mode 100644 index 0000000..b09e754 --- /dev/null +++ b/homarr/k8s/homarr.yaml @@ -0,0 +1,81 @@ +apiVersion: v1 +kind: Service +metadata: + name: homarr-service + namespace: homarr +spec: + selector: + app: homarr + ports: + - port: 7575 + targetPort: 7575 +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: homarr-deployment + namespace: homarr +spec: + replicas: 1 + selector: + matchLabels: + app: homarr + strategy: + type: Recreate + template: + metadata: + labels: + app: homarr + spec: + serviceAccountName: homarr + containers: + - name: homarr + image: ghcr.io/homarr-labs/homarr:v2.1.2 + envFrom: + - configMapRef: + name: homarr-config + - secretRef: + name: homarr-secrets + ports: + - containerPort: 7575 + readinessProbe: + httpGet: + path: / + port: 7575 + initialDelaySeconds: 30 + periodSeconds: 10 + failureThreshold: 6 + livenessProbe: + httpGet: + path: / + port: 7575 + initialDelaySeconds: 60 + periodSeconds: 30 + failureThreshold: 3 + volumeMounts: + - name: homarr-data + mountPath: /appdata + resources: + requests: + cpu: "250m" + memory: "350Mi" + limits: + cpu: "500m" + memory: "700Mi" + volumes: + - name: homarr-data + persistentVolumeClaim: + claimName: homarr-pvc +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: homarr-pvc + namespace: homarr +spec: + resources: + requests: + storage: 2Gi + volumeMode: Filesystem + accessModes: + - ReadWriteOnce diff --git a/homarr/k8s/ingress.yaml b/homarr/k8s/ingress.yaml new file mode 100644 index 0000000..1281646 --- /dev/null +++ b/homarr/k8s/ingress.yaml @@ -0,0 +1,33 @@ +# apiVersion: traefik.io/v1alpha1 +# kind: IngressRoute +# metadata: +# name: homarr-prod +# namespace: homarr +# spec: +# entryPoints: +# - websecure +# routes: +# - match: Host(`home.forust.xyz`) +# kind: Rule +# services: +# - name: homarr-service +# port: 7575 +# tls: +# secretName: home-prod-tls +# --- +apiVersion: traefik.io/v1alpha1 +kind: IngressRoute +metadata: + name: homarr-local + namespace: homarr +spec: + entryPoints: + - websecure + routes: + - match: Host(`home.workstation.internal`) || Host(`home.gigaforust.internal`) + kind: Rule + services: + - name: homarr-service + port: 7575 + tls: + secretName: internal-wildcard-tls diff --git a/homarr/k8s/namespace.yaml b/homarr/k8s/namespace.yaml new file mode 100644 index 0000000..2db5ebc --- /dev/null +++ b/homarr/k8s/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: homarr diff --git a/homarr/k8s/rbac.yaml b/homarr/k8s/rbac.yaml new file mode 100644 index 0000000..0f3ee36 --- /dev/null +++ b/homarr/k8s/rbac.yaml @@ -0,0 +1,58 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: homarr + namespace: homarr +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: homarr-readonly +rules: + - apiGroups: [""] + resources: + - pods + - services + - endpoints + - namespaces + - nodes + - configmaps + - persistentvolumeclaims + - events + verbs: ["get", "list", "watch"] + - apiGroups: ["apps"] + resources: + - deployments + - statefulsets + - daemonsets + - replicasets + verbs: ["get", "list", "watch"] + - apiGroups: ["networking.k8s.io"] + resources: + - ingresses + verbs: ["get", "list", "watch"] + - apiGroups: ["traefik.io"] + resources: + - ingressroutes + - ingressroutetcps + - ingressrouteudps + - middlewares + verbs: ["get", "list", "watch"] + - apiGroups: ["metrics.k8s.io"] + resources: + - pods + - nodes + verbs: ["get", "list"] +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: homarr-readonly +roleRef: + apiGroup: rbac.authorization.k8s.io + kind: ClusterRole + name: homarr-readonly +subjects: + - kind: ServiceAccount + name: homarr + namespace: homarr diff --git a/homarr/k8s/secrets.yaml.example b/homarr/k8s/secrets.yaml.example new file mode 100644 index 0000000..79afc14 --- /dev/null +++ b/homarr/k8s/secrets.yaml.example @@ -0,0 +1,9 @@ +apiVersion: v1 +kind: Secret +metadata: + name: homarr-secrets + namespace: homarr +type: Opaque +stringData: + # openssl rand -hex 32 + SECRET_ENCRYPTION_KEY: "REPLACE_ME"