This commit is contained in:
2025-08-14 22:11:27 -05:00
30 changed files with 893 additions and 74 deletions

View File

@@ -0,0 +1,33 @@
---
apiVersion: argoproj.io/v1alpha1
kind: Application
metadata:
name: homepage-app
finalizers:
- resources-finalizer.argocd.argoproj.io
annotations:
argocd.argoproj.io/sync-wave: "5"
spec:
destination:
name: internal
namespace: homepage-app
project: default
source:
path: applications/homepage
repoURL: https://github.com/rblundon/homelab.git
targetRevision: HEAD
syncPolicy:
automated:
prune: false
selfHeal: true
syncOptions:
- RespectIgnoreDifferences=true
- CreateNamespace=true
managedNamespaceMetadata:
labels:
argocd.argoproj.io/managed-by: openshift-gitops
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas

View File

@@ -0,0 +1,55 @@
---
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
resources:
- ingressroutes
verbs:
- get
- list
- apiGroups:
- metrics.k8s.io
resources:
- nodes
- pods
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-app

View File

@@ -0,0 +1,30 @@
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: homepage-bookmarks-secret
namespace: homepage-app
spec:
secretStoreRef:
kind: ClusterSecretStore
name: doppler-cluster
refreshInterval: "1h"
data:
- secretKey: bookmarks.yaml
remoteRef:
key: HOMEPAGE_BOOKMARKS
---
apiVersion: external-secrets.io/v1beta1
kind: ExternalSecret
metadata:
name: homepage-services-secret
namespace: homepage-app
spec:
secretStoreRef:
kind: ClusterSecretStore
name: doppler-cluster
refreshInterval: "1h"
data:
- secretKey: services.yaml
remoteRef:
key: HOMEPAGE_SERVICES

View File

@@ -0,0 +1,66 @@
---
apiVersion: v1
kind: ConfigMap
metadata:
name: homepage
namespace: homepage-app
labels:
app.kubernetes.io/name: homepage
data:
kubernetes.yaml: |
mode: cluster
settings.yaml: |
title: MK-Labs Homepage
background:
image: https://images.unsplash.com/photo-1502790671504-542ad42d5189?auto=format&fit=crop&w=2560&q=80
saturate: 100 # 0, 50, 100... see https://tailwindcss.com/docs/backdrop-saturate
brightness: 50 # 0, 50, 75... see https://tailwindcss.com/docs/backdrop-brightness
opacity: 100 # 0-100
theme: dark
color: slate
useEqualHeights: true
layout:
Proxmox:
header: true
style: row
columns: 4
Network:
header: true
style: row
columns: 4
Other:
header: true
style: row
columns: 4
providers:
openweathermap: openweathermapapikey
weatherapi: weatherapiapikey
custom.css: ""
custom.js: ""
widgets.yaml: |
- kubernetes:
cluster:
show: true
cpu: true
memory: true
showLabel: true
label: "cluster"
nodes:
show: true
cpu: true
memory: true
showLabel: true
- resources:
backend: resources
expanded: true
cpu: true
memory: true
- search:
provider: duckduckgo
target: _blank
docker.yaml: ""

View File

@@ -0,0 +1,84 @@
---
apiVersion: apps/v1
kind: Deployment
metadata:
name: homepage
namespace: homepage-app
labels:
app.kubernetes.io/name: homepage
spec:
revisionHistoryLimit: 3
replicas: 1
strategy:
type: RollingUpdate
selector:
matchLabels:
app.kubernetes.io/name: homepage
template:
metadata:
labels:
app.kubernetes.io/name: homepage
spec:
serviceAccountName: homepage
automountServiceAccountToken: true
dnsPolicy: ClusterFirst
enableServiceLinks: true
containers:
- name: homepage
image: "ghcr.io/gethomepage/homepage:latest"
imagePullPolicy: Always
env:
- name: HOMEPAGE_ALLOWED_HOSTS
value: "homepage.apps.openshift.int.mk-labs.cloud"
ports:
- name: http
containerPort: 3000
protocol: TCP
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: bookmarks
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: services
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
# - mountPath: /usr/local/etc/ssl/certs/tls.crt
# name: ssl-certs
# subPath: tls.crt
# - mountPath: /usr/local/etc/ssl/certs/tls.key
# name: ssl-certs
# subPath: tls.key
volumes:
- name: homepage-config
configMap:
name: homepage
- name: bookmarks
secret:
secretName: homepage-bookmarks-secret
- name: services
secret:
secretName: homepage-services-secret
# - name: ssl-certs
# secret:
# secretName: letsencrypt-homepage
- name: logs
emptyDir: {}

