This commit is contained in:
Alexis Bruneteau 2025-09-04 17:17:18 +02:00
commit 50f5234488
8 changed files with 454 additions and 0 deletions

85
README.md Normal file
View File

@ -0,0 +1,85 @@
# Homepage K3s Configuration
A complete Kubernetes configuration for deploying [Homepage](https://gethomepage.dev/) dashboard on K3s clusters.
## Quick Start
Deploy Homepage to your K3s cluster:
```bash
kubectl apply -k k8s/
```
## Configuration
The configuration includes:
- **Namespace**: `homepage` namespace with service account
- **RBAC**: ClusterRole with permissions to read cluster resources
- **ConfigMap**: Pre-configured with widgets for K3s monitoring
- **Deployment**: Secure deployment with resource limits and health checks
- **Service**: ClusterIP service on port 3000
- **Ingress**: Traefik-compatible ingress with TLS support
## Access
After deployment, Homepage will be available at:
- HTTP: `http://sortifal.fr`
- HTTPS: `https://sortifal.fr` (with cert-manager)
Ensure your DNS points `sortifal.fr` to your K3s ingress IP.
## Customization
### Update Configuration
Edit the ConfigMap in `k8s/configmap.yaml` to customize:
- **services.yaml**: Your applications and services
- **bookmarks.yaml**: Quick links and bookmarks
- **widgets.yaml**: Dashboard widgets (cluster info, resources, etc.)
- **settings.yaml**: Theme, layout, and provider settings
Apply changes:
```bash
kubectl apply -k k8s/
kubectl rollout restart deployment/homepage -n homepage
```
### Change Domain
Update `sortifal.fr` in `k8s/ingress.yaml` and the `HOMEPAGE_ALLOWED_HOSTS` environment variable in `k8s/deployment.yaml`.
### Resource Limits
Adjust CPU/memory limits in `k8s/deployment.yaml` based on your needs.
## Monitoring
Homepage includes widgets for monitoring your K3s cluster:
- Cluster CPU and memory usage
- Node status and resources
- Pod information across namespaces
- System resources
## Troubleshooting
Check deployment status:
```bash
kubectl get pods -n homepage
kubectl logs -n homepage deployment/homepage
```
Verify RBAC permissions:
```bash
kubectl auth can-i get nodes --as=system:serviceaccount:homepage:homepage
```
## Security
The configuration follows security best practices:
- Non-root container execution
- Read-only root filesystem where possible
- Minimal RBAC permissions
- Resource limits
- Security contexts
- Dropped capabilities

100
k8s/configmap.yaml Normal file
View File

@ -0,0 +1,100 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: homepage-config
namespace: homepage
labels:
app.kubernetes.io/name: homepage
data:
kubernetes.yaml: |
mode: cluster
settings.yaml: |
providers:
openweathermap: openweathermapapikey
weatherapi: weatherapiapikey
title: Dashboard
favicon: https://github.com/walkxcode/dashboard-icons/blob/main/png/homepage.png
theme: dark
color: slate
headerStyle: clean
layout:
My First Group:
style: row
columns: 3
My Second Group:
style: column
custom.css: ""
custom.js: ""
bookmarks.yaml: |
- Developer:
- Github:
- abbr: GH
href: https://github.com/
- Docker Hub:
- abbr: DH
href: https://hub.docker.com/
- Social:
- Reddit:
- abbr: RE
href: https://www.reddit.com/
services.yaml: |
- Infrastructure:
- Traefik:
href: http://traefik.local
description: Reverse Proxy & Load Balancer
icon: traefik.png
server: my-k3s
container: traefik
- Longhorn:
href: http://longhorn.local
description: Distributed Storage
icon: longhorn.png
- Monitoring:
- Grafana:
href: http://grafana.local
description: Analytics & Monitoring
icon: grafana.png
- Prometheus:
href: http://prometheus.local
description: Metrics Collection
icon: prometheus.png
- Applications:
- Nextcloud:
href: http://nextcloud.local
description: File Sharing & Collaboration
icon: nextcloud.png
- Jellyfin:
href: http://jellyfin.local
description: Media Server
icon: jellyfin.png
widgets.yaml: |
- kubernetes:
cluster:
show: true
cpu: true
memory: true
showLabel: true
label: "K3s Cluster"
nodes:
show: true
cpu: true
memory: true
showLabel: true
- resources:
backend: resources
expanded: true
cpu: true
memory: true
- datetime:
text_size: xl
format:
timeStyle: short
dateStyle: short
hourCycle: h23
- search:
provider: duckduckgo
target: _blank
showSearchSuggestions: true
docker.yaml: ""

110
k8s/deployment.yaml Normal file
View File

@ -0,0 +1,110 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: homepage
namespace: homepage
labels:
app.kubernetes.io/name: homepage
spec:
revisionHistoryLimit: 3
replicas: 1
strategy:
type: RollingUpdate
rollingUpdate:
maxUnavailable: 0
maxSurge: 1
selector:
matchLabels:
app.kubernetes.io/name: homepage
template:
metadata:
labels:
app.kubernetes.io/name: homepage
spec:
serviceAccountName: homepage
automountServiceAccountToken: true
dnsPolicy: ClusterFirst
enableServiceLinks: true
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
containers:
- name: homepage
image: "ghcr.io/gethomepage/homepage:latest"
imagePullPolicy: Always
securityContext:
allowPrivilegeEscalation: false
readOnlyRootFilesystem: false
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
capabilities:
drop:
- ALL
env:
- name: HOMEPAGE_ALLOWED_HOSTS
value: "sortifal.fr,localhost"
ports:
- name: http
containerPort: 3000
protocol: TCP
livenessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 30
periodSeconds: 10
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
readinessProbe:
httpGet:
path: /
port: http
initialDelaySeconds: 5
periodSeconds: 5
timeoutSeconds: 5
successThreshold: 1
failureThreshold: 3
resources:
limits:
cpu: 500m
memory: 512Mi
requests:
cpu: 100m
memory: 256Mi
volumeMounts:
- mountPath: /app/config/custom.js
name: homepage-config
subPath: custom.js
- mountPath: /app/config/custom.css
name: homepage-config
subPath: custom.css
- mountPath: /app/config/bookmarks.yaml
name: homepage-config
subPath: bookmarks.yaml
- mountPath: /app/config/docker.yaml
name: homepage-config
subPath: docker.yaml
- mountPath: /app/config/kubernetes.yaml
name: homepage-config
subPath: kubernetes.yaml
- mountPath: /app/config/services.yaml
name: homepage-config
subPath: services.yaml
- mountPath: /app/config/settings.yaml
name: homepage-config
subPath: settings.yaml
- mountPath: /app/config/widgets.yaml
name: homepage-config
subPath: widgets.yaml
- mountPath: /app/config/logs
name: logs
volumes:
- name: homepage-config
configMap:
name: homepage-config
- name: logs
emptyDir: {}

33
k8s/ingress.yaml Normal file
View File

@ -0,0 +1,33 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: homepage
namespace: homepage
labels:
app.kubernetes.io/name: homepage
annotations:
kubernetes.io/ingress.class: "traefik"
traefik.ingress.kubernetes.io/router.entrypoints: web,websecure
traefik.ingress.kubernetes.io/router.middlewares: default-redirect-https@kubernetescrd
cert-manager.io/cluster-issuer: "letsencrypt-prod"
gethomepage.dev/description: "Homepage Dashboard"
gethomepage.dev/enabled: "true"
gethomepage.dev/group: "Dashboard"
gethomepage.dev/icon: "homepage.png"
gethomepage.dev/name: "Homepage"
spec:
tls:
- hosts:
- sortifal.fr
secretName: homepage-tls
rules:
- host: "sortifal.fr"
http:
paths:
- path: "/"
pathType: Prefix
backend:
service:
name: homepage
port:
number: 3000

24
k8s/kustomization.yaml Normal file
View File

@ -0,0 +1,24 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: homepage
resources:
- namespace.yaml
- configmap.yaml
- rbac.yaml
- service.yaml
- deployment.yaml
- ingress.yaml
commonLabels:
app: homepage
version: v1.0.0
images:
- name: ghcr.io/gethomepage/homepage
newTag: latest
replicas:
- name: homepage
count: 1

14
k8s/namespace.yaml Normal file
View File

@ -0,0 +1,14 @@
apiVersion: v1
kind: Namespace
metadata:
name: homepage
labels:
app.kubernetes.io/name: homepage
---
apiVersion: v1
kind: ServiceAccount
metadata:
name: homepage
namespace: homepage
labels:
app.kubernetes.io/name: homepage

72
k8s/rbac.yaml Normal file
View File

@ -0,0 +1,72 @@
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRole
metadata:
name: homepage
labels:
app.kubernetes.io/name: homepage
rules:
- apiGroups:
- ""
resources:
- namespaces
- pods
- nodes
verbs:
- get
- list
- apiGroups:
- extensions
- networking.k8s.io
resources:
- ingresses
verbs:
- get
- list
- apiGroups:
- traefik.containo.us
- traefik.io
resources:
- ingressroutes
verbs:
- get
- list
- apiGroups:
- gateway.networking.k8s.io
resources:
- httproutes
- gateways
verbs:
- get
- list
- apiGroups:
- metrics.k8s.io
resources:
- nodes
- pods
verbs:
- get
- list
- apiGroups:
- apps
resources:
- deployments
- replicasets
- statefulsets
verbs:
- get
- list
---
apiVersion: rbac.authorization.k8s.io/v1
kind: ClusterRoleBinding
metadata:
name: homepage
labels:
app.kubernetes.io/name: homepage
roleRef:
apiGroup: rbac.authorization.k8s.io
kind: ClusterRole
name: homepage
subjects:
- kind: ServiceAccount
name: homepage
namespace: homepage

16
k8s/service.yaml Normal file
View File

@ -0,0 +1,16 @@
apiVersion: v1
kind: Service
metadata:
name: homepage
namespace: homepage
labels:
app.kubernetes.io/name: homepage
spec:
type: ClusterIP
ports:
- port: 3000
targetPort: http
protocol: TCP
name: http
selector:
app.kubernetes.io/name: homepage