View File

@@ -0,0 +1,20 @@
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
annotations:
name: letsencrypt-homepage
namespace: homepage-app
spec:
commonName: 'homepage.int.mk-labs.cloud'
dnsNames:
- homepage.int.mk-labs.cloud
duration: 2160h0m0s
issuerRef:
kind: ClusterIssuer
name: letsencrypt-prod
renewBefore: 360h0m0s
secretName: letsencrypt-homepage
usages:
- server auth
- client auth

View File

@@ -0,0 +1,48 @@
---
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: homepage-ingress
namespace: homepage-app
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
nginx.ingress.kubernetes.io/force-ssl-redirect: "true"
spec:
ingressClassName: nginx
tls:
- hosts:
- homepage.int.mk-labs.cloud
secretName: letsencrypt-homepage
rules:
- host: homepage.int.mk-labs.cloud
http:
paths:
- path: /
pathType: Exact
backend:
service:
name: homepage-nginx
port:
number: 443
# tls:
# - hosts:
# - homepage.int.mk-labs.cloud
# secretName: letsencrypt-homepage
#---
#apiVersion: networking.k8s.io/v1
#kind: Ingress
#metadata:
# name: hello-openshift
#spec:
# rules:
# - host: hello-openshift.yourcluster.example.com
# http:
# paths:
# - backend:
# # Forward to a Service called 'hello-openshift'
# service:
# name: hello-openshift
# port:
# number: 8080
# path: /
# pathType: Exact

View File

@@ -0,0 +1,16 @@
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
resources:
- namespace.yaml
- secret.yaml
- serviceaccount.yaml
- configmap-eso.yaml
- configmap.yaml
- clusterrole.yaml
- service.yaml
#- ingress-certificate.yaml
- ingress.yaml
- deployment.yaml
- route.yaml

View File

@@ -0,0 +1,12 @@
---
apiVersion: v1
kind: Namespace
metadata:
labels:
kubernetes.io/metadata.name: homepage-app
name: homepage-app
argocd.argoproj.io/managed-by: openshift-gitops-operator
name: homepage-app
spec:
finalizers:
- kubernetes

View File

@@ -0,0 +1,46 @@
#---
#3apiVersion: route.openshift.io/v1
#kind: Route
#metadata:
# labels:
# app.kubernetes.io/instance: homepage-app
# app.kubernetes.io/name: homepage-app
# name: homepage-app
# namespace: homepage-app
#spec:
# host: homepage.int.mk-labs.cloud
# port:
# targetPort: http
# tls:
# insecureEdgeTerminationPolicy: Redirect
# termination: edge
# externalCertificate:
# name: letsencrypt-homepage
# to:
# kind: Service
# name: homepage
# weight: 100
# wildcardPolicy: None
---
apiVersion: route.openshift.io/v1
kind: Route
metadata:
labels:
app.kubernetes.io/instance: homepage-app
app.kubernetes.io/name: homepage-app
name: homepage-app2
namespace: homepage-app
spec:
host: homepage.apps.openshift.int.mk-labs.cloud
port:
targetPort: http
tls:
insecureEdgeTerminationPolicy: Redirect
termination: edge
to:
kind: Service
name: homepage
weight: 100
wildcardPolicy: None

View File

@@ -0,0 +1,11 @@
---
apiVersion: v1
kind: Secret
type: kubernetes.io/service-account-token
metadata:
name: homepage
namespace: homepage-app
labels:
app.kubernetes.io/name: homepage
annotations:
kubernetes.io/service-account.name: homepage

View File

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

View File

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

View File

@@ -0,0 +1,20 @@
---
apiVersion: cert-manager.io/v1
kind: Certificate
metadata:
annotations:
name: letsencrypt-homepage2
namespace: homepage-app
spec:
commonName: 'homepage2.int.mk-labs.cloud'
dnsNames:
- homepage2.int.mk-labs.cloud
duration: 2160h0m0s
issuerRef:
kind: ClusterIssuer
name: letsencrypt-prod
renewBefore: 360h0m0s
secretName: letsencrypt-homepage2
usages:
- server auth
- client auth

View File

@@ -6,9 +6,9 @@ commonAnnotations:
argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
resources:
- namespace.yaml
# Operator deployment
- subscription.yaml
# Deploy cluster resources
- scc.yaml
- namespace.yaml
- pvcs.yaml

View File

@@ -0,0 +1,100 @@
---
kind: NginxIngress
apiVersion: charts.nginx.org/v1alpha1
metadata:
name: nginx
namespace: nginx-ingress
spec:
routeSelector:
matchLabels:
type: nginx
controller:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app.kubernetes.io/instance: nginx
app.kubernetes.io/name: nginx
topologyKey: kubernetes.io/hostname
config:
entries:
http-snippets: proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=static-cache:10m
max_size=10g inactive=60m use_temp_path=off;
log-format-escaping: json
log-format: |-
{
"msec": "$msec",
"connection": "$connection",
"connection_requests": "$connection_requests",
"pid": "$pid",
"request_id": "$request_id",
"request_length": "$request_length",
"remote_addr": "$remote_addr",
"remote_user": "$remote_user",
"remote_port": "$remote_port",
"time_local": "$time_local",
"time_iso8601": "$time_iso8601",
"request": "$request",
"request_uri": "$request_uri",
"args": "$args",
"status": "$status",
"body_bytes_sent": "$body_bytes_sent",
"bytes_sent": "$bytes_sent",
"http_referer": "$http_referer",
"http_user_agent": "$http_user_agent",
"http_x_forwarded_for": "$http_x_forwarded_for",
"http_host": "$http_host",
"server_name": "$server_name",
"request_time": "$request_time",
"upstream": "$upstream_addr",
"upstream_connect_time": "$upstream_connect_time",
"upstream_header_time": "$upstream_header_time",
"upstream_response_time": "$upstream_response_time",
"upstream_response_length": "$upstream_response_length",
"upstream_cache_status": "$upstream_cache_status",
"ssl_protocol": "$ssl_protocol",
"ssl_cipher": "$ssl_cipher",
"scheme": "$scheme",
"request_method": "$request_method",
"server_protocol": "$server_protocol",
"pipe": "$pipe",
"gzip_ratio": "$gzip_ratio",
"http_cf_ray": "$http_cf_ray"
}
enableCustomResources: true
enableTLSPassthrough: true
enableSnippets: true
image:
pullPolicy: IfNotPresent
repository: nginx/nginx-ingress
tag: 5.1.0-ubi
ingressClass:
create: true
name: nginx
setAsDefaultIngress: false
initContainerResources:
requests:
cpu: 100m
memory: 128Mi
replicaCount: 2
reportIngressStatus:
annotations: {}
enable: true
enableLeaderElection: true
ingressLink: ''
leaderElectionLockName: nginx-ingress-leader
service:
externalTrafficPolicy: Local
loadBalancerIP: 10.1.82.0
prometheus:
create: true
serviceMonitor:
create: true
volumes:
- name: nginx-cache
persistentVolumeClaim:
claimName: nginx-cache
volumeMounts:
- name: nginx-cache
mountPath: /var/cache/nginx

View File

@@ -1,96 +1,175 @@
---
kind: NginxIngress
apiVersion: charts.nginx.org/v1alpha1
kind: NginxIngress
metadata:
name: nginx
namespace: nginx-ingress
spec:
routeSelector:
matchLabels:
type: nginx
controller:
affinity:
podAntiAffinity:
requiredDuringSchedulingIgnoredDuringExecution:
- labelSelector:
matchLabels:
app.kubernetes.io/instance: nginx
app.kubernetes.io/name: nginx
topologyKey: kubernetes.io/hostname
affinity: {}
annotations: {}
appprotect:
enable: false
appprotectdos:
debug: false
enable: false
maxDaemons: 0
maxWorkers: 0
memory: 0
autoscaling:
annotations: {}
behavior: {}
enabled: false
maxReplicas: 3
minReplicas: 1
targetCPUUtilizationPercentage: 50
targetMemoryUtilizationPercentage: 50
config:
entries:
http-snippets: proxy_cache_path /tmp/nginx_cache levels=1:2 keys_zone=static-cache:10m
max_size=10g inactive=60m use_temp_path=off;
log-format-escaping: json
log-format: |-
{
"msec": "$msec",
"connection": "$connection",
"connection_requests": "$connection_requests",
"pid": "$pid",
"request_id": "$request_id",
"request_length": "$request_length",
"remote_addr": "$remote_addr",
"remote_user": "$remote_user",
"remote_port": "$remote_port",
"time_local": "$time_local",
"time_iso8601": "$time_iso8601",
"request": "$request",
"request_uri": "$request_uri",
"args": "$args",
"status": "$status",
"body_bytes_sent": "$body_bytes_sent",
"bytes_sent": "$bytes_sent",
"http_referer": "$http_referer",
"http_user_agent": "$http_user_agent",
"http_x_forwarded_for": "$http_x_forwarded_for",
"http_host": "$http_host",
"server_name": "$server_name",
"request_time": "$request_time",
"upstream": "$upstream_addr",
"upstream_connect_time": "$upstream_connect_time",
"upstream_header_time": "$upstream_header_time",
"upstream_response_time": "$upstream_response_time",
"upstream_response_length": "$upstream_response_length",
"upstream_cache_status": "$upstream_cache_status",
"ssl_protocol": "$ssl_protocol",
"ssl_cipher": "$ssl_cipher",
"scheme": "$scheme",
"request_method": "$request_method",
"server_protocol": "$server_protocol",
"pipe": "$pipe",
"gzip_ratio": "$gzip_ratio",
"http_cf_ray": "$http_cf_ray"
}
annotations: {}
entries: {}
containerPort:
http: 80
https: 443
customConfigMap: ''
customPorts: []
defaultHTTPListenerPort: 80
defaultHTTPSListenerPort: 443
defaultTLS:
cert: ''
key: ''
secret: ''
disableIPV6: false
dnsPolicy: ClusterFirst
enableCertManager: false
enableCustomResources: true
enableTLSPassthrough: true
enableSnippets: true
enableExternalDNS: false
enableLatencyMetrics: false
enableOIDC: false
enableSSLDynamicReload: true
enableSnippets: false
enableTLSPassthrough: false
env: []
extraContainers: []
globalConfiguration:
create: false
spec: {}
healthStatus: false
healthStatusURI: /nginx-health
hostNetwork: false
hostPort:
enable: false
http: 80
https: 443
image:
pullPolicy: IfNotPresent
repository: nginx/nginx-ingress
tag: 3.7.0-ubi
tag: 5.1.0-ubi
ingressClass:
create: true
name: nginx
setAsDefaultIngress: false
replicaCount: 2
initContainerResources:
requests:
cpu: 100m
memory: 128Mi
initContainers: []
lifecycle: {}
logFormat: glog
logLevel: info
mgmt:
licenseTokenSecretName: license-token
minReadySeconds: 0
name: controller
nginxDebug: false
nginxReloadTimeout: 60000
nginxStatus:
allowCidrs: 127.0.0.1
enable: true
port: 8080
nginxplus: false
pod:
annotations: {}
extraLabels: {}
podDisruptionBudget:
annotations: {}
enabled: false
readOnlyRootFilesystem: false
readyStatus:
enable: true
initialDelaySeconds: 0
port: 8081
replicaCount: 1
reportIngressStatus:
annotations: {}
enable: true
enableLeaderElection: true
ingressLink: ''
leaderElectionLockName: ingress-leader
leaderElectionLockName: nginx-ingress-leader
resources:
requests:
cpu: 100m
memory: 128Mi
selectorLabels: {}
service:
annotations: {}
clusterIP: ''
create: true
customPorts: []
externalIPs: []
externalTrafficPolicy: Local
# loadBalancerIP: 10.1.82.2
extraLabels: {}
httpPort:
enable: true
port: 80
targetPort: 80
httpsPort:
enable: true
port: 443
targetPort: 443
loadBalancerIP: 10.1.82.0
loadBalancerSourceRanges: []
type: LoadBalancer
serviceAccount:
annotations: {}
imagePullSecretName: ''
imagePullSecretsNames: []
shareProcessNamespace: false
strategy: {}
terminationGracePeriodSeconds: 30
tlsPassthroughPort: 443
tolerations: []
volumeMounts: []
volumes: []
watchNamespace: ''
watchNamespaceLabel: ''
watchSecretNamespace: ''
wildcardTLS:
cert: ''
key: ''
secret: ''
kind: deployment
nginxServiceMesh:
enable: false
enableEgress: false
prometheus:
create: true
port: 9113
scheme: http
secret: ''
service:
create: false
labels:
service: nginx-ingress-prometheus-service
serviceMonitor:
create: false
endpoints:
- port: prometheus
labels: {}
selectorMatchLabels:
service: nginx-ingress-prometheus-service
rbac:
create: true
volumes:
- name: nginx-cache
persistentVolumeClaim:
claimName: nginx-cache
volumeMounts:
- name: nginx-cache
mountPath: /var/cache/nginx
serviceInsight:
create: false
port: 9114
scheme: http
secret: ''

View File

@@ -0,0 +1,46 @@
---
apiVersion: argoproj.io/v1alpha1
kind: ApplicationSet
metadata:
name: metallb-operator
namespace: openshift-gitops
finalizers:
- resources-finalizer.argocd.argoproj.io
spec:
goTemplate: true
goTemplateOptions: ["missingkey=error"]
generators:
# - clusters: {} # Variable is .name
- list: # Variable is .cluster
elements:
- cluster: internal
template:
metadata:
name: '{{.cluster}}-metallb-operator'
annotations:
argocd.argoproj.io/sync-wave: "2"
spec:
destination:
name: '{{.cluster}}'
namespace: metallb-system
project: default
source:
path: cluster/metallb-operator/overlays/{{.cluster}}
repoURL: https://github.com/rblundon/homelab.git
targetRevision: HEAD
syncPolicy:
automated:
prune: true
selfHeal: true
syncOptions:
- RespectIgnoreDifferences=true
- CreateNamespace=true
managedNamespaceMetadata:
labels:
argocd.argoproj.io/managed-by: argocd
ignoreDifferences:
- group: apps
kind: Deployment
jsonPointers:
- /spec/replicas

View File

@@ -0,0 +1,11 @@
---
apiVersion: metallb.io/v1beta1
kind: BGPAdvertisement
metadata:
name: bgp-advert
namespace: metallb-system
spec:
aggregationLength: 32
aggregationLengthV6: 128
ipAddressPools:
- bgp-ip-addresspool

View File

@@ -0,0 +1,15 @@
---
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
commonAnnotations:
argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
resources:
# Operator deployment
- namespace.yaml
- subscription.yaml
- operatorgroup.yaml
# Deploy cluster resources
- metallb.yaml
- bgp_advertisement.yaml

View File

@@ -0,0 +1,7 @@
---
apiVersion: metallb.io/v1beta1
kind: MetalLB
metadata:
name: metallb
namespace: metallb-system
spec: {}

View File

@@ -0,0 +1,13 @@
---
apiVersion: v1
kind: Namespace
metadata:
labels:
kubernetes.io/metadata.name: metallb-system
name: metallb-system
argocd.argoproj.io/managed-by: openshift-gitops-operator
openshift.io/cluster-monitoring: 'true'
name: metallb-system
spec:
finalizers:
- kubernetes

View File

@@ -0,0 +1,9 @@
---
apiVersion: operators.coreos.com/v1
kind: OperatorGroup
metadata:
name: metallb-operator
namespace: metallb-system
#spec:
# targetNamespaces:
# - metallb-system

View File

@@ -0,0 +1,12 @@
---
apiVersion: operators.coreos.com/v1alpha1
kind: Subscription
metadata:
name: metallb-operator
namespace: metallb-system
spec:
channel: stable
installPlanApproval: Automatic #Manual
name: metallb-operator
source: redhat-operators
sourceNamespace: openshift-marketplace

View File

@@ -0,0 +1,12 @@
---
apiVersion: metallb.io/v1beta2
kind: BGPPeer
metadata:
name: bgp-peer-worlddrive
namespace: metallb-system
spec:
disableMP: false
myASN: 65003
peerASN: 65002
peerAddress: 10.1.71.1
peerPort: 179

View File

@@ -0,0 +1,12 @@
---
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: bgp-ip-addresspool
namespace: metallb-system
spec:
addresses:
- 10.1.182.0/24
autoAssign: true
avoidBuggyIPs: false

View File

@@ -0,0 +1,12 @@
---
apiVersion: metallb.io/v1beta2
kind: BGPPeer
metadata:
name: bgp-peer-worlddrive
namespace: metallb-system
spec:
disableMP: false
myASN: 65001
peerASN: 65002
peerAddress: 10.1.71.1
peerPort: 179

View File

@@ -0,0 +1,12 @@
---
apiVersion: metallb.io/v1beta1
kind: IPAddressPool
metadata:
name: bgp-ip-addresspool
namespace: metallb-system
spec:
addresses:
- 10.1.82.0/24
autoAssign: true
avoidBuggyIPs: false

View File

@@ -0,0 +1,10 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
commonAnnotations:
argocd.argoproj.io/sync-options: SkipDryRunOnMissingResource=true
resources:
- ../../base
- bgp_peer.yaml
- ip_addresspool.yaml