commit 41feffb123d353ff990cde4cd2d74f632db71dd3 Author: Morten Olsen Date: Thu Sep 25 20:57:46 2025 +0200 init diff --git a/charts/apps/AGENT.md b/charts/apps/AGENT.md new file mode 100644 index 0000000..e94f2e0 --- /dev/null +++ b/charts/apps/AGENT.md @@ -0,0 +1,136 @@ +# Agent Documentation + +This document describes how to create a new application chart for the homelab operator. + +## Chart Structure + +Each application has its own chart located in a directory under `charts/apps`. The chart should contain the following files: + +- `Chart.yaml`: The chart metadata. +- `values.yaml`: The default values for the chart. +- `templates/`: A directory containing the Kubernetes resource templates. + +## Custom Resources + +The homelab operator uses several custom resources to manage applications. These resources are defined in the `templates` directory of the chart. + +### `PostgresDatabase` + +If the application requires a PostgreSQL database, you can create a `PostgresDatabase` resource. The operator will automatically create a database and a secret containing the connection details. The secret will have the same name as the release with a `-pg-connection` postfix. + +Example: + +```yaml +# templates/database.yaml +apiVersion: homelab.mortenolsen.pro/v1 +kind: PostgresDatabase +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" +``` + +The secret has the following values: + +- `database`: name of the created database +- `host`: the hostname of the postgres server +- `port`: the port of the postgres server +- `url`: combined url in the format `postgresql://{user}:{password}@{host}:{port}/{database}` + +### `OidcClient` + +If the application requires OIDC authentication, you can create an `OidcClient` resource. The operator will automatically create an OIDC client and a secret containing the client ID and secret. The secret will have the same name as the release with a `-client` postfix. + +You need to specify the redirect URIs for the OIDC client. The subdomain is taken from the `values.yaml` file. + +Example: + +```yaml +# templates/client.yaml +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + redirectUris: + - path: /user/oauth2/Authentik/callback + subdomain: "{{ .Values.subdomain }}" + matchingMode: strict +``` + +The secret has the following value: + +- `authorization`: Authorization endpoint +- `clientId` +- `clientSecret` +- `configuration`: autodiscovery endpoint +- `configurationIssuer`: issuer url +- `endSession`: end session endpoint +- `jwks`: jwks endpoint +- `token`: token endpoint +- `userinfo`: user info endpoint + +### `HttpService` and `ExternalHttpService` + +To expose the application, you can use either an `HttpService` or an `ExternalHttpService` resource. + +- `HttpService`: This will expose the application through the Istio gateway. This is for internal access only. +- `ExternalHttpService`: This will expose the application through a CloudFlare tunnel. This is for external access. + +Both resources take a `subdomain` and a `destination` as parameters. The `destination` is the Kubernetes service to route traffic to. + +Example of `HttpService`: + +```yaml +# templates/http-service.yaml +apiVersion: homelab.mortenolsen.pro/v1 +kind: HttpService +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + subdomain: "{{ .Values.subdomain }}" + destination: + host: "{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local" + port: + number: 80 +``` + +Example of `ExternalHttpService`: + +```yaml +# templates/external-http-service.yaml +apiVersion: homelab.mortenolsen.pro/v1 +kind: ExternalHttpService +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + subdomain: "{{ .Values.subdomain }}" + destination: + host: "{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local" + port: + number: 80 +``` + +## `values.yaml` + +The `values.yaml` file should contain the following values: + +- `globals.environment`: The environment the application is running in (e.g., `prod`, `dev`). +- `image.repository`: The Docker image repository. +- `image.tag`: The Docker image tag. +- `subdomain`: The subdomain for the application. + +Example: + +```yaml +# values.yaml +globals: + environment: prod +image: + repository: docker.gitea.com/gitea + tag: latest +subdomain: gitea +``` diff --git a/charts/apps/apprise/Chart.yaml b/charts/apps/apprise/Chart.yaml new file mode 100644 index 0000000..d54ee22 --- /dev/null +++ b/charts/apps/apprise/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: apprise diff --git a/charts/apps/apprise/templates/client.yaml b/charts/apps/apprise/templates/client.yaml new file mode 100644 index 0000000..8299b34 --- /dev/null +++ b/charts/apps/apprise/templates/client.yaml @@ -0,0 +1,10 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + redirectUris: + - path: /oauth/oidc/callback + subdomain: '{{ .Values.subdomain }}' + matchingMode: strict diff --git a/charts/apps/apprise/templates/deployment.yaml b/charts/apps/apprise/templates/deployment.yaml new file mode 100644 index 0000000..9544d6e --- /dev/null +++ b/charts/apps/apprise/templates/deployment.yaml @@ -0,0 +1,43 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + containers: + - name: "{{ .Release.Name }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + ports: + - name: http + containerPort: 8000 + protocol: TCP + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + env: + - name: TZ + value: "{{ .Values.globals.timezone }}" + - name: BASE_URL + value: https://{{ .Values.subdomain }}.{{ .Values.globals.domain }} + volumeMounts: + - mountPath: /config + name: data + + volumes: + - name: data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-data" diff --git a/charts/apps/apprise/templates/http-service.yaml b/charts/apps/apprise/templates/http-service.yaml new file mode 100644 index 0000000..15b1989 --- /dev/null +++ b/charts/apps/apprise/templates/http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: HttpService +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + subdomain: "{{ .Values.subdomain }}" + destination: + host: "{{ .Release.Name }}" + port: + number: 80 diff --git a/charts/apps/apprise/templates/pvc.yaml b/charts/apps/apprise/templates/pvc.yaml new file mode 100644 index 0000000..bc1d0a6 --- /dev/null +++ b/charts/apps/apprise/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-data' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/apps/apprise/templates/service.yaml b/charts/apps/apprise/templates/service.yaml new file mode 100644 index 0000000..f7001fc --- /dev/null +++ b/charts/apps/apprise/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 8000 + protocol: TCP + name: http + selector: + app: "{{ .Release.Name }}" diff --git a/charts/apps/apprise/values.yaml b/charts/apps/apprise/values.yaml new file mode 100644 index 0000000..e3c9f2e --- /dev/null +++ b/charts/apps/apprise/values.yaml @@ -0,0 +1,9 @@ +globals: + environment: prod + timezone: Europe/Amsterdam + domain: olsen.cloud +image: + repository: docker.io/caronc/apprise + tag: latest@sha256:127b3834f0679502529397ead8ffeaadf5189019c4c863fa6652e9b942fdccf8 + pullPolicy: IfNotPresent +subdomain: apprise diff --git a/charts/apps/audiobookshelf/Chart.yaml b/charts/apps/audiobookshelf/Chart.yaml new file mode 100644 index 0000000..b6db4d9 --- /dev/null +++ b/charts/apps/audiobookshelf/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: audiobookshelf diff --git a/charts/apps/audiobookshelf/templates/client.yaml b/charts/apps/audiobookshelf/templates/client.yaml new file mode 100644 index 0000000..6f94876 --- /dev/null +++ b/charts/apps/audiobookshelf/templates/client.yaml @@ -0,0 +1,13 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + redirectUris: + - path: /audiobookshelf/auth/openid/callback + subdomain: '{{ .Values.subdomain }}' + matchingMode: strict + - path: /audiobookshelf/auth/openid/mobile-redirect + subdomain: '{{ .Values.subdomain }}' + matchingMode: strict diff --git a/charts/apps/audiobookshelf/templates/deployment.yaml b/charts/apps/audiobookshelf/templates/deployment.yaml new file mode 100644 index 0000000..119a656 --- /dev/null +++ b/charts/apps/audiobookshelf/templates/deployment.yaml @@ -0,0 +1,52 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: '{{ .Release.Name }}' +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: '{{ .Release.Name }}' + template: + metadata: + labels: + app: '{{ .Release.Name }}' + spec: + containers: + - name: '{{ .Release.Name }}' + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' + imagePullPolicy: '{{ .Values.image.pullPolicy }}' + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + volumeMounts: + - mountPath: /config + name: config + - mountPath: /metadata + name: metadata + - mountPath: /audiobooks + name: audiobooks + - mountPath: /podcasts + name: podcasts + volumes: + - name: config + persistentVolumeClaim: + claimName: '{{ .Release.Name }}-config' + - name: metadata + persistentVolumeClaim: + claimName: '{{ .Release.Name }}-metadata' + - name: audiobooks + persistentVolumeClaim: + claimName: books + - name: podcasts + persistentVolumeClaim: + claimName: podcasts diff --git a/charts/apps/audiobookshelf/templates/external-http-service.yaml b/charts/apps/audiobookshelf/templates/external-http-service.yaml new file mode 100644 index 0000000..e28916d --- /dev/null +++ b/charts/apps/audiobookshelf/templates/external-http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: ExternalHttpService +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + subdomain: '{{ .Values.subdomain }}' + destination: + host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local' + port: + number: 80 diff --git a/charts/apps/audiobookshelf/templates/pvc.yaml b/charts/apps/audiobookshelf/templates/pvc.yaml new file mode 100644 index 0000000..14c9293 --- /dev/null +++ b/charts/apps/audiobookshelf/templates/pvc.yaml @@ -0,0 +1,24 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-config' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' + +--- +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-metadata' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/apps/audiobookshelf/templates/service.yaml b/charts/apps/audiobookshelf/templates/service.yaml new file mode 100644 index 0000000..ac45675 --- /dev/null +++ b/charts/apps/audiobookshelf/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: '{{ .Release.Name }}' + labels: + app: '{{ .Release.Name }}' +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 80 + protocol: TCP + name: http + selector: + app: '{{ .Release.Name }}' diff --git a/charts/apps/audiobookshelf/values.yaml b/charts/apps/audiobookshelf/values.yaml new file mode 100644 index 0000000..f41fe62 --- /dev/null +++ b/charts/apps/audiobookshelf/values.yaml @@ -0,0 +1,7 @@ +globals: + environment: prod +image: + repository: ghcr.io/advplyr/audiobookshelf + tag: 2.29.0@sha256:dd4a3079d26bfe9f0ea63de3e3eff483dfa25fef05ef850a5a9d121dca3794b2 + pullPolicy: IfNotPresent +subdomain: audiobookshelf diff --git a/charts/apps/baikal/Chart.yaml b/charts/apps/baikal/Chart.yaml new file mode 100644 index 0000000..b06614b --- /dev/null +++ b/charts/apps/baikal/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: esphome diff --git a/charts/apps/baikal/templates/database.yaml b/charts/apps/baikal/templates/database.yaml new file mode 100644 index 0000000..6a30b53 --- /dev/null +++ b/charts/apps/baikal/templates/database.yaml @@ -0,0 +1,6 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: PostgresDatabase +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' diff --git a/charts/apps/baikal/templates/deployment.yaml b/charts/apps/baikal/templates/deployment.yaml new file mode 100644 index 0000000..a661d1a --- /dev/null +++ b/charts/apps/baikal/templates/deployment.yaml @@ -0,0 +1,46 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + containers: + - name: "{{ .Release.Name }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + ports: + - name: http + containerPort: 80 + protocol: TCP + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + env: + - name: TZ + value: "{{ .Values.globals.timezone }}" + volumeMounts: + - mountPath: /var/www/baikal/Specific + name: data + - mountPath: /var/www/baikal/config + name: config + + volumes: + - name: data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-data" + - name: config + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-config" diff --git a/charts/apps/baikal/templates/external-http-service.yaml b/charts/apps/baikal/templates/external-http-service.yaml new file mode 100644 index 0000000..e28916d --- /dev/null +++ b/charts/apps/baikal/templates/external-http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: ExternalHttpService +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + subdomain: '{{ .Values.subdomain }}' + destination: + host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local' + port: + number: 80 diff --git a/charts/apps/baikal/templates/http-service.yaml b/charts/apps/baikal/templates/http-service.yaml new file mode 100644 index 0000000..15b1989 --- /dev/null +++ b/charts/apps/baikal/templates/http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: HttpService +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + subdomain: "{{ .Values.subdomain }}" + destination: + host: "{{ .Release.Name }}" + port: + number: 80 diff --git a/charts/apps/baikal/templates/pvc.yaml b/charts/apps/baikal/templates/pvc.yaml new file mode 100644 index 0000000..a7bd546 --- /dev/null +++ b/charts/apps/baikal/templates/pvc.yaml @@ -0,0 +1,24 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: "{{ .Release.Name }}-data" +spec: + accessModes: + - "ReadWriteOnce" + resources: + requests: + storage: "1Gi" + storageClassName: "{{ .Values.globals.environment }}" + +--- +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: "{{ .Release.Name }}-config" +spec: + accessModes: + - "ReadWriteOnce" + resources: + requests: + storage: "1Gi" + storageClassName: "{{ .Values.globals.environment }}" diff --git a/charts/apps/baikal/templates/service.yaml b/charts/apps/baikal/templates/service.yaml new file mode 100644 index 0000000..98872d7 --- /dev/null +++ b/charts/apps/baikal/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 80 + protocol: TCP + name: http + selector: + app: "{{ .Release.Name }}" diff --git a/charts/apps/baikal/values.yaml b/charts/apps/baikal/values.yaml new file mode 100644 index 0000000..4839125 --- /dev/null +++ b/charts/apps/baikal/values.yaml @@ -0,0 +1,9 @@ +globals: + environment: prod + timezone: Europe/Amsterdam + domain: olsen.cloud +image: + repository: docker.io/ckulka/baikal + tag: nginx@sha256:045918423df00a3f9ec793a819b9acdb055d338b75387926b7d93d753ac1e93a + pullPolicy: IfNotPresent +subdomain: baikal diff --git a/charts/apps/bytestash/Chart.yaml b/charts/apps/bytestash/Chart.yaml new file mode 100644 index 0000000..8bc957b --- /dev/null +++ b/charts/apps/bytestash/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: ByteStash diff --git a/charts/apps/bytestash/templates/client.yaml b/charts/apps/bytestash/templates/client.yaml new file mode 100644 index 0000000..60befa2 --- /dev/null +++ b/charts/apps/bytestash/templates/client.yaml @@ -0,0 +1,10 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + redirectUris: + - path: /api/auth/oidc/callback + subdomain: '{{ .Values.subdomain }}' + matchingMode: strict diff --git a/charts/apps/bytestash/templates/deployment.yaml b/charts/apps/bytestash/templates/deployment.yaml new file mode 100644 index 0000000..c86fe3f --- /dev/null +++ b/charts/apps/bytestash/templates/deployment.yaml @@ -0,0 +1,54 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + containers: + - name: "{{ .Release.Name }}" + image: ghcr.io/jordan-dalby/bytestash:latest + ports: + - containerPort: 5000 + name: http + env: + - name: ALLOW_NEW_ACCOUNTS + value: "true" + - name: DISABLE_INTERNAL_ACCOUNTS + value: "true" + - name: OIDC_ENABLED + value: "true" + - name: OIDC_DISPLAY_NAME + value: OIDC + - name: OIDC_CLIENT_ID + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: clientId + - name: OIDC_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: clientSecret + - name: OIDC_ISSUER_URL + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: configurationIssuer + + volumeMounts: + - mountPath: /data/snippets + name: data + volumes: + - name: data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-data" diff --git a/charts/apps/bytestash/templates/external-http-service.yaml b/charts/apps/bytestash/templates/external-http-service.yaml new file mode 100644 index 0000000..e28916d --- /dev/null +++ b/charts/apps/bytestash/templates/external-http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: ExternalHttpService +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + subdomain: '{{ .Values.subdomain }}' + destination: + host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local' + port: + number: 80 diff --git a/charts/apps/bytestash/templates/http-service.yaml b/charts/apps/bytestash/templates/http-service.yaml new file mode 100644 index 0000000..a57b37d --- /dev/null +++ b/charts/apps/bytestash/templates/http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: HttpService +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.environment }}' + subdomain: '{{ .Values.subdomain }}' + destination: + host: '{{ .Release.Name }}' + port: + number: 80 diff --git a/charts/apps/bytestash/templates/pvc.yaml b/charts/apps/bytestash/templates/pvc.yaml new file mode 100644 index 0000000..bc1d0a6 --- /dev/null +++ b/charts/apps/bytestash/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-data' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/apps/bytestash/templates/service.yaml b/charts/apps/bytestash/templates/service.yaml new file mode 100644 index 0000000..b8bedd6 --- /dev/null +++ b/charts/apps/bytestash/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: '{{ .Release.Name }}' + labels: + app: '{{ .Release.Name }}' +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 5000 + protocol: TCP + name: http + selector: + app: '{{ .Release.Name }}' diff --git a/charts/apps/bytestash/values.yaml b/charts/apps/bytestash/values.yaml new file mode 100644 index 0000000..a9a2b59 --- /dev/null +++ b/charts/apps/bytestash/values.yaml @@ -0,0 +1,3 @@ +globals: + environment: prod +subdomain: bytestash diff --git a/charts/apps/calibre-web/Chart.yaml b/charts/apps/calibre-web/Chart.yaml new file mode 100644 index 0000000..81961cb --- /dev/null +++ b/charts/apps/calibre-web/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: calibre-web diff --git a/charts/apps/calibre-web/templates/client.yaml b/charts/apps/calibre-web/templates/client.yaml new file mode 100644 index 0000000..60befa2 --- /dev/null +++ b/charts/apps/calibre-web/templates/client.yaml @@ -0,0 +1,10 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + redirectUris: + - path: /api/auth/oidc/callback + subdomain: '{{ .Values.subdomain }}' + matchingMode: strict diff --git a/charts/apps/calibre-web/templates/deployment.yaml b/charts/apps/calibre-web/templates/deployment.yaml new file mode 100644 index 0000000..c22a5a2 --- /dev/null +++ b/charts/apps/calibre-web/templates/deployment.yaml @@ -0,0 +1,42 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + containers: + - name: "{{ .Release.Name }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + ports: + - containerPort: 8083 + name: http + env: + - name: TZ + value: "{{ .Values.globals.timezone }}" + - name: PUID + value: "1000" + - name: PGID + value: "1000" + volumeMounts: + - mountPath: /config + name: data + - mountPath: /books + name: books + volumes: + - name: data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-data" + - name: books + persistentVolumeClaim: + claimName: books diff --git a/charts/apps/calibre-web/templates/external-http-service.yaml b/charts/apps/calibre-web/templates/external-http-service.yaml new file mode 100644 index 0000000..e28916d --- /dev/null +++ b/charts/apps/calibre-web/templates/external-http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: ExternalHttpService +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + subdomain: '{{ .Values.subdomain }}' + destination: + host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local' + port: + number: 80 diff --git a/charts/apps/calibre-web/templates/http-service.yaml b/charts/apps/calibre-web/templates/http-service.yaml new file mode 100644 index 0000000..15b1989 --- /dev/null +++ b/charts/apps/calibre-web/templates/http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: HttpService +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + subdomain: "{{ .Values.subdomain }}" + destination: + host: "{{ .Release.Name }}" + port: + number: 80 diff --git a/charts/apps/calibre-web/templates/pvc.yaml b/charts/apps/calibre-web/templates/pvc.yaml new file mode 100644 index 0000000..bc1d0a6 --- /dev/null +++ b/charts/apps/calibre-web/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-data' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/apps/calibre-web/templates/service.yaml b/charts/apps/calibre-web/templates/service.yaml new file mode 100644 index 0000000..75b8c54 --- /dev/null +++ b/charts/apps/calibre-web/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 8083 + protocol: TCP + name: http + selector: + app: "{{ .Release.Name }}" diff --git a/charts/apps/calibre-web/values.yaml b/charts/apps/calibre-web/values.yaml new file mode 100644 index 0000000..6a49a3c --- /dev/null +++ b/charts/apps/calibre-web/values.yaml @@ -0,0 +1,9 @@ +globals: + environment: prod + domain: olsen.cloud + timezone: Europe/Amsterdam +image: + repository: lscr.io/linuxserver/calibre-web + tag: latest@sha256:98a20064168ab284bbb8e048af48c89a5e25650f35a4b217705241af94c1debe + pullPolicy: IfNotPresent +subdomain: calibre-web diff --git a/charts/apps/coder/Chart.yaml b/charts/apps/coder/Chart.yaml new file mode 100644 index 0000000..5b46cef --- /dev/null +++ b/charts/apps/coder/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: openwebui diff --git a/charts/apps/coder/templates/client.yaml b/charts/apps/coder/templates/client.yaml new file mode 100644 index 0000000..f931eac --- /dev/null +++ b/charts/apps/coder/templates/client.yaml @@ -0,0 +1,10 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + redirectUris: + - path: /api/v2/users/oidc/callback + subdomain: '{{ .Values.subdomain }}' + matchingMode: strict diff --git a/charts/apps/coder/templates/deployment.yaml b/charts/apps/coder/templates/deployment.yaml new file mode 100644 index 0000000..910ed4e --- /dev/null +++ b/charts/apps/coder/templates/deployment.yaml @@ -0,0 +1,73 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: '{{ .Release.Name }}' +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: '{{ .Release.Name }}' + template: + metadata: + labels: + app: '{{ .Release.Name }}' + spec: + serviceAccountName: '{{ .Release.Name }}-serviceaccount' + containers: + - name: '{{ .Release.Name }}' + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' + imagePullPolicy: '{{ .Values.image.pullPolicy }}' + ports: + - name: http + containerPort: 7080 + protocol: TCP + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + volumeMounts: + - mountPath: /home/coder/.config + name: data + env: + - name: CODER_HTTP_ADDRESS + value: '0.0.0.0:7080' + - name: CODER_OIDC_ALLOWED_GROUPS + value: admin + - name: CODER_OIDC_GROUP_FIELD + value: groups + - name: CODER_ACCESS_URL + value: https://coder.olsen.cloud + - name: CODER_OIDC_ICON_URL + value: https://authentik.olsen.cloud/static/dist/assets/icons/icon.png + - name: CODER_DISABLE_PASSWORD_AUTH + value: 'true' + - name: CODER_OAUTH2_GITHUB_ALLOW_SIGNUPS + value: 'false' + - name: CODER_OIDC_SIGN_IN_TEXT + value: 'Sign in with OIDC' + - name: CODER_OIDC_SCOPES + value: openid,profile,email,offline_access + - name: CODER_OIDC_ISSUER_URL + valueFrom: + secretKeyRef: + name: '{{ .Release.Name }}-client' + key: configurationIssuer + - name: CODER_OIDC_CLIENT_ID + valueFrom: + secretKeyRef: + name: '{{ .Release.Name }}-client' + key: clientId + - name: CODER_OIDC_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: '{{ .Release.Name }}-client' + key: clientSecret + + volumes: + - name: data + persistentVolumeClaim: + claimName: '{{ .Release.Name }}-data' diff --git a/charts/apps/coder/templates/http-service.yaml b/charts/apps/coder/templates/http-service.yaml new file mode 100644 index 0000000..2233b00 --- /dev/null +++ b/charts/apps/coder/templates/http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: HttpService +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + subdomain: '{{ .Values.subdomain }}' + destination: + host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local' + port: + number: 80 diff --git a/charts/apps/coder/templates/pvc.yaml b/charts/apps/coder/templates/pvc.yaml new file mode 100644 index 0000000..bc1d0a6 --- /dev/null +++ b/charts/apps/coder/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-data' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/apps/coder/templates/role.yaml b/charts/apps/coder/templates/role.yaml new file mode 100644 index 0000000..5724980 --- /dev/null +++ b/charts/apps/coder/templates/role.yaml @@ -0,0 +1,21 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRole +metadata: + name: '{{ .Release.Name }}-workspace-creator' +rules: + - apiGroups: [''] # "" indicates the core API group (for Pods, PVCs, Services) + resources: ['pods', 'pods/exec', 'pods/log', 'persistentvolumeclaims', 'services'] + verbs: ['get', 'list', 'watch', 'create', 'update', 'patch', 'delete'] + - apiGroups: ['apps'] # For Deployments, StatefulSets + resources: ['deployments', 'statefulsets'] + verbs: ['get', 'list', 'watch', 'create', 'update', 'patch', 'delete'] + - apiGroups: ['networking.k8s.io'] # For Ingresses + resources: ['ingresses'] + verbs: ['get', 'list', 'watch', 'create', 'update', 'patch', 'delete'] + - apiGroups: ['events.k8s.io'] # For events related to workspace activity + resources: ['events'] + verbs: ['create', 'patch', 'update'] # Coder might create events for workspace lifecycle + # Add any other resources that Coder workspace templates might create (e.g., secrets, configmaps) + # - apiGroups: [""] + # resources: ["secrets", "configmaps"] + # verbs: ["get", "list", "watch", "create", "update", "patch", "delete"] diff --git a/charts/apps/coder/templates/rolebinding.yaml b/charts/apps/coder/templates/rolebinding.yaml new file mode 100644 index 0000000..3354a26 --- /dev/null +++ b/charts/apps/coder/templates/rolebinding.yaml @@ -0,0 +1,13 @@ +apiVersion: rbac.authorization.k8s.io/v1 +kind: ClusterRoleBinding +metadata: + name: '{{ .Release.Name }}-workspace-creator-binding' + namespace: '{{ .Release.Namespace }}' +subjects: + - kind: ServiceAccount + name: '{{ .Release.Name }}-serviceaccount' + namespace: '{{ .Release.Namespace }}' +roleRef: + kind: ClusterRole + name: '{{ .Release.Name }}-workspace-creator' + apiGroup: rbac.authorization.k8s.io diff --git a/charts/apps/coder/templates/service.yaml b/charts/apps/coder/templates/service.yaml new file mode 100644 index 0000000..ca4d3c5 --- /dev/null +++ b/charts/apps/coder/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: '{{ .Release.Name }}' + labels: + app: '{{ .Release.Name }}' +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 7080 + protocol: TCP + name: http + selector: + app: '{{ .Release.Name }}' diff --git a/charts/apps/coder/templates/serviceaccount.yaml b/charts/apps/coder/templates/serviceaccount.yaml new file mode 100644 index 0000000..53966e4 --- /dev/null +++ b/charts/apps/coder/templates/serviceaccount.yaml @@ -0,0 +1,5 @@ +apiVersion: v1 +kind: ServiceAccount +metadata: + name: '{{ .Release.Name }}-serviceaccount' + namespace: '{{ .Release.Namespace }}' diff --git a/charts/apps/coder/values.yaml b/charts/apps/coder/values.yaml new file mode 100644 index 0000000..69b7bbc --- /dev/null +++ b/charts/apps/coder/values.yaml @@ -0,0 +1,7 @@ +globals: + environment: prod +image: + repository: ghcr.io/coder/coder + tag: latest@sha256:73714e0685addde01bbff905cf5b647d6b677d77977c8009b6293d40fdf0f562 + pullPolicy: IfNotPresent +subdomain: coder diff --git a/charts/apps/data/Chart.yaml b/charts/apps/data/Chart.yaml new file mode 100644 index 0000000..339c647 --- /dev/null +++ b/charts/apps/data/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: data diff --git a/charts/apps/data/templates/database.yaml b/charts/apps/data/templates/database.yaml new file mode 100644 index 0000000..6a30b53 --- /dev/null +++ b/charts/apps/data/templates/database.yaml @@ -0,0 +1,6 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: PostgresDatabase +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' diff --git a/charts/apps/data/values.yaml b/charts/apps/data/values.yaml new file mode 100644 index 0000000..d005bde --- /dev/null +++ b/charts/apps/data/values.yaml @@ -0,0 +1,2 @@ +globals: + environment: prod diff --git a/charts/apps/esphome/Chart.yaml b/charts/apps/esphome/Chart.yaml new file mode 100644 index 0000000..b06614b --- /dev/null +++ b/charts/apps/esphome/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: esphome diff --git a/charts/apps/esphome/templates/deployment.yaml b/charts/apps/esphome/templates/deployment.yaml new file mode 100644 index 0000000..86e0b7e --- /dev/null +++ b/charts/apps/esphome/templates/deployment.yaml @@ -0,0 +1,42 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + hostNetwork: true + containers: + - name: "{{ .Release.Name }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + ports: + - name: http + containerPort: 6052 + protocol: TCP + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + env: + - name: TZ + value: "{{ .Values.globals.timezone }}" + volumeMounts: + - mountPath: /config + name: data + + volumes: + - name: data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-data" diff --git a/charts/apps/esphome/templates/http-service.yaml b/charts/apps/esphome/templates/http-service.yaml new file mode 100644 index 0000000..15b1989 --- /dev/null +++ b/charts/apps/esphome/templates/http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: HttpService +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + subdomain: "{{ .Values.subdomain }}" + destination: + host: "{{ .Release.Name }}" + port: + number: 80 diff --git a/charts/apps/esphome/templates/pvc.yaml b/charts/apps/esphome/templates/pvc.yaml new file mode 100644 index 0000000..bc1d0a6 --- /dev/null +++ b/charts/apps/esphome/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-data' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/apps/esphome/templates/service.yaml b/charts/apps/esphome/templates/service.yaml new file mode 100644 index 0000000..48d3c5a --- /dev/null +++ b/charts/apps/esphome/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 6052 + protocol: TCP + name: http + selector: + app: "{{ .Release.Name }}" diff --git a/charts/apps/esphome/values.yaml b/charts/apps/esphome/values.yaml new file mode 100644 index 0000000..2ee4135 --- /dev/null +++ b/charts/apps/esphome/values.yaml @@ -0,0 +1,9 @@ +globals: + environment: prod + timezone: Europe/Amsterdam + domain: olsen.cloud +image: + repository: ghcr.io/esphome/esphome + tag: latest@sha256:67f4df2206af244e79c6c624ea7ef27be572f83af981657b1ac1ffa0d7b8487a + pullPolicy: IfNotPresent +subdomain: esphome diff --git a/charts/apps/gitea/Chart.yaml b/charts/apps/gitea/Chart.yaml new file mode 100644 index 0000000..2027869 --- /dev/null +++ b/charts/apps/gitea/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: gitea diff --git a/charts/apps/gitea/templates/_runner-deployment.yaml b/charts/apps/gitea/templates/_runner-deployment.yaml new file mode 100644 index 0000000..9973799 --- /dev/null +++ b/charts/apps/gitea/templates/_runner-deployment.yaml @@ -0,0 +1,36 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: '{{ .Release.Name }}-runner' + labels: + app: '{{ .Release.Name }}-runner' +spec: + replicas: 1 + selector: + matchLabels: + app: '{{ .Release.Name }}-runner' + template: + metadata: + labels: + app: '{{ .Release.Name }}-runner' + spec: + containers: + - name: '{{ .Release.Name }}-runner' + image: docker.io/gitea/act_runner:latest-dind-rootless + env: + - name: GITEA_INSTANCE_URL + value: '{{ .Release.Name }}' + - name: GITEA_RUNNER_NAME + - name: GITEA_RUNNER_REGISTRATION_TOKEN + valueFrom: + secretKeyRef: + name: '{{ .Release.Name }}-runner' + key: registration_token + - name: DOCKER_HOST + value: tcp://localhost:2376 + - name: DOCKER_CERT_PATH + value: /certs/client + - name: DOCKER_TLS_VERIFY + value: '1' + securityContext: + privileged: true diff --git a/charts/apps/gitea/templates/client.yaml b/charts/apps/gitea/templates/client.yaml new file mode 100644 index 0000000..3f4410c --- /dev/null +++ b/charts/apps/gitea/templates/client.yaml @@ -0,0 +1,10 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + redirectUris: + - path: /user/oauth2/Authentik/callback + subdomain: '{{ .Values.subdomain }}' + matchingMode: strict diff --git a/charts/apps/gitea/templates/database.yaml b/charts/apps/gitea/templates/database.yaml new file mode 100644 index 0000000..6a30b53 --- /dev/null +++ b/charts/apps/gitea/templates/database.yaml @@ -0,0 +1,6 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: PostgresDatabase +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' diff --git a/charts/apps/gitea/templates/deployment.yaml b/charts/apps/gitea/templates/deployment.yaml new file mode 100644 index 0000000..b0e8788 --- /dev/null +++ b/charts/apps/gitea/templates/deployment.yaml @@ -0,0 +1,103 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + containers: + - name: "{{ .Release.Name }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + ports: + - name: http + containerPort: 3000 + protocol: TCP + - name: ssh + containerPort: 22 + protocol: TCP + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + volumeMounts: + - mountPath: /data + name: data + env: + - name: TZ + value: "{{ .Values.globals.timezone }}" + - name: USER_UID + value: "1000" + - name: USER_GID + value: "1000" + - name: GITEA__server__SSH_DOMAIN + value: ssh-gitea.olsen.cloud + - name: GITEA__server__SSH_PORT + value: "2205" + - name: GITEA__service__REQUIRE_EXTERNAL_REGISTRATION_PASSWORD + value: "true" + #- name: GITEA__service__ENABLE_BASIC_AUTHENTICATION + # value: 'true' + - name: GITEA__service__ENABLE_PASSWORD_SIGNIN_FORM + value: "false" + - name: GITEA__service__DEFAULT_KEEP_EMAIL_PRIVATE + value: "true" + - name: GITEA__service__DEFAULT_USER_IS_RESTRICTED + value: "true" + - name: GITEA__service__DEFAULT_USER_VISIBILITY + value: "private" + - name: GITEA__service__DEFAULT_ORG_VISIBILITY + value: "private" + - name: GITEA__service__ALLOW_ONLY_EXTERNAL_REGISTRATION + value: "true" + - name: GITEA__other__SHOW_FOOTER_POWERED_BY + value: "false" + - name: GITEA__other__SHOW_FOOTER_TEMPLATE_LOAD_TIME + value: "false" + - name: GITEA__other__SHOW_FOOTER_VERSION + value: "false" + - name: GITEA__repository__ENABLE_PUSH_CREATE_USER + value: "true" + - name: GITEA__repository__ENABLE_PUSH_CREATE_ORG + value: "true" + - name: GITEA__openid__ENABLE_OPENID_SIGNIN + value: "false" + - name: GITEA__openid__ENABLE_OPENID_SIGNUP + value: "false" + - name: GITEA__database__DB_TYPE + value: postgres + - name: GITEA__database__NAME + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-pg-connection" + key: database + - name: GITEA__database__HOST + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-pg-connection" + key: host + - name: GITEA__database__USER + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-pg-connection" + key: user + - name: GITEA__database__PASSWD + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-pg-connection" + key: password + volumes: + - name: data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-data" diff --git a/charts/apps/gitea/templates/external-http-service.yaml b/charts/apps/gitea/templates/external-http-service.yaml new file mode 100644 index 0000000..e28916d --- /dev/null +++ b/charts/apps/gitea/templates/external-http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: ExternalHttpService +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + subdomain: '{{ .Values.subdomain }}' + destination: + host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local' + port: + number: 80 diff --git a/charts/apps/gitea/templates/pvc.yaml b/charts/apps/gitea/templates/pvc.yaml new file mode 100644 index 0000000..bc1d0a6 --- /dev/null +++ b/charts/apps/gitea/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-data' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/apps/gitea/templates/service.yaml b/charts/apps/gitea/templates/service.yaml new file mode 100644 index 0000000..1c09f6d --- /dev/null +++ b/charts/apps/gitea/templates/service.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 3000 + protocol: TCP + name: http + selector: + app: "{{ .Release.Name }}" + +--- +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}-ssh" + labels: + app: "{{ .Release.Name }}" +spec: + type: LoadBalancer + ports: + - port: 2205 + targetPort: 22 + protocol: TCP + name: ssh + selector: + app: "{{ .Release.Name }}" diff --git a/charts/apps/gitea/values.yaml b/charts/apps/gitea/values.yaml new file mode 100644 index 0000000..e8b0241 --- /dev/null +++ b/charts/apps/gitea/values.yaml @@ -0,0 +1,8 @@ +globals: + environment: prod + timezone: Europe/Amsterdam +image: + repository: docker.gitea.com/gitea + tag: latest@sha256:2edc102cbb636ae1ddac5fa0c715aa5b03079dee13ac6800b2cef6d4e912e718 + pullPolicy: IfNotPresent +subdomain: gitea diff --git a/charts/apps/headscale/Chart.yaml b/charts/apps/headscale/Chart.yaml new file mode 100644 index 0000000..01287f5 --- /dev/null +++ b/charts/apps/headscale/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: headscale diff --git a/charts/apps/headscale/templates/client.yaml b/charts/apps/headscale/templates/client.yaml new file mode 100644 index 0000000..7401edd --- /dev/null +++ b/charts/apps/headscale/templates/client.yaml @@ -0,0 +1,10 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + redirectUris: + - path: /oidc/callback + subdomain: '{{ .Values.subdomain }}' + matchingMode: strict diff --git a/charts/apps/headscale/templates/config-map.yaml b/charts/apps/headscale/templates/config-map.yaml new file mode 100644 index 0000000..3906380 --- /dev/null +++ b/charts/apps/headscale/templates/config-map.yaml @@ -0,0 +1,70 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: '{{ .Release.Name }}-config-template' +data: + config.yaml.template: | + server_url: ${PUBLIC_URL} + listen_addr: 0.0.0.0:8080 + metrics_listen_addr: 0.0.0.0:9090 + grpc_listen_addr: 0.0.0.0:50443 + + private_key_path: /var/lib/headscale/private_key # Path inside the container + + noise: + private_key_path: /var/lib/headscale/noise_private_key # Path inside the container + + listen_routes: false + base_domain: "${PUBLIC_URL}" # For client routes and DNS push. + + derp: + server: + enabled: false + region_id: 999 + region_code: "headscale" + region_name: "Headscale Embedded DERP" + stun_listen_addr: "0.0.0.0:3478" + automatically_add_embedded_derp_region: true + urls: + - https://controlplane.tailscale.com/derpmap/default + auto_update_enabled: true + update_frequency: 24h + + oidc: + enabled: true + only_start_if_oidc_is_available: true + issuer: "${OIDC_ISSUER_URL}" + client_id: "${OIDC_CLIENT_ID}" + client_secret: "${OIDC_CLIENT_SECRET}" + scopes: ["openid", "profile", "email"] + redirect_url: "${PUBLIC_URL}/oidc/callback" + pkce: + enabled: true + method: S256 + + + # DNS configuration + dns: + magic_dns: false + override_local_dns: true # Push Headscale's DNS settings to clients + ttl: 60 + nameservers: + global: + - 1.1.1.1 # Cloudflare DNS + #- 10.43.0.10 # Replace with your ClusterIP for kube-dns/CoreDNS + # Domains to search for (e.g., for Kubernetes services) + search_domains: + - svc.cluster.local + - cluster.local + + auto_create_users: true + + oidc_user_property: preferred_username # Or 'email' or 'sub' + + prefixes: + v4: 10.20.20.0/24 # Example: A /24 subnet for your VPN clients + + database: + type: sqlite + sqlite: + path: /var/lib/headscale/db.sqlite diff --git a/charts/apps/headscale/templates/deployment.yaml b/charts/apps/headscale/templates/deployment.yaml new file mode 100644 index 0000000..5fe4a05 --- /dev/null +++ b/charts/apps/headscale/templates/deployment.yaml @@ -0,0 +1,97 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: '{{ .Release.Name }}' + labels: + app: '{{ .Release.Name }}' +spec: + replicas: 1 + selector: + matchLabels: + app: '{{ .Release.Name }}' + template: + metadata: + labels: + app: '{{ .Release.Name }}' + spec: + # To expose WireGuard UDP directly, we need a NodePort service. + # The Pod needs to be aware of the external port it's being exposed on. + # The easiest way to get WireGuard to listen on the correct port and make it + # externally accessible is to use `hostNetwork: true` for the UDP component, + # or by directly specifying the listen port in Headscale config if the NodePort is stable. + + # OPTION 1: Best for simple homelab on bare metal where host network traffic isn't an issue + # hostNetwork: true # This makes the pod listen directly on the node's IPs + # dnsPolicy: ClusterFirstWithHostNet # Required if using hostNetwork + + initContainers: + - name: generate-config + image: alpine/git # A small image with 'envsubst' available or easily installable + imagePullPolicy: IfNotPresent + command: ['sh', '-c'] + args: + - | + # Install envsubst if it's not present (alpine/git may not have it by default) + apk update && apk add bash gettext + + # Substitute environment variables into the template + # The vars are passed via `env` section below + envsubst < /config-template/config.yaml.template > /etc/headscale/config.yaml + + mkdir -p /etc/headscale + # Optional: Verify the generated config + echo "--- Generated Headscale Configuration ---" + cat /etc/headscale/config.yaml + echo "---------------------------------------" + env: + # These are the variables that `envsubst` will look for and replace + - name: PUBLIC_URL + value: 'https://{{ .Values.subdomain }}.olsen.cloud' + - name: OIDC_ISSUER_URL + valueFrom: + secretKeyRef: + name: '{{ .Release.Name }}-client' + key: configurationIssuer + - name: OIDC_CLIENT_ID + valueFrom: + secretKeyRef: + name: '{{ .Release.Name }}-client' + key: clientId + - name: OIDC_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: '{{ .Release.Name }}-client' + key: clientSecret + # Add any other variables used in config.yaml.template here + volumeMounts: + - name: config-template + mountPath: /config-template # Mount the ConfigMap as a volume + readOnly: true + - name: headscale-config + mountPath: /etc/headscale # Destination for the generated config + + containers: + - name: '{{ .Release.Name }}' + image: headscale/headscale:latest # Use the official image + command: ['headscale', 'serve'] + ports: + - name: http-api + containerPort: 8080 + protocol: TCP + - name: wireguard-udp + containerPort: 41641 + protocol: UDP + volumeMounts: + - name: headscale-data + mountPath: /var/lib/headscale + - name: headscale-config + mountPath: /etc/headscale + volumes: + - name: config-template + configMap: + name: '{{ .Release.Name }}-config-template' + - name: headscale-config + emptyDir: {} + - name: headscale-data + persistentVolumeClaim: + claimName: '{{ .Release.Name }}-data' diff --git a/charts/apps/headscale/templates/external-http-service.yaml b/charts/apps/headscale/templates/external-http-service.yaml new file mode 100644 index 0000000..e28916d --- /dev/null +++ b/charts/apps/headscale/templates/external-http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: ExternalHttpService +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + subdomain: '{{ .Values.subdomain }}' + destination: + host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local' + port: + number: 80 diff --git a/charts/apps/headscale/templates/pvc.yaml b/charts/apps/headscale/templates/pvc.yaml new file mode 100644 index 0000000..bc1d0a6 --- /dev/null +++ b/charts/apps/headscale/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-data' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/apps/headscale/templates/service.yaml b/charts/apps/headscale/templates/service.yaml new file mode 100644 index 0000000..6f98962 --- /dev/null +++ b/charts/apps/headscale/templates/service.yaml @@ -0,0 +1,32 @@ +apiVersion: v1 +kind: Service +metadata: + name: '{{ .Release.Name }}' + labels: + app: '{{ .Release.Name }}' +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 8080 + protocol: TCP + name: http + selector: + app: '{{ .Release.Name }}' + +--- +apiVersion: v1 +kind: Service +metadata: + name: '{{ .Release.Name }}-headscale' + labels: + app: '{{ .Release.Name }}' +spec: + type: LoadBalancer + ports: + - port: 41641 + targetPort: 41641 + protocol: UDP + name: wireguard-udp + selector: + app: '{{ .Release.Name }}' diff --git a/charts/apps/headscale/values.yaml b/charts/apps/headscale/values.yaml new file mode 100644 index 0000000..1afb3f9 --- /dev/null +++ b/charts/apps/headscale/values.yaml @@ -0,0 +1,7 @@ +globals: + environment: prod +image: + repository: headscale/headscale + tag: latest@sha256:ea9b5ee06274d757a4d52103de56cd11a9c393acb19d9a35f4b9fe52ada410de + pullPolicy: IfNotPresent +subdomain: headscale diff --git a/charts/apps/homarr/Chart.yaml b/charts/apps/homarr/Chart.yaml new file mode 100644 index 0000000..5b46cef --- /dev/null +++ b/charts/apps/homarr/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: openwebui diff --git a/charts/apps/homarr/templates/client.yaml b/charts/apps/homarr/templates/client.yaml new file mode 100644 index 0000000..747fe09 --- /dev/null +++ b/charts/apps/homarr/templates/client.yaml @@ -0,0 +1,10 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + redirectUris: + - path: /api/auth/callback/oidc + subdomain: "{{ .Values.subdomain }}" + matchingMode: strict diff --git a/charts/apps/homarr/templates/deployment.yaml b/charts/apps/homarr/templates/deployment.yaml new file mode 100644 index 0000000..5824df6 --- /dev/null +++ b/charts/apps/homarr/templates/deployment.yaml @@ -0,0 +1,83 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + containers: + - name: "{{ .Release.Name }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + ports: + - name: http + containerPort: 7575 + protocol: TCP + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + volumeMounts: + - mountPath: /appdata + name: data + env: + - name: BASE_URL + value: https://homarr.olsen.cloud # TODO + + - name: NEXTAUTH_URL + value: https://homarr.olsen.cloud + + - name: AUTH_PROVIDERS + value: oidc + + - name: AUTH_OIDC_CLIENT_NAME + value: Authentik + + - name: AUTH_OIDC_SCOPE_OVERWRITE + value: openid email profile + + - name: AUTH_OIDC_GROUPS_ATTRIBUTE + value: groups + + - name: AUTH_OIDC_AUTO_LOGIN + value: "true" + + - name: SECRET_ENCRYPTION_KEY + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-secrets" + key: encryptionkey + + - name: AUTH_OIDC_ISSUER + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: configurationIssuer + + - name: AUTH_OIDC_CLIENT_ID + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: clientId + + - name: AUTH_OIDC_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: clientSecret + + volumes: + - name: data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-data" diff --git a/charts/apps/homarr/templates/external-http-service.yaml b/charts/apps/homarr/templates/external-http-service.yaml new file mode 100644 index 0000000..e28916d --- /dev/null +++ b/charts/apps/homarr/templates/external-http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: ExternalHttpService +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + subdomain: '{{ .Values.subdomain }}' + destination: + host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local' + port: + number: 80 diff --git a/charts/apps/homarr/templates/http-service.yaml b/charts/apps/homarr/templates/http-service.yaml new file mode 100644 index 0000000..89df8bf --- /dev/null +++ b/charts/apps/homarr/templates/http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: HttpService +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + subdomain: "{{ .Values.subdomain }}" + destination: + host: "{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local" + port: + number: 80 diff --git a/charts/apps/homarr/templates/pvc.yaml b/charts/apps/homarr/templates/pvc.yaml new file mode 100644 index 0000000..bc1d0a6 --- /dev/null +++ b/charts/apps/homarr/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-data' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/apps/homarr/templates/secret.yaml b/charts/apps/homarr/templates/secret.yaml new file mode 100644 index 0000000..d086249 --- /dev/null +++ b/charts/apps/homarr/templates/secret.yaml @@ -0,0 +1,9 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: GenerateSecret +metadata: + name: "{{ .Release.Name }}-secrets" +spec: + fields: + - name: encryptionkey + encoding: hex + length: 64 diff --git a/charts/apps/homarr/templates/service.yaml b/charts/apps/homarr/templates/service.yaml new file mode 100644 index 0000000..73dd8e9 --- /dev/null +++ b/charts/apps/homarr/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 7575 + protocol: TCP + name: http + selector: + app: "{{ .Release.Name }}" diff --git a/charts/apps/homarr/values.yaml b/charts/apps/homarr/values.yaml new file mode 100644 index 0000000..d76648e --- /dev/null +++ b/charts/apps/homarr/values.yaml @@ -0,0 +1,7 @@ +globals: + environment: prod +image: + repository: ghcr.io/homarr-labs/homarr + tag: latest@sha256:9ba9831d43347b6d66143a0754c97b9790a2ffe9bdf5004083668864b3328e65 + pullPolicy: IfNotPresent +subdomain: homarr diff --git a/charts/apps/home-assistant/Chart.yaml b/charts/apps/home-assistant/Chart.yaml new file mode 100644 index 0000000..a245983 --- /dev/null +++ b/charts/apps/home-assistant/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: home-assistant diff --git a/charts/apps/home-assistant/templates/client.yaml b/charts/apps/home-assistant/templates/client.yaml new file mode 100644 index 0000000..6b913fd --- /dev/null +++ b/charts/apps/home-assistant/templates/client.yaml @@ -0,0 +1,10 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + redirectUris: + - path: /auth/openid/callback + subdomain: "{{ .Values.subdomain }}" + matchingMode: strict diff --git a/charts/apps/home-assistant/templates/deployment.yaml b/charts/apps/home-assistant/templates/deployment.yaml new file mode 100644 index 0000000..682edcf --- /dev/null +++ b/charts/apps/home-assistant/templates/deployment.yaml @@ -0,0 +1,45 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + hostNetwork: true + dnsPolicy: ClusterFirstWithHostNet + + containers: + - name: "{{ .Release.Name }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + env: + - name: TZ + value: "{{ .Values.globals.timezone }}" + ports: + - name: http + containerPort: 8123 + protocol: TCP + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + volumeMounts: + - mountPath: /config + name: config + securityContext: + privileged: true + volumes: + - name: config + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-config" diff --git a/charts/apps/home-assistant/templates/external-http-service.yaml b/charts/apps/home-assistant/templates/external-http-service.yaml new file mode 100644 index 0000000..f865728 --- /dev/null +++ b/charts/apps/home-assistant/templates/external-http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: ExternalHttpService +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + subdomain: "{{ .Values.subdomain }}" + destination: + host: "{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local" + port: + number: 80 diff --git a/charts/apps/home-assistant/templates/http-service.yaml b/charts/apps/home-assistant/templates/http-service.yaml new file mode 100644 index 0000000..89df8bf --- /dev/null +++ b/charts/apps/home-assistant/templates/http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: HttpService +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + subdomain: "{{ .Values.subdomain }}" + destination: + host: "{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local" + port: + number: 80 diff --git a/charts/apps/home-assistant/templates/piper.yaml b/charts/apps/home-assistant/templates/piper.yaml new file mode 100644 index 0000000..18cd69a --- /dev/null +++ b/charts/apps/home-assistant/templates/piper.yaml @@ -0,0 +1,59 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}-piper" +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}-piper" + template: + metadata: + labels: + app: "{{ .Release.Name }}-piper" + spec: + hostNetwork: true + + containers: + - name: "{{ .Release.Name }}-piper" + image: "{{ .Values.piper.image.repository }}:{{ .Values.piper.image.tag }}" + imagePullPolicy: "{{ .Values.piper.image.pullPolicy }}" + args: + - --piper + - /usr/share/piper/piper + - --data-dir + - /usr/share/piper-voices + - --voice + - "{{ .Values.piper.model }}" + env: + - name: TZ + value: "{{ .Values.globals.timezone }}" + ports: + - name: http + containerPort: 10200 + protocol: TCP + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + +--- +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}-piper" + labels: + app: "{{ .Release.Name }}-piper" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 10200 + protocol: TCP + name: http + selector: + app: "{{ .Release.Name }}-piper" diff --git a/charts/apps/home-assistant/templates/pvc.yaml b/charts/apps/home-assistant/templates/pvc.yaml new file mode 100644 index 0000000..8cbd0b4 --- /dev/null +++ b/charts/apps/home-assistant/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: "{{ .Release.Name }}-config" +spec: + accessModes: + - "ReadWriteOnce" + resources: + requests: + storage: "1Gi" + storageClassName: "{{ .Values.globals.environment }}" diff --git a/charts/apps/home-assistant/templates/service.yaml b/charts/apps/home-assistant/templates/service.yaml new file mode 100644 index 0000000..2e04e50 --- /dev/null +++ b/charts/apps/home-assistant/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 8123 + protocol: TCP + name: http + selector: + app: "{{ .Release.Name }}" diff --git a/charts/apps/home-assistant/templates/whisper.yaml b/charts/apps/home-assistant/templates/whisper.yaml new file mode 100644 index 0000000..4f394e8 --- /dev/null +++ b/charts/apps/home-assistant/templates/whisper.yaml @@ -0,0 +1,57 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}-whisper" +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}-whisper" + template: + metadata: + labels: + app: "{{ .Release.Name }}-whisper" + spec: + hostNetwork: true + + containers: + - name: "{{ .Release.Name }}-whisper" + image: "{{ .Values.whisper.image.repository }}:{{ .Values.whisper.image.tag }}" + imagePullPolicy: "{{ .Values.whisper.image.pullPolicy }}" + args: + - --model + - "{{ .Values.whisper.model }}" + - --language + - "{{ .Values.whisper.language }}" + env: + - name: TZ + value: "{{ .Values.globals.timezone }}" + ports: + - name: http + containerPort: 10300 + protocol: TCP + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + +--- +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}-whisper" + labels: + app: "{{ .Release.Name }}-whisper" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 10300 + protocol: TCP + name: http + selector: + app: "{{ .Release.Name }}-whisper" diff --git a/charts/apps/home-assistant/values.yaml b/charts/apps/home-assistant/values.yaml new file mode 100644 index 0000000..1307b1f --- /dev/null +++ b/charts/apps/home-assistant/values.yaml @@ -0,0 +1,21 @@ +globals: + environment: prod + timezone: Europe/Amsterdam +image: + repository: ghcr.io/home-assistant/home-assistant + tag: stable@sha256:89ec0583c7f47c8a150204f6b5ed48b5432026012bebe1226cf72775a795a5e1 + pullPolicy: IfNotPresent +subdomain: home-assistant +piper: + image: + repository: ghcr.io/morten-olsen/glados-voice + tag: main@sha256:8fcc19bd9e7e846bdfd9e9e569c8c944dcfb1d0b47e3f479cbaa7f5587c7206c + pullPolicy: Always + model: en_US-glados-medium +whisper: + image: + repository: rhasspy/wyoming-whisper + tag: latest@sha256:f03456914affe8076fc7688c0890f4c708d93ebfac7340b0b2467f721412012d + pullPolicy: IfNotPresent + model: tiny-int8 + language: us diff --git a/charts/apps/install.sh b/charts/apps/install.sh new file mode 100755 index 0000000..3c72038 --- /dev/null +++ b/charts/apps/install.sh @@ -0,0 +1,12 @@ +set -euo pipefail + +find . -name "values.yaml" -type f -print0 | while IFS= read -r -d '' values_file; do + location=$(dirname "$values_file") + name=$(basename "$location") + name=$(echo "$name" | tr '[:upper:]' '[:lower:]' | tr -s '[:punct:][:space:]' '-' | sed -e 's/^-*//' -e 's/-*$//') + + echo "✅ Chart found in: $location" + echo " - Generated release name: $name" + HELM_COMMAND="helm install --namespace prod \"$name\" \"$location\"" + helm upgrade -i --namespace prod "$name" "$location" +done diff --git a/charts/apps/jellyfin/Chart.yaml b/charts/apps/jellyfin/Chart.yaml new file mode 100644 index 0000000..333b29f --- /dev/null +++ b/charts/apps/jellyfin/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: Jellyfin diff --git a/charts/apps/jellyfin/notes.md b/charts/apps/jellyfin/notes.md new file mode 100644 index 0000000..41b4c17 --- /dev/null +++ b/charts/apps/jellyfin/notes.md @@ -0,0 +1 @@ +https://www.authelia.com/integration/openid-connect/clients/jellyfin/ diff --git a/charts/apps/jellyfin/templates/client.yaml b/charts/apps/jellyfin/templates/client.yaml new file mode 100644 index 0000000..a8509cb --- /dev/null +++ b/charts/apps/jellyfin/templates/client.yaml @@ -0,0 +1,10 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.environment }}' + redirectUris: + - path: /sso/OID/redirect/Authentik + subdomain: '{{ .Values.globals.subdomain }}' + matchingMode: strict diff --git a/charts/apps/jellyfin/templates/config-pvc.yaml b/charts/apps/jellyfin/templates/config-pvc.yaml new file mode 100644 index 0000000..8cbd0b4 --- /dev/null +++ b/charts/apps/jellyfin/templates/config-pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: "{{ .Release.Name }}-config" +spec: + accessModes: + - "ReadWriteOnce" + resources: + requests: + storage: "1Gi" + storageClassName: "{{ .Values.globals.environment }}" diff --git a/charts/apps/jellyfin/templates/deployment.yaml b/charts/apps/jellyfin/templates/deployment.yaml new file mode 100644 index 0000000..a221d8d --- /dev/null +++ b/charts/apps/jellyfin/templates/deployment.yaml @@ -0,0 +1,52 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: '{{ .Release.Name }}' +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: '{{ .Release.Name }}' + template: + metadata: + labels: + app: '{{ .Release.Name }}' + spec: + containers: + - name: '{{ .Release.Name }}' + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' + imagePullPolicy: '{{ .Values.image.pullPolicy }}' + ports: + - name: http + containerPort: 8096 + protocol: TCP + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + volumeMounts: + - mountPath: /config + name: config + - mountPath: /media/movies + name: movies + - mountPath: /media/tv-shows + name: tvshows + - mountPath: /media/music + name: music + volumes: + - name: config + persistentVolumeClaim: + claimName: '{{ .Release.Name }}-config' + - name: movies + persistentVolumeClaim: + claimName: movies + - name: tvshows + persistentVolumeClaim: + claimName: tvshows + - name: music + persistentVolumeClaim: + claimName: music diff --git a/charts/apps/jellyfin/templates/external-http-service.yaml b/charts/apps/jellyfin/templates/external-http-service.yaml new file mode 100644 index 0000000..e28916d --- /dev/null +++ b/charts/apps/jellyfin/templates/external-http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: ExternalHttpService +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + subdomain: '{{ .Values.subdomain }}' + destination: + host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local' + port: + number: 80 diff --git a/charts/apps/jellyfin/templates/service.yaml b/charts/apps/jellyfin/templates/service.yaml new file mode 100644 index 0000000..99905f3 --- /dev/null +++ b/charts/apps/jellyfin/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: '{{ .Release.Name }}' + labels: + app: '{{ .Release.Name }}' +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 8096 + protocol: TCP + name: http + selector: + app: '{{ .Release.Name }}' diff --git a/charts/apps/jellyfin/values.yaml b/charts/apps/jellyfin/values.yaml new file mode 100644 index 0000000..94123cc --- /dev/null +++ b/charts/apps/jellyfin/values.yaml @@ -0,0 +1,7 @@ +globals: + environment: prod +image: + repository: docker.io/jellyfin/jellyfin + tag: latest@sha256:7ae36aab93ef9b6aaff02b37f8bb23df84bb2d7a3f6054ec8fc466072a648ce2 + pullPolicy: IfNotPresent +subdomain: jellyfin diff --git a/charts/apps/linkwarden/Chart.yaml b/charts/apps/linkwarden/Chart.yaml new file mode 100644 index 0000000..bf40913 --- /dev/null +++ b/charts/apps/linkwarden/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: Linkwarden diff --git a/charts/apps/linkwarden/templates/client.yaml b/charts/apps/linkwarden/templates/client.yaml new file mode 100644 index 0000000..7fbff6e --- /dev/null +++ b/charts/apps/linkwarden/templates/client.yaml @@ -0,0 +1,10 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + redirectUris: + - path: /api/v1/auth/callback/authentik + subdomain: "{{ .Values.subdomain }}" + matchingMode: strict diff --git a/charts/apps/linkwarden/templates/database.yaml b/charts/apps/linkwarden/templates/database.yaml new file mode 100644 index 0000000..6a30b53 --- /dev/null +++ b/charts/apps/linkwarden/templates/database.yaml @@ -0,0 +1,6 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: PostgresDatabase +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' diff --git a/charts/apps/linkwarden/templates/deployment.yaml b/charts/apps/linkwarden/templates/deployment.yaml new file mode 100644 index 0000000..79f72f6 --- /dev/null +++ b/charts/apps/linkwarden/templates/deployment.yaml @@ -0,0 +1,75 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + containers: + - name: "{{ .Release.Name }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + ports: + - containerPort: 3000 + name: http + env: + - name: TZ + value: "{{ .Values.globals.timezone }}" + - name: NEXTAUTH_URL + value: "https://{{ .Values.subdomain }}.{{ .Values.globals.domain }}/api/v1/auth" + - name: NEXT_PUBLIC_OLLAMA_ENDPOINT_URL + value: "http://ollama:80" + - name: OLLAMA_MODEL + value: phi3:mini-4k + - name: DATABASE_URL + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-pg-connection" + key: url + - name: NEXTAUTH_SECRET + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-secrets" + key: nextauth + - name: NEXT_PUBLIC_DISABLE_REGISTRATION + value: "true" + - name: NEXT_PUBLIC_CREDENTIALS_ENABLED + value: "false" + - name: DISABLE_NEW_SSO_USERS + value: "false" + - name: NEXT_PUBLIC_AUTHENTIK_ENABLED + value: "true" + - name: AUTHENTIK_CLIENT_ID + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: clientId + - name: AUTHENTIK_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: clientSecret + - name: AUTHENTIK_ISSUER + value: "https://authentik.{{ .Values.globals.domain }}/application/o/linkwarden" + # TODO: + # - name: AUTHENTIK_ISSUER + # valueFrom: + # secretKeyRef: + # name: "{{ .Release.Name }}-client" + # key: configurationIssuer + volumeMounts: + - mountPath: /data/data + name: data + volumes: + - name: data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-data" diff --git a/charts/apps/linkwarden/templates/external-http-service.yaml b/charts/apps/linkwarden/templates/external-http-service.yaml new file mode 100644 index 0000000..e28916d --- /dev/null +++ b/charts/apps/linkwarden/templates/external-http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: ExternalHttpService +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + subdomain: '{{ .Values.subdomain }}' + destination: + host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local' + port: + number: 80 diff --git a/charts/apps/linkwarden/templates/http-service.yaml b/charts/apps/linkwarden/templates/http-service.yaml new file mode 100644 index 0000000..15b1989 --- /dev/null +++ b/charts/apps/linkwarden/templates/http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: HttpService +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + subdomain: "{{ .Values.subdomain }}" + destination: + host: "{{ .Release.Name }}" + port: + number: 80 diff --git a/charts/apps/linkwarden/templates/pvc.yaml b/charts/apps/linkwarden/templates/pvc.yaml new file mode 100644 index 0000000..bc1d0a6 --- /dev/null +++ b/charts/apps/linkwarden/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-data' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/apps/linkwarden/templates/secret.yaml b/charts/apps/linkwarden/templates/secret.yaml new file mode 100644 index 0000000..cd7bee9 --- /dev/null +++ b/charts/apps/linkwarden/templates/secret.yaml @@ -0,0 +1,9 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: GenerateSecret +metadata: + name: "{{ .Release.Name }}-secrets" +spec: + fields: + - name: nextauth + encoding: hex + length: 64 diff --git a/charts/apps/linkwarden/templates/service.yaml b/charts/apps/linkwarden/templates/service.yaml new file mode 100644 index 0000000..b759568 --- /dev/null +++ b/charts/apps/linkwarden/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 3000 + protocol: TCP + name: http + selector: + app: "{{ .Release.Name }}" diff --git a/charts/apps/linkwarden/values.yaml b/charts/apps/linkwarden/values.yaml new file mode 100644 index 0000000..ce6233e --- /dev/null +++ b/charts/apps/linkwarden/values.yaml @@ -0,0 +1,9 @@ +globals: + environment: prod + domain: olsen.cloud + timezone: Europe/Amsterdam +image: + repository: ghcr.io/linkwarden/linkwarden + tag: latest@sha256:c1c6f417ea566de2c2dac6e79353ee5f40cb6a44fd9dd3970c83e6fc098de1df + pullPolicy: IfNotPresent +subdomain: linkwarden diff --git a/charts/apps/mealie/Chart.yaml b/charts/apps/mealie/Chart.yaml new file mode 100644 index 0000000..054a083 --- /dev/null +++ b/charts/apps/mealie/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: mealie diff --git a/charts/apps/mealie/templates/client.yaml b/charts/apps/mealie/templates/client.yaml new file mode 100644 index 0000000..d693063 --- /dev/null +++ b/charts/apps/mealie/templates/client.yaml @@ -0,0 +1,10 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + redirectUris: + - path: /login + subdomain: "{{ .Values.subdomain }}" + matchingMode: strict diff --git a/charts/apps/mealie/templates/deployment.yaml b/charts/apps/mealie/templates/deployment.yaml new file mode 100644 index 0000000..0f576f8 --- /dev/null +++ b/charts/apps/mealie/templates/deployment.yaml @@ -0,0 +1,72 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + containers: + - name: "{{ .Release.Name }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + ports: + - containerPort: 9000 + name: http + env: + - name: TZ + value: "{{ .Values.globals.timezone }}" + - name: BASE_URL + value: https://{{ .Values.subdomain }}.{{ .Values.globals.domain }} + - name: ALLOW_SIGNUP + value: "false" + - name: PUID + value: "1000" + - name: PGID + value: "1000" + - name: OIDC_AUTH_ENABLED + value: "true" + - name: OIDC_SIGNUP_ENABLED + value: "true" + - name: OIDC_USER_GROUP + value: "mealie-users" + - name: OIDC_ADMIN_GROUP + value: "admin" + - name: OIDC_AUTO_REDIRECT + value: "true" + - name: OIDC_PROVIDER_NAME + value: Authentik + - name: OIDC_REMEMBER_ME + value: "true" + - name: OIDC_SIGNING_ALGORITHM + value: RS256 + - name: OIDC_CLIENT_ID + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: clientId + - name: OIDC_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: clientSecret + - name: OIDC_CONFIGURATION_URL + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: configuration + + volumeMounts: + - mountPath: /app/data + name: data + volumes: + - name: data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-data" diff --git a/charts/apps/mealie/templates/external-http-service.yaml b/charts/apps/mealie/templates/external-http-service.yaml new file mode 100644 index 0000000..e28916d --- /dev/null +++ b/charts/apps/mealie/templates/external-http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: ExternalHttpService +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + subdomain: '{{ .Values.subdomain }}' + destination: + host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local' + port: + number: 80 diff --git a/charts/apps/mealie/templates/http-service.yaml b/charts/apps/mealie/templates/http-service.yaml new file mode 100644 index 0000000..15b1989 --- /dev/null +++ b/charts/apps/mealie/templates/http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: HttpService +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + subdomain: "{{ .Values.subdomain }}" + destination: + host: "{{ .Release.Name }}" + port: + number: 80 diff --git a/charts/apps/mealie/templates/pvc.yaml b/charts/apps/mealie/templates/pvc.yaml new file mode 100644 index 0000000..bc1d0a6 --- /dev/null +++ b/charts/apps/mealie/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-data' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/apps/mealie/templates/service.yaml b/charts/apps/mealie/templates/service.yaml new file mode 100644 index 0000000..8ad8f42 --- /dev/null +++ b/charts/apps/mealie/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 9000 + protocol: TCP + name: http + selector: + app: "{{ .Release.Name }}" diff --git a/charts/apps/mealie/values.yaml b/charts/apps/mealie/values.yaml new file mode 100644 index 0000000..770fee6 --- /dev/null +++ b/charts/apps/mealie/values.yaml @@ -0,0 +1,8 @@ +globals: + environment: prod + domain: olsen.cloud + timezone: Europe/Amsterdam +subdomain: mealie +image: + repository: ghcr.io/mealie-recipes/mealie + tag: latest@sha256:322369a5b748eddb091417e708f0667d21994e6119278d1b8c509900ba41e54b \ No newline at end of file diff --git a/charts/apps/metamcp/Chart.yaml b/charts/apps/metamcp/Chart.yaml new file mode 100644 index 0000000..886d45c --- /dev/null +++ b/charts/apps/metamcp/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: metamcp diff --git a/charts/apps/metamcp/templates/client.yaml b/charts/apps/metamcp/templates/client.yaml new file mode 100644 index 0000000..60befa2 --- /dev/null +++ b/charts/apps/metamcp/templates/client.yaml @@ -0,0 +1,10 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + redirectUris: + - path: /api/auth/oidc/callback + subdomain: '{{ .Values.subdomain }}' + matchingMode: strict diff --git a/charts/apps/metamcp/templates/database.yaml b/charts/apps/metamcp/templates/database.yaml new file mode 100644 index 0000000..6a30b53 --- /dev/null +++ b/charts/apps/metamcp/templates/database.yaml @@ -0,0 +1,6 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: PostgresDatabase +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' diff --git a/charts/apps/metamcp/templates/deployment.yaml b/charts/apps/metamcp/templates/deployment.yaml new file mode 100644 index 0000000..0dfcaf5 --- /dev/null +++ b/charts/apps/metamcp/templates/deployment.yaml @@ -0,0 +1,100 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + containers: + - name: "{{ .Release.Name }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + ports: + - name: http + containerPort: 12008 + protocol: TCP + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + volumeMounts: + - mountPath: /data + name: data + env: + - name: TZ + value: "{{ .Values.globals.timezone }}" + - name: APP_URL + value: "https://{{ .Values.subdomain }}.{{ .Values.globals.domain }}" + - name: NEXT_PUBLIC_APP_URL + value: "https://{{ .Values.subdomain }}.{{ .Values.globals.domain }}" + - name: BETTER_AUTH_SECRET + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-secrets" + key: betterauth + - name: DATABASE_URL + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-pg-connection" + key: url + - name: POSTGRES_DB + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-pg-connection" + key: database + - name: POSTGRES_HOST + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-pg-connection" + key: host + - name: POSTGRES_PORT + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-pg-connection" + key: port + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-pg-connection" + key: user + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-pg-connection" + key: password + - name: OIDC_PROVIDER_ID + value: oidc + - name: OIDC_SCOPES + value: openid email profile + - name: OIDC_PKCE + value: "true" + - name: OIDC_CLIENT_ID + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: clientId + - name: OIDC_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: clientSecret + - name: OIDC_DISCOVERY_URL + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: configuration + volumes: + - name: data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-data" diff --git a/charts/apps/metamcp/templates/external-http-service.yaml b/charts/apps/metamcp/templates/external-http-service.yaml new file mode 100644 index 0000000..e28916d --- /dev/null +++ b/charts/apps/metamcp/templates/external-http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: ExternalHttpService +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + subdomain: '{{ .Values.subdomain }}' + destination: + host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local' + port: + number: 80 diff --git a/charts/apps/metamcp/templates/pvc.yaml b/charts/apps/metamcp/templates/pvc.yaml new file mode 100644 index 0000000..bc1d0a6 --- /dev/null +++ b/charts/apps/metamcp/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-data' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/apps/metamcp/templates/secret.yaml b/charts/apps/metamcp/templates/secret.yaml new file mode 100644 index 0000000..9157356 --- /dev/null +++ b/charts/apps/metamcp/templates/secret.yaml @@ -0,0 +1,9 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: GenerateSecret +metadata: + name: '{{ .Release.Name }}-secrets' +spec: + fields: + - name: betterauth + encoding: base64 + length: 64 diff --git a/charts/apps/metamcp/templates/service.yaml b/charts/apps/metamcp/templates/service.yaml new file mode 100644 index 0000000..d730592 --- /dev/null +++ b/charts/apps/metamcp/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: '{{ .Release.Name }}' + labels: + app: '{{ .Release.Name }}' +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 12008 + protocol: TCP + name: http + selector: + app: '{{ .Release.Name }}' diff --git a/charts/apps/metamcp/values.yaml b/charts/apps/metamcp/values.yaml new file mode 100644 index 0000000..08a164c --- /dev/null +++ b/charts/apps/metamcp/values.yaml @@ -0,0 +1,9 @@ +globals: + environment: prod + domain: olsen.cloud + timezone: Europe/Amsterdam +image: + repository: ghcr.io/metatool-ai/metamcp + tag: latest@sha256:009c6354d55a7ff0df484c8109ac5ae241484e6fb6f7f09318dfeeba384108ac + pullPolicy: IfNotPresent +subdomain: metamcp diff --git a/charts/apps/miniflux/Chart.yaml b/charts/apps/miniflux/Chart.yaml new file mode 100644 index 0000000..7503208 --- /dev/null +++ b/charts/apps/miniflux/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: miniflux diff --git a/charts/apps/miniflux/templates/client.yaml b/charts/apps/miniflux/templates/client.yaml new file mode 100644 index 0000000..35bf730 --- /dev/null +++ b/charts/apps/miniflux/templates/client.yaml @@ -0,0 +1,10 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + redirectUris: + - path: oauth2/oidc/callback + subdomain: "{{ .Values.subdomain }}" + matchingMode: strict diff --git a/charts/apps/miniflux/templates/database.yaml b/charts/apps/miniflux/templates/database.yaml new file mode 100644 index 0000000..6a30b53 --- /dev/null +++ b/charts/apps/miniflux/templates/database.yaml @@ -0,0 +1,6 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: PostgresDatabase +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' diff --git a/charts/apps/miniflux/templates/deployment.yaml b/charts/apps/miniflux/templates/deployment.yaml new file mode 100644 index 0000000..f14ba8b --- /dev/null +++ b/charts/apps/miniflux/templates/deployment.yaml @@ -0,0 +1,74 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + containers: + - name: "{{ .Release.Name }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + ports: + - name: http + containerPort: 8080 + protocol: TCP + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + volumeMounts: + - mountPath: /data + name: data + env: + - name: TZ + value: "{{ .Values.globals.timezone }}" + - name: BASE_URL + value: https://{{ .Values.subdomain }}.{{ .Values.globals.domain }} + - name: RUN_MIGRATIONS + value: "1" + - name: DISABLE_LOCAL_AUTH + value: "1" + - name: OAUTH2_CLIENT_ID + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: clientId + - name: OAUTH2_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: clientSecret + - name: OAUTH2_OIDC_DISCOVERY_ENDPOINT + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: configurationIssuer + - name: OAUTH2_OIDC_PROVIDER_NAME + value: Authentik + - name: OAUTH2_PROVIDER + value: oidc + - name: OAUTH2_REDIRECT_URL + value: https://{{ .Values.subdomain }}.{{ .Values.globals.domain }}/oauth2/oidc/callback + - name: OAUTH2_USER_CREATION + value: "1" + - name: DATABASE_URL + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-pg-connection" + key: url + volumes: + - name: data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-data" diff --git a/charts/apps/miniflux/templates/external-http-service.yaml b/charts/apps/miniflux/templates/external-http-service.yaml new file mode 100644 index 0000000..e28916d --- /dev/null +++ b/charts/apps/miniflux/templates/external-http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: ExternalHttpService +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + subdomain: '{{ .Values.subdomain }}' + destination: + host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local' + port: + number: 80 diff --git a/charts/apps/miniflux/templates/pvc.yaml b/charts/apps/miniflux/templates/pvc.yaml new file mode 100644 index 0000000..bc1d0a6 --- /dev/null +++ b/charts/apps/miniflux/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-data' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/apps/miniflux/templates/service.yaml b/charts/apps/miniflux/templates/service.yaml new file mode 100644 index 0000000..c2cbc23 --- /dev/null +++ b/charts/apps/miniflux/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 8080 + protocol: TCP + name: http + selector: + app: "{{ .Release.Name }}" diff --git a/charts/apps/miniflux/values.yaml b/charts/apps/miniflux/values.yaml new file mode 100644 index 0000000..d4afaea --- /dev/null +++ b/charts/apps/miniflux/values.yaml @@ -0,0 +1,9 @@ +globals: + environment: prod + timezone: Europe/Amsterdam + domain: olsen.cloud +image: + repository: ghcr.io/miniflux/miniflux + tag: latest@sha256:fd6587a23884c277301307e4d70c196cd0f772fba1720b9e60051fc65a75121e + pullPolicy: IfNotPresent +subdomain: miniflux diff --git a/charts/apps/mqtt/Chart.yaml b/charts/apps/mqtt/Chart.yaml new file mode 100644 index 0000000..d54ee22 --- /dev/null +++ b/charts/apps/mqtt/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: apprise diff --git a/charts/apps/mqtt/templates/client.yaml b/charts/apps/mqtt/templates/client.yaml new file mode 100644 index 0000000..8299b34 --- /dev/null +++ b/charts/apps/mqtt/templates/client.yaml @@ -0,0 +1,10 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + redirectUris: + - path: /oauth/oidc/callback + subdomain: '{{ .Values.subdomain }}' + matchingMode: strict diff --git a/charts/apps/mqtt/templates/config.yaml b/charts/apps/mqtt/templates/config.yaml new file mode 100644 index 0000000..a099a66 --- /dev/null +++ b/charts/apps/mqtt/templates/config.yaml @@ -0,0 +1,12 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: "{{ .Release.Name }}-config" + labels: + app: "{{ .Release.Name }}" +data: + mosquitto.conf: | + persistence true + persistence_location /mosquitto/data/ + listener 1883 0.0.0.0 + allow_anonymous true diff --git a/charts/apps/mqtt/templates/deployment.yaml b/charts/apps/mqtt/templates/deployment.yaml new file mode 100644 index 0000000..92fabd5 --- /dev/null +++ b/charts/apps/mqtt/templates/deployment.yaml @@ -0,0 +1,62 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + containers: + - name: "{{ .Release.Name }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + ports: + - name: mqtt + containerPort: 1883 + protocol: TCP + livenessProbe: + exec: + command: + - sh + - -c + - mosquitto_pub -h localhost -p 1883 -t health/ready -m "ready" -q 0 -i readiness_client -V 5 + initialDelaySeconds: 10 # Give broker time to start + periodSeconds: 20 # Check every 20 seconds + timeoutSeconds: 5 # Fail if command takes longer than 5 seconds + failureThreshold: 3 # Restart if 3 consecutive failures + readinessProbe: + exec: + command: + - sh + - -c + - mosquitto_pub -h localhost -p 1883 -t health/ready -m "ready" -q 0 -i readiness_client -V 5 + initialDelaySeconds: 15 + periodSeconds: 20 + timeoutSeconds: 5 + failureThreshold: 3 + env: + - name: TZ + value: "{{ .Values.globals.timezone }}" + - name: MODE + value: "{{ .Values.mode }}" + volumeMounts: + - mountPath: /mosquitto/config + name: config + - mountPath: /mosquitto/data + name: data + + volumes: + - name: config + configMap: + name: "{{ .Release.Name }}-config" + - name: data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-data" diff --git a/charts/apps/mqtt/templates/http-service.yaml b/charts/apps/mqtt/templates/http-service.yaml new file mode 100644 index 0000000..52a7cc3 --- /dev/null +++ b/charts/apps/mqtt/templates/http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: HttpService +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + subdomain: "{{ .Values.subdomain }}" + destination: + host: "{{ .Release.Name }}" + port: + number: 1883 diff --git a/charts/apps/mqtt/templates/pvc.yaml b/charts/apps/mqtt/templates/pvc.yaml new file mode 100644 index 0000000..aeca898 --- /dev/null +++ b/charts/apps/mqtt/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: "{{ .Release.Name }}-data" +spec: + accessModes: + - "ReadWriteOnce" + resources: + requests: + storage: "1Gi" + storageClassName: "{{ .Values.globals.environment }}" diff --git a/charts/apps/mqtt/templates/service.yaml b/charts/apps/mqtt/templates/service.yaml new file mode 100644 index 0000000..ca1209d --- /dev/null +++ b/charts/apps/mqtt/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + type: LoadBalancer + ports: + - port: 1883 + targetPort: 1883 + protocol: TCP + name: mqtt + selector: + app: "{{ .Release.Name }}" diff --git a/charts/apps/mqtt/values.yaml b/charts/apps/mqtt/values.yaml new file mode 100644 index 0000000..39cb94a --- /dev/null +++ b/charts/apps/mqtt/values.yaml @@ -0,0 +1,10 @@ +globals: + environment: prod + timezone: Europe/Amsterdam + domain: olsen.cloud +image: + repository: docker.io/eclipse-mosquitto + tag: latest@sha256:d219d3a72847f3aed6a1d66975972d3b17f86e39e8f6f6b86b4088b879c1a2d6 + pullPolicy: IfNotPresent +subdomain: mqtt +mode: json-rpc \ No newline at end of file diff --git a/charts/apps/music-assistant/Chart.yaml b/charts/apps/music-assistant/Chart.yaml new file mode 100644 index 0000000..274c312 --- /dev/null +++ b/charts/apps/music-assistant/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: music-assistant diff --git a/charts/apps/music-assistant/templates/deployment.yaml b/charts/apps/music-assistant/templates/deployment.yaml new file mode 100644 index 0000000..2014210 --- /dev/null +++ b/charts/apps/music-assistant/templates/deployment.yaml @@ -0,0 +1,44 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + hostNetwork: true + + containers: + - name: "{{ .Release.Name }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + ports: + - name: http + containerPort: 8095 + protocol: TCP + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + volumeMounts: + - mountPath: /data + name: data + securityContext: + capabilities: + add: + - SYS_ADMIN + - DAC_READ_SEARCH + volumes: + - name: data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-data" diff --git a/charts/apps/music-assistant/templates/http-service.yaml b/charts/apps/music-assistant/templates/http-service.yaml new file mode 100644 index 0000000..89df8bf --- /dev/null +++ b/charts/apps/music-assistant/templates/http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: HttpService +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + subdomain: "{{ .Values.subdomain }}" + destination: + host: "{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local" + port: + number: 80 diff --git a/charts/apps/music-assistant/templates/pvc.yaml b/charts/apps/music-assistant/templates/pvc.yaml new file mode 100644 index 0000000..aeca898 --- /dev/null +++ b/charts/apps/music-assistant/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: "{{ .Release.Name }}-data" +spec: + accessModes: + - "ReadWriteOnce" + resources: + requests: + storage: "1Gi" + storageClassName: "{{ .Values.globals.environment }}" diff --git a/charts/apps/music-assistant/templates/service.yaml b/charts/apps/music-assistant/templates/service.yaml new file mode 100644 index 0000000..aa43db4 --- /dev/null +++ b/charts/apps/music-assistant/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 8095 + protocol: TCP + name: http + selector: + app: "{{ .Release.Name }}" diff --git a/charts/apps/music-assistant/values.yaml b/charts/apps/music-assistant/values.yaml new file mode 100644 index 0000000..af33be5 --- /dev/null +++ b/charts/apps/music-assistant/values.yaml @@ -0,0 +1,7 @@ +globals: + environment: prod +image: + repository: ghcr.io/music-assistant/server + tag: latest@sha256:f534116c53d49b3120961c908a5fa24f28684806bf222ccd74add9e16b105aa4 + pullPolicy: IfNotPresent +subdomain: music-assistant diff --git a/charts/apps/n8n/Chart.yaml b/charts/apps/n8n/Chart.yaml new file mode 100644 index 0000000..333b29f --- /dev/null +++ b/charts/apps/n8n/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: Jellyfin diff --git a/charts/apps/n8n/templates/database.yaml b/charts/apps/n8n/templates/database.yaml new file mode 100644 index 0000000..6a30b53 --- /dev/null +++ b/charts/apps/n8n/templates/database.yaml @@ -0,0 +1,6 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: PostgresDatabase +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' diff --git a/charts/apps/n8n/templates/deployment.yaml b/charts/apps/n8n/templates/deployment.yaml new file mode 100644 index 0000000..a3e099b --- /dev/null +++ b/charts/apps/n8n/templates/deployment.yaml @@ -0,0 +1,81 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + containers: + - name: "{{ .Release.Name }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + ports: + - name: http + containerPort: 5678 + protocol: TCP + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + volumeMounts: + - mountPath: /home/node/.n8n + name: data + env: + - name: TZ + value: "{{ .Values.globals.timezone }}" + - name: GENERIC_TIMEZONE + value: "{{ .Values.globals.timezone }}" + - name: N8N_ENFORCE_SETTINGS_FILE_PERMISSIONS + value: "true" + - name: N8N_RUNNERS_ENABLED + value: "true" + - name: N8N_EDITOR_BASE_URL + value: https://{{ .Values.subdomain }}.{{ .Values.globals.domain }} + - name: VUE_APP_URL_BASE_API + value: https://{{ .Values.subdomain }}.{{ .Values.globals.domain }} + - name: N8N_HOST + value: "{{ .Values.subdomain }}.{{ .Values.globals.domain }}" + - name: N8N_DIAGNOSTICS_ENABLED + value: "false" + - name: DB_TYPE + value: postgresdb + - name: DB_POSTGRESDB_DATABASE + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-pg-connection" + key: database + - name: DB_POSTGRESDB_HOST + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-pg-connection" + key: host + - name: DB_POSTGRESDB_PORT + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-pg-connection" + key: port + - name: DB_POSTGRESDB_USER + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-pg-connection" + key: user + - name: DB_POSTGRESDB_PASSWORD + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-pg-connection" + key: password + volumes: + - name: data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-data" diff --git a/charts/apps/n8n/templates/external-http-service.yaml b/charts/apps/n8n/templates/external-http-service.yaml new file mode 100644 index 0000000..e28916d --- /dev/null +++ b/charts/apps/n8n/templates/external-http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: ExternalHttpService +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + subdomain: '{{ .Values.subdomain }}' + destination: + host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local' + port: + number: 80 diff --git a/charts/apps/n8n/templates/pvc.yaml b/charts/apps/n8n/templates/pvc.yaml new file mode 100644 index 0000000..bc1d0a6 --- /dev/null +++ b/charts/apps/n8n/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-data' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/apps/n8n/templates/service.yaml b/charts/apps/n8n/templates/service.yaml new file mode 100644 index 0000000..4fa3b1b --- /dev/null +++ b/charts/apps/n8n/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: '{{ .Release.Name }}' + labels: + app: '{{ .Release.Name }}' +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 5678 + protocol: TCP + name: http + selector: + app: '{{ .Release.Name }}' diff --git a/charts/apps/n8n/values.yaml b/charts/apps/n8n/values.yaml new file mode 100644 index 0000000..a3bf893 --- /dev/null +++ b/charts/apps/n8n/values.yaml @@ -0,0 +1,9 @@ +globals: + environment: prod + timezone: Europe/Amsterdam + domain: olsen.cloud +image: + repository: docker.n8n.io/n8nio/n8n + tag: latest@sha256:4a159553c22d41f6167c7ddf01e4078c97726af863eae59579f3b2d9e8b12fe2 + pullPolicy: IfNotPresent +subdomain: n8n diff --git a/charts/apps/nocodb/Chart.yaml b/charts/apps/nocodb/Chart.yaml new file mode 100644 index 0000000..4fcb6db --- /dev/null +++ b/charts/apps/nocodb/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: nocodb diff --git a/charts/apps/nocodb/templates/deployment.yaml b/charts/apps/nocodb/templates/deployment.yaml new file mode 100644 index 0000000..ded3cb8 --- /dev/null +++ b/charts/apps/nocodb/templates/deployment.yaml @@ -0,0 +1,33 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + containers: + - name: "{{ .Release.Name }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + ports: + - containerPort: 8080 + name: http + env: + - name: TZ + value: "{{ .Values.globals.timezone }}" + - name: PUID + - mountPath: /usr/app/data/ + name: data + volumes: + - name: data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-data" diff --git a/charts/apps/nocodb/templates/external-http-service.yaml b/charts/apps/nocodb/templates/external-http-service.yaml new file mode 100644 index 0000000..e28916d --- /dev/null +++ b/charts/apps/nocodb/templates/external-http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: ExternalHttpService +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + subdomain: '{{ .Values.subdomain }}' + destination: + host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local' + port: + number: 80 diff --git a/charts/apps/nocodb/templates/http-service.yaml b/charts/apps/nocodb/templates/http-service.yaml new file mode 100644 index 0000000..15b1989 --- /dev/null +++ b/charts/apps/nocodb/templates/http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: HttpService +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + subdomain: "{{ .Values.subdomain }}" + destination: + host: "{{ .Release.Name }}" + port: + number: 80 diff --git a/charts/apps/nocodb/templates/pvc.yaml b/charts/apps/nocodb/templates/pvc.yaml new file mode 100644 index 0000000..bc1d0a6 --- /dev/null +++ b/charts/apps/nocodb/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-data' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/apps/nocodb/templates/service.yaml b/charts/apps/nocodb/templates/service.yaml new file mode 100644 index 0000000..c2cbc23 --- /dev/null +++ b/charts/apps/nocodb/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 8080 + protocol: TCP + name: http + selector: + app: "{{ .Release.Name }}" diff --git a/charts/apps/nocodb/values.yaml b/charts/apps/nocodb/values.yaml new file mode 100644 index 0000000..69f6826 --- /dev/null +++ b/charts/apps/nocodb/values.yaml @@ -0,0 +1,9 @@ +globals: + environment: prod + domain: olsen.cloud + timezone: Europe/Amsterdam +image: + repository: nocodb/nocodb + tag: latest@sha256:71d5b23640a9f5068bab26cf5b4c6a733709677a2c78664b132beaf24d766246 + pullPolicy: IfNotPresent +subdomain: nocodb diff --git a/charts/apps/ollama/Chart.yaml b/charts/apps/ollama/Chart.yaml new file mode 100644 index 0000000..66232a9 --- /dev/null +++ b/charts/apps/ollama/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: ollama diff --git a/charts/apps/ollama/templates/client.yaml b/charts/apps/ollama/templates/client.yaml new file mode 100644 index 0000000..8299b34 --- /dev/null +++ b/charts/apps/ollama/templates/client.yaml @@ -0,0 +1,10 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + redirectUris: + - path: /oauth/oidc/callback + subdomain: '{{ .Values.subdomain }}' + matchingMode: strict diff --git a/charts/apps/ollama/templates/deployment.yaml b/charts/apps/ollama/templates/deployment.yaml new file mode 100644 index 0000000..8d0d66b --- /dev/null +++ b/charts/apps/ollama/templates/deployment.yaml @@ -0,0 +1,38 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: '{{ .Release.Name }}' +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: '{{ .Release.Name }}' + template: + metadata: + labels: + app: '{{ .Release.Name }}' + spec: + containers: + - name: '{{ .Release.Name }}' + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' + imagePullPolicy: '{{ .Values.image.pullPolicy }}' + ports: + - name: http + containerPort: 11434 + protocol: TCP + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + volumeMounts: + - mountPath: /root/.ollama + name: data + + volumes: + - name: data + persistentVolumeClaim: + claimName: '{{ .Release.Name }}-data' diff --git a/charts/apps/ollama/templates/pvc.yaml b/charts/apps/ollama/templates/pvc.yaml new file mode 100644 index 0000000..bc1d0a6 --- /dev/null +++ b/charts/apps/ollama/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-data' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/apps/ollama/templates/service.yaml b/charts/apps/ollama/templates/service.yaml new file mode 100644 index 0000000..5650efa --- /dev/null +++ b/charts/apps/ollama/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: '{{ .Release.Name }}' + labels: + app: '{{ .Release.Name }}' +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 11434 + protocol: TCP + name: http + selector: + app: '{{ .Release.Name }}' diff --git a/charts/apps/ollama/values.yaml b/charts/apps/ollama/values.yaml new file mode 100644 index 0000000..3d6ee49 --- /dev/null +++ b/charts/apps/ollama/values.yaml @@ -0,0 +1,7 @@ +globals: + environment: prod +image: + repository: ollama/ollama + tag: 0.12.1@sha256:5aed793ab336d1aac9b132f4b46fddfcfa13b8911def3d275937c8acbd1763e8 + pullPolicy: IfNotPresent +subdomain: openwebui diff --git a/charts/apps/openwebui/Chart.yaml b/charts/apps/openwebui/Chart.yaml new file mode 100644 index 0000000..5b46cef --- /dev/null +++ b/charts/apps/openwebui/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: openwebui diff --git a/charts/apps/openwebui/templates/client.yaml b/charts/apps/openwebui/templates/client.yaml new file mode 100644 index 0000000..8299b34 --- /dev/null +++ b/charts/apps/openwebui/templates/client.yaml @@ -0,0 +1,10 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + redirectUris: + - path: /oauth/oidc/callback + subdomain: '{{ .Values.subdomain }}' + matchingMode: strict diff --git a/charts/apps/openwebui/templates/deployment.yaml b/charts/apps/openwebui/templates/deployment.yaml new file mode 100644 index 0000000..2fcd4aa --- /dev/null +++ b/charts/apps/openwebui/templates/deployment.yaml @@ -0,0 +1,70 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: '{{ .Release.Name }}' +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: '{{ .Release.Name }}' + template: + metadata: + labels: + app: '{{ .Release.Name }}' + spec: + containers: + - name: '{{ .Release.Name }}' + image: '{{ .Values.image.repository }}:{{ .Values.image.tag }}' + imagePullPolicy: '{{ .Values.image.pullPolicy }}' + ports: + - name: http + containerPort: 8080 + protocol: TCP + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + volumeMounts: + - mountPath: /app/backend/data + name: data + env: + - name: ENABLE_SIGNUP + value: 'false' + - name: WEBUI_URL # TODO: remove + value: https://openwebui.olsen.cloud + - name: ENABLE_OAUTH_PERSISTENT_CONFIG + value: 'false' + - name: ENABLE_OAUTH_SIGNUP + value: 'true' + - name: OAUTH_MERGE_ACCOUNTS_BY_EMAIL + value: 'true' + - name: OAUTH_PROVIDER_NAME + value: authentik + - name: OPENID_PROVIDER_URL + valueFrom: + secretKeyRef: + name: '{{ .Release.Name }}-client' + key: configuration + - name: OAUTH_CLIENT_ID + valueFrom: + secretKeyRef: + name: '{{ .Release.Name }}-client' + key: clientId + - name: OAUTH_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: '{{ .Release.Name }}-client' + key: clientSecret + - name: ENABLE_LOGIN_FORM + value: 'false' + - name: OPENID_REDIRECT + value: https://openwebui.olsen.cloud/oauth/oidc/callback + + volumes: + - name: data + persistentVolumeClaim: + claimName: '{{ .Release.Name }}-data' diff --git a/charts/apps/openwebui/templates/external-http-service.yaml b/charts/apps/openwebui/templates/external-http-service.yaml new file mode 100644 index 0000000..e28916d --- /dev/null +++ b/charts/apps/openwebui/templates/external-http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: ExternalHttpService +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + subdomain: '{{ .Values.subdomain }}' + destination: + host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local' + port: + number: 80 diff --git a/charts/apps/openwebui/templates/pvc.yaml b/charts/apps/openwebui/templates/pvc.yaml new file mode 100644 index 0000000..bc1d0a6 --- /dev/null +++ b/charts/apps/openwebui/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-data' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/apps/openwebui/templates/service.yaml b/charts/apps/openwebui/templates/service.yaml new file mode 100644 index 0000000..501e92a --- /dev/null +++ b/charts/apps/openwebui/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: '{{ .Release.Name }}' + labels: + app: '{{ .Release.Name }}' +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 8080 + protocol: TCP + name: http + selector: + app: '{{ .Release.Name }}' diff --git a/charts/apps/openwebui/values.yaml b/charts/apps/openwebui/values.yaml new file mode 100644 index 0000000..62a7a9d --- /dev/null +++ b/charts/apps/openwebui/values.yaml @@ -0,0 +1,7 @@ +globals: + environment: prod +image: + repository: ghcr.io/open-webui/open-webui + tag: main@sha256:05aaa81eb4094038a16f0ae056342e3515d1912a30e41b828bfd3731fbe36a6c + pullPolicy: IfNotPresent +subdomain: openwebui diff --git a/charts/apps/photoprism/Chart.yaml b/charts/apps/photoprism/Chart.yaml new file mode 100644 index 0000000..00f15a7 --- /dev/null +++ b/charts/apps/photoprism/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: photoprism diff --git a/charts/apps/photoprism/templates/client.yaml b/charts/apps/photoprism/templates/client.yaml new file mode 100644 index 0000000..3aa633c --- /dev/null +++ b/charts/apps/photoprism/templates/client.yaml @@ -0,0 +1,10 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + redirectUris: + - path: /api/v1/oidc/redirect + subdomain: "{{ .Values.subdomain }}" + matchingMode: strict diff --git a/charts/apps/photoprism/templates/deployment.yaml b/charts/apps/photoprism/templates/deployment.yaml new file mode 100644 index 0000000..1bf7618 --- /dev/null +++ b/charts/apps/photoprism/templates/deployment.yaml @@ -0,0 +1,92 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + containers: + - name: "{{ .Release.Name }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + env: + - name: PHOTOPRISM_UPLOAD_NSFW + value: "true" + - name: PHOTOPRISM_SITE_URL + value: "https://{{ .Values.subdomain }}.olsen.cloud" #TODO + # - name: PHOTOPRISM_UID + # value: "1000" + # - name: PHOTOPRISM_GID + # value: "1000" + # - name: PHOTOPRISM_DISABLE_CHOWN + # value: "true" + - name: PHOTOPRISM_AUTH_MODE + value: password + - name: PHOTOPRISM_DISABLE_TLS + value: "false" + - name: PHOTOPRISM_READONLY + value: "false" + - name: PHOTOPRISM_HTTP_COMPRESSION + value: "gzip" + + - name: PHOTOPRISM_ADMIN_PASSWORD + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-secrets" + key: password + - name: PHOTOPRISM_OIDC_SCOPES + value: "openid email profile offline_access" + - name: PHOTOPRISM_OIDC_PROVIDER + value: Authentik + - name: PHOTOPRISM_OIDC_ICON + value: https://cdn.jsdelivr.net/gh/selfhst/icons/png/authentik.png + - name: PHOTOPRISM_OIDC_REGISTER + value: "true" + - name: PHOTOPRISM_OIDC_REDIRECT + value: "false" + - name: PHOTOPRISM_OIDC_CLIENT + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: clientId + - name: PHOTOPRISM_OIDC_SECRET + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: clientSecret + - name: PHOTOPRISM_OIDC_URI + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: configurationIssuer + ports: + - name: http + containerPort: 2342 + protocol: TCP + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + volumeMounts: + - mountPath: /photoprism/storage + name: data + - mountPath: /photoprism/originals + name: originals + volumes: + - name: data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-data" + - name: originals + persistentVolumeClaim: + claimName: pictures diff --git a/charts/apps/photoprism/templates/external-http-service.yaml b/charts/apps/photoprism/templates/external-http-service.yaml new file mode 100644 index 0000000..e28916d --- /dev/null +++ b/charts/apps/photoprism/templates/external-http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: ExternalHttpService +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + subdomain: '{{ .Values.subdomain }}' + destination: + host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local' + port: + number: 80 diff --git a/charts/apps/photoprism/templates/http-service.yaml b/charts/apps/photoprism/templates/http-service.yaml new file mode 100644 index 0000000..89df8bf --- /dev/null +++ b/charts/apps/photoprism/templates/http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: HttpService +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + subdomain: "{{ .Values.subdomain }}" + destination: + host: "{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local" + port: + number: 80 diff --git a/charts/apps/photoprism/templates/pvc.yaml b/charts/apps/photoprism/templates/pvc.yaml new file mode 100644 index 0000000..aeca898 --- /dev/null +++ b/charts/apps/photoprism/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: "{{ .Release.Name }}-data" +spec: + accessModes: + - "ReadWriteOnce" + resources: + requests: + storage: "1Gi" + storageClassName: "{{ .Values.globals.environment }}" diff --git a/charts/apps/photoprism/templates/secret.yaml b/charts/apps/photoprism/templates/secret.yaml new file mode 100644 index 0000000..6e8ed5b --- /dev/null +++ b/charts/apps/photoprism/templates/secret.yaml @@ -0,0 +1,9 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: GenerateSecret +metadata: + name: "{{ .Release.Name }}-secrets" +spec: + fields: + - name: password + encoding: base64 + length: 64 diff --git a/charts/apps/photoprism/templates/service.yaml b/charts/apps/photoprism/templates/service.yaml new file mode 100644 index 0000000..2162563 --- /dev/null +++ b/charts/apps/photoprism/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 2342 + protocol: TCP + name: http + selector: + app: "{{ .Release.Name }}" diff --git a/charts/apps/photoprism/values.yaml b/charts/apps/photoprism/values.yaml new file mode 100644 index 0000000..e525100 --- /dev/null +++ b/charts/apps/photoprism/values.yaml @@ -0,0 +1,7 @@ +globals: + environment: prod +image: + repository: photoprism/photoprism + tag: latest@sha256:2ba3a774ca1acc498096d7a5cb50df9cfecb7e3117a617d648093ff74eec2793 + pullPolicy: IfNotPresent +subdomain: photoprism diff --git a/charts/apps/readeck/Chart.yaml b/charts/apps/readeck/Chart.yaml new file mode 100644 index 0000000..71ce3d0 --- /dev/null +++ b/charts/apps/readeck/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: readeck diff --git a/charts/apps/readeck/templates/deployment.yaml b/charts/apps/readeck/templates/deployment.yaml new file mode 100644 index 0000000..9eb77d8 --- /dev/null +++ b/charts/apps/readeck/templates/deployment.yaml @@ -0,0 +1,35 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + containers: + - name: "{{ .Release.Name }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + ports: + - containerPort: 8000 + name: http + env: + - name: TZ + value: "{{ .Values.globals.timezone }}" + - name: READECK_SERVER_HOST + value: "0.0.0.0" + volumeMounts: + - mountPath: /readeck + name: data + volumes: + - name: data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-data" diff --git a/charts/apps/readeck/templates/external-http-service.yaml b/charts/apps/readeck/templates/external-http-service.yaml new file mode 100644 index 0000000..e28916d --- /dev/null +++ b/charts/apps/readeck/templates/external-http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: ExternalHttpService +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + subdomain: '{{ .Values.subdomain }}' + destination: + host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local' + port: + number: 80 diff --git a/charts/apps/readeck/templates/http-service.yaml b/charts/apps/readeck/templates/http-service.yaml new file mode 100644 index 0000000..15b1989 --- /dev/null +++ b/charts/apps/readeck/templates/http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: HttpService +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + subdomain: "{{ .Values.subdomain }}" + destination: + host: "{{ .Release.Name }}" + port: + number: 80 diff --git a/charts/apps/readeck/templates/pvc.yaml b/charts/apps/readeck/templates/pvc.yaml new file mode 100644 index 0000000..bc1d0a6 --- /dev/null +++ b/charts/apps/readeck/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-data' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/apps/readeck/templates/service.yaml b/charts/apps/readeck/templates/service.yaml new file mode 100644 index 0000000..f7001fc --- /dev/null +++ b/charts/apps/readeck/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 8000 + protocol: TCP + name: http + selector: + app: "{{ .Release.Name }}" diff --git a/charts/apps/readeck/values.yaml b/charts/apps/readeck/values.yaml new file mode 100644 index 0000000..49d0ede --- /dev/null +++ b/charts/apps/readeck/values.yaml @@ -0,0 +1,9 @@ +globals: + environment: prod + domain: olsen.cloud + timezone: Europe/Amsterdam +image: + repository: codeberg.org/readeck/readeck + tag: latest@sha256:432cc2026f9dca3c33ce331f52c225287a2fa91a3c1dce8a4b0b7e9de4185c2f + pullPolicy: IfNotPresent +subdomain: readeck diff --git a/charts/apps/signal/Chart.yaml b/charts/apps/signal/Chart.yaml new file mode 100644 index 0000000..d54ee22 --- /dev/null +++ b/charts/apps/signal/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: apprise diff --git a/charts/apps/signal/templates/client.yaml b/charts/apps/signal/templates/client.yaml new file mode 100644 index 0000000..8299b34 --- /dev/null +++ b/charts/apps/signal/templates/client.yaml @@ -0,0 +1,10 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + redirectUris: + - path: /oauth/oidc/callback + subdomain: '{{ .Values.subdomain }}' + matchingMode: strict diff --git a/charts/apps/signal/templates/deployment.yaml b/charts/apps/signal/templates/deployment.yaml new file mode 100644 index 0000000..3e010b2 --- /dev/null +++ b/charts/apps/signal/templates/deployment.yaml @@ -0,0 +1,43 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + containers: + - name: "{{ .Release.Name }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + ports: + - name: http + containerPort: 8080 + protocol: TCP + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + env: + - name: TZ + value: "{{ .Values.globals.timezone }}" + - name: MODE + value: "{{ .Values.mode }}" + volumeMounts: + - mountPath: /home/.local/share/signal-cli + name: data + + volumes: + - name: data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-data" diff --git a/charts/apps/signal/templates/pvc.yaml b/charts/apps/signal/templates/pvc.yaml new file mode 100644 index 0000000..bc1d0a6 --- /dev/null +++ b/charts/apps/signal/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-data' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/apps/signal/templates/service.yaml b/charts/apps/signal/templates/service.yaml new file mode 100644 index 0000000..c2cbc23 --- /dev/null +++ b/charts/apps/signal/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 8080 + protocol: TCP + name: http + selector: + app: "{{ .Release.Name }}" diff --git a/charts/apps/signal/values.yaml b/charts/apps/signal/values.yaml new file mode 100644 index 0000000..dd8ce7d --- /dev/null +++ b/charts/apps/signal/values.yaml @@ -0,0 +1,10 @@ +globals: + environment: prod + timezone: Europe/Amsterdam + domain: olsen.cloud +image: + repository: bbernhard/signal-cli-rest-api + tag: latest@sha256:e4bc92213b2a4da10fc429d16ed1754e90c2c169f186efbb9ce5f04da5322771 + pullPolicy: IfNotPresent +subdomain: apprise +mode: json-rpc \ No newline at end of file diff --git a/charts/apps/volumes/Chart.yaml b/charts/apps/volumes/Chart.yaml new file mode 100644 index 0000000..2e26fac --- /dev/null +++ b/charts/apps/volumes/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: Resources diff --git a/charts/apps/volumes/templates/pvc.yaml b/charts/apps/volumes/templates/pvc.yaml new file mode 100644 index 0000000..71e641d --- /dev/null +++ b/charts/apps/volumes/templates/pvc.yaml @@ -0,0 +1,36 @@ +{{- $values := .Values -}} +{{- $release := .Release -}} + +--- +{{- range $key, $value := $values.shares }} +apiVersion: v1 +kind: PersistentVolume +metadata: + name: "{{$key}}" + labels: + type: nfs +spec: + capacity: + storage: 10Gi + accessModes: + - ReadWriteMany + persistentVolumeReclaimPolicy: Retain + storageClassName: "manual-{{$key}}" + nfs: + path: "{{ $value.path }}" + server: "{{ $values.host }}" +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: "{{ $key }}" +spec: + storageClassName: "manual-{{ $key }}" + accessModes: + - ReadWriteMany + resources: + requests: + storage: 10Gi +--- +{{- end }} + diff --git a/charts/apps/volumes/values.yaml b/charts/apps/volumes/values.yaml new file mode 100644 index 0000000..a477ab3 --- /dev/null +++ b/charts/apps/volumes/values.yaml @@ -0,0 +1,16 @@ +host: 192.168.20.106 +shares: + movies: + path: /mnt/HDD/Movies + tvshows: + path: /mnt/HDD/TV-Shows + music: + path: /mnt/HDD/Music2 + books: + path: /mnt/HDD/Books + podcasts: + path: /mnt/HDD/Podcasts + pictures: + path: /mnt/HDD/Pictures + backups: + path: /mnt/HDD/Backups diff --git a/charts/apps/zot/Chart.yaml b/charts/apps/zot/Chart.yaml new file mode 100644 index 0000000..125024a --- /dev/null +++ b/charts/apps/zot/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: zot diff --git a/charts/apps/zot/templates/client.yaml b/charts/apps/zot/templates/client.yaml new file mode 100644 index 0000000..d579b13 --- /dev/null +++ b/charts/apps/zot/templates/client.yaml @@ -0,0 +1,10 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + redirectUris: + - path: /zot/auth/callback/oidc + subdomain: "{{ .Values.subdomain }}" + matchingMode: strict diff --git a/charts/apps/zot/templates/config-map.yaml b/charts/apps/zot/templates/config-map.yaml new file mode 100644 index 0000000..ad53801 --- /dev/null +++ b/charts/apps/zot/templates/config-map.yaml @@ -0,0 +1,96 @@ +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ .Release.Name }}-config-template +data: + secrets.tpl.json: | + { + "clientid": "${CLIENT_ID}", + "clientsecret": "${CLIENT_SECRET}" + } + config.tpl.json: | + { + "storage": { + "rootDirectory": "/var/lib/registry", + "commit": false, + "dedupe": true, + "gc": true, + "gcDelay": "1h", + "gcInterval": "24h" + }, + "log": { + "level": "info" + }, + "http": { + "address": "0.0.0.0", + "port": "5000", + "externalUrl": "https://{{ .Values.subdomain }}.{{ .Values.globals.domain }}", + "ratelimit": { + "rate": 10, + "methods": [ + { + "method": "GET", + "rate": 20 + } + ] + }, + "auth": { + "failDelay": 5, + "htpasswd": { + "path": "/etc/zot/htpasswd" + }, + "openid": { + "providers": { + "oidc": { + "name": "main", + "credentialsFile": "/etc/zot/secrets.json", + "issuer": "${ISSUER}", + "scopes": ["openid", "profile", "email"] + } + } + } + }, + "accessControl": { + "adminPolicy": { + "groups": ["admin"], + "actions": ["read", "create", "update", "delete"] + }, + "repositories": { + "public/**": { + "anonymousPolicy": ["read"], + "defaultPolicy": ["read"], + "policies": [ + { + "users": ["*"], + "actions": ["create", "update", "delete"] + } + ] + }, + "**": { + "defaultPolicy": ["read"], + "policies": [ + { + "users": ["*"], + "actions": ["create", "update", "delete"] + } + ] + } + } + } + }, + "extensions": { + "ui": { "enable": true }, + "metrics": { "enable": true }, + "search": { "enable": true }, + "scrub": { + "enable": true, + "interval": "24h" + }, + "trust": { + "enable": true, + "cosign": true, + "notation": true + } + + } + } \ No newline at end of file diff --git a/charts/apps/zot/templates/deployment.yaml b/charts/apps/zot/templates/deployment.yaml new file mode 100644 index 0000000..3346d17 --- /dev/null +++ b/charts/apps/zot/templates/deployment.yaml @@ -0,0 +1,104 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + replicas: 1 + strategy: + type: Recreate + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + initContainers: + - name: render-config + image: alpine:3.20 + command: ["/bin/sh", "-c"] + env: + - name: ISSUER + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: configurationIssuer + - name: CLIENT_ID + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: clientId + - name: CLIENT_SECRET + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-client" + key: clientSecret + - name: PASSWORD + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-cluster" + key: password + args: + - | + apk add --no-cache gettext apache2-utils >/dev/null + envsubst < /config-tpl/config.tpl.json > /config-out/config.json + echo "Rendered /etc/zot/config.json" + echo "---------------------------------------" + cat /config-out/config.json + echo "---------------------------------------" + envsubst < /config-tpl/secrets.tpl.json > /config-out/secrets.json + echo "Rendered /etc/zot/secrets.json" + echo "---------------------------------------" + cat /config-out/secrets.json + echo "---------------------------------------" + htpasswd -nbB cluster "$PASSWORD" > /config-out/htpasswd + volumeMounts: + - name: config-tpl + mountPath: /config-tpl + - name: config + mountPath: /config-out + containers: + - name: "{{ .Release.Name }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + ports: + - containerPort: 5000 + name: http + env: + - name: TZ + value: "{{ .Values.globals.timezone }}" + - name: BASE_URL + value: https://{{ .Values.subdomain }}.{{ .Values.globals.domain }} + volumeMounts: + - mountPath: /var/lib/registry + name: data + - mountPath: /etc/zot + name: config + # readinessProbe: + # httpGet: + # path: /v2/ + # port: http + # initialDelaySeconds: 3 + # periodSeconds: 10 + # livenessProbe: + # httpGet: + # path: /v2/ + # port: http + # initialDelaySeconds: 10 + # periodSeconds: 20 + volumes: + - name: data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-data" + - name: config-tpl + configMap: + name: {{ .Release.Name }}-config-template + items: + - key: config.tpl.json + path: config.tpl.json + - key: secrets.tpl.json + path: secrets.tpl.json + - name: config + emptyDir: {} diff --git a/charts/apps/zot/templates/external-http-service.yaml b/charts/apps/zot/templates/external-http-service.yaml new file mode 100644 index 0000000..e28916d --- /dev/null +++ b/charts/apps/zot/templates/external-http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: ExternalHttpService +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + subdomain: '{{ .Values.subdomain }}' + destination: + host: '{{ .Release.Name }}.{{ .Release.Namespace }}.svc.cluster.local' + port: + number: 80 diff --git a/charts/apps/zot/templates/http-service.yaml b/charts/apps/zot/templates/http-service.yaml new file mode 100644 index 0000000..15b1989 --- /dev/null +++ b/charts/apps/zot/templates/http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: HttpService +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + subdomain: "{{ .Values.subdomain }}" + destination: + host: "{{ .Release.Name }}" + port: + number: 80 diff --git a/charts/apps/zot/templates/pvc.yaml b/charts/apps/zot/templates/pvc.yaml new file mode 100644 index 0000000..bc1d0a6 --- /dev/null +++ b/charts/apps/zot/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-data' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/apps/zot/templates/secret.yaml b/charts/apps/zot/templates/secret.yaml new file mode 100644 index 0000000..d44c2c3 --- /dev/null +++ b/charts/apps/zot/templates/secret.yaml @@ -0,0 +1,9 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: GenerateSecret +metadata: + name: "{{ .Release.Name }}-cluster" +spec: + fields: + - name: password + encoding: hex + length: 64 diff --git a/charts/apps/zot/templates/service.yaml b/charts/apps/zot/templates/service.yaml new file mode 100644 index 0000000..a634293 --- /dev/null +++ b/charts/apps/zot/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 5000 + protocol: TCP + name: http + selector: + app: "{{ .Release.Name }}" diff --git a/charts/apps/zot/values.yaml b/charts/apps/zot/values.yaml new file mode 100644 index 0000000..38e92d9 --- /dev/null +++ b/charts/apps/zot/values.yaml @@ -0,0 +1,8 @@ +globals: + environment: prod + domain: olsen.cloud + timezone: Europe/Amsterdam +subdomain: zot +image: + repository: ghcr.io/project-zot/zot + tag: latest@sha256:cd2aea942f428630bcb4190542be6abd35e14177aab84fc7ccad0dca8ecb363d \ No newline at end of file diff --git a/charts/backup/Chart.yaml b/charts/backup/Chart.yaml new file mode 100644 index 0000000..df9c5e9 --- /dev/null +++ b/charts/backup/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: backup diff --git a/charts/backup/templates/client.yaml b/charts/backup/templates/client.yaml new file mode 100644 index 0000000..8299b34 --- /dev/null +++ b/charts/backup/templates/client.yaml @@ -0,0 +1,10 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: '{{ .Release.Name }}' +spec: + environment: '{{ .Values.globals.environment }}' + redirectUris: + - path: /oauth/oidc/callback + subdomain: '{{ .Values.subdomain }}' + matchingMode: strict diff --git a/charts/backup/templates/cron-job-backup.yaml b/charts/backup/templates/cron-job-backup.yaml new file mode 100644 index 0000000..5b249fc --- /dev/null +++ b/charts/backup/templates/cron-job-backup.yaml @@ -0,0 +1,48 @@ +{{- $values := .Values -}} +{{- $release := .Release -}} + +--- +{{- range $key, $value := $values.jobs}} +apiVersion: batch/v1 +kind: CronJob +metadata: + name: "{{ $release.Name }}-{{ $key }}-backup" +spec: + schedule: "{{ $value.cron.backup }}" + concurrencyPolicy: Forbid + successfulJobsHistoryLimit: 3 + failedJobsHistoryLimit: 1 + jobTemplate: + spec: + template: + metadata: + annotations: + sidecar.istio.io/inject: "false" + spec: + containers: + - name: "{{ $release.Name }}-{{ $key }}-backup" + image: ghcr.io/morten-olsen/homelab-operator-backup:main + imagePullPolicy: Always + command: ["/app/backup.sh"] + env: + - name: RESTIC_PASSWORD + valueFrom: + secretKeyRef: + name: "{{ $values.password.name }}" + key: "{{ $values.password.key }}" + volumeMounts: + - name: source + mountPath: "/mnt/source" + - name: target + mountPath: "/mnt/backup" + subPath: "{{ $release.Name }}-{{ $key }}" + volumes: + - name: source + persistentVolumeClaim: + claimName: "{{ $value.source }}" + - name: target + persistentVolumeClaim: + claimName: "{{ $values.target }}" + restartPolicy: OnFailure +--- +{{- end }} diff --git a/charts/backup/templates/cron-job-cleanup.yaml b/charts/backup/templates/cron-job-cleanup.yaml new file mode 100644 index 0000000..b671a9a --- /dev/null +++ b/charts/backup/templates/cron-job-cleanup.yaml @@ -0,0 +1,43 @@ +{{- $values := .Values -}} +{{- $release := .Release -}} + +--- +{{- range $key, $value := $values.jobs}} +apiVersion: batch/v1 +kind: CronJob +metadata: + name: "{{ $release.Name }}-{{ $key }}-cleanup" +spec: + schedule: "{{ $value.cron.cleanup }}" + concurrencyPolicy: Forbid + successfulJobsHistoryLimit: 3 + failedJobsHistoryLimit: 1 + jobTemplate: + spec: + template: + metadata: + annotations: + sidecar.istio.io/inject: "false" + spec: + containers: + - name: "{{ $release.Name }}-{{ $key }}-cleanup" + image: ghcr.io/morten-olsen/homelab-operator-backup:main + imagePullPolicy: Always + command: ["/app/cleanup.sh"] + env: + - name: RESTIC_PASSWORD + valueFrom: + secretKeyRef: + name: "{{ $values.password.name }}" + key: "{{ $values.password.key }}" + volumeMounts: + - name: target + mountPath: "/mnt/backup" + subPath: "{{ $release.Name }}-{{ $key }}" + volumes: + - name: target + persistentVolumeClaim: + claimName: "{{ $values.target }}" + restartPolicy: OnFailure +--- +{{- end }} diff --git a/charts/backup/templates/deployment.yaml b/charts/backup/templates/deployment.yaml new file mode 100644 index 0000000..c76fee0 --- /dev/null +++ b/charts/backup/templates/deployment.yaml @@ -0,0 +1,48 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}" +spec: + strategy: + type: Recreate + replicas: 1 + selector: + matchLabels: + app: "{{ .Release.Name }}" + template: + metadata: + labels: + app: "{{ .Release.Name }}" + spec: + containers: + - name: "{{ .Release.Name }}" + image: "{{ .Values.image.repository }}:{{ .Values.image.tag }}" + imagePullPolicy: "{{ .Values.image.pullPolicy }}" + ports: + - name: http + containerPort: 9898 + protocol: TCP + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + env: + - name: TZ + value: "{{ .Values.globals.timezone }}" + - name: BASE_URL + value: https://{{ .Values.subdomain }}.{{ .Values.globals.domain }} + volumeMounts: + - mountPath: /data + name: data + - mountPath: /backups + name: backups + + volumes: + - name: data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-data" + - name: backups + persistentVolumeClaim: + claimName: "{{ .Values.target }}" diff --git a/charts/backup/templates/http-service.yaml b/charts/backup/templates/http-service.yaml new file mode 100644 index 0000000..15b1989 --- /dev/null +++ b/charts/backup/templates/http-service.yaml @@ -0,0 +1,11 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: HttpService +metadata: + name: "{{ .Release.Name }}" +spec: + environment: "{{ .Values.globals.environment }}" + subdomain: "{{ .Values.subdomain }}" + destination: + host: "{{ .Release.Name }}" + port: + number: 80 diff --git a/charts/backup/templates/pvc.yaml b/charts/backup/templates/pvc.yaml new file mode 100644 index 0000000..bc1d0a6 --- /dev/null +++ b/charts/backup/templates/pvc.yaml @@ -0,0 +1,11 @@ +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: '{{ .Release.Name }}-data' +spec: + accessModes: + - 'ReadWriteOnce' + resources: + requests: + storage: '1Gi' + storageClassName: '{{ .Values.globals.environment }}' diff --git a/charts/backup/templates/service.yaml b/charts/backup/templates/service.yaml new file mode 100644 index 0000000..4d55614 --- /dev/null +++ b/charts/backup/templates/service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}" + labels: + app: "{{ .Release.Name }}" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 9898 + protocol: TCP + name: http + selector: + app: "{{ .Release.Name }}" diff --git a/charts/backup/values.yaml b/charts/backup/values.yaml new file mode 100644 index 0000000..016bab5 --- /dev/null +++ b/charts/backup/values.yaml @@ -0,0 +1,19 @@ +globals: + environment: prod + timezone: Europe/Amsterdam + domain: olsen.cloud +image: + repository: garethgeorge/backrest + tag: latest@sha256:f8306faef0a3cbedc7daa55756f1d4c105d8c104aa773656bdad4fa8553dab5a + pullPolicy: IfNotPresent +subdomain: restic +password: + name: backup + key: password +jobs: + pictures: + cron: + backup: "0 2 * * *" + cleanup: "0 4 * * SUN" + source: pictures +target: backups diff --git a/charts/monitoring/Chart.yaml b/charts/monitoring/Chart.yaml new file mode 100644 index 0000000..9683fee --- /dev/null +++ b/charts/monitoring/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: 1.0.0 +name: monitoring diff --git a/charts/monitoring/templates/falco.yaml b/charts/monitoring/templates/falco.yaml new file mode 100644 index 0000000..0175dd8 --- /dev/null +++ b/charts/monitoring/templates/falco.yaml @@ -0,0 +1,25 @@ +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmRepository +metadata: + name: '{{ .Release.Name }}-falco' +spec: + interval: 1h + url: https://falcosecurity.github.io/charts + +--- +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: '{{ .Release.Name }}-falco' +spec: + chart: + spec: + chart: falco + reconcileStrategy: ChartVersion + sourceRef: + apiVersion: source.toolkit.fluxcd.io/v1 + kind: HelmRepository + name: '{{ .Release.Name }}-falco' + namespace: '{{ .Release.Namespace }}' + interval: 1h + values: {} diff --git a/charts/monitoring/templates/kube-prometheus-stack.yaml b/charts/monitoring/templates/kube-prometheus-stack.yaml new file mode 100644 index 0000000..bc8df51 --- /dev/null +++ b/charts/monitoring/templates/kube-prometheus-stack.yaml @@ -0,0 +1,53 @@ +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmRepository +metadata: + name: "{{ .Release.Name }}-prometheus-community" +spec: + interval: 1h + url: https://prometheus-community.github.io/helm-charts/ + +--- +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: "{{ .Release.Name }}-prometheus-community" +spec: + chart: + spec: + chart: kube-prometheus-stack + reconcileStrategy: ChartVersion + sourceRef: + apiVersion: source.toolkit.fluxcd.io/v1 + kind: HelmRepository + name: "{{ .Release.Name }}-prometheus-community" + namespace: "{{ .Release.Namespace }}" + interval: 1h + values: + grafana: + env: + GF_SERVER_ROOT_URL: https://grafana.olsen.cloud # TODO + +--- +apiVersion: homelab.mortenolsen.pro/v1 +kind: HttpService +metadata: + name: "{{ .Release.Name }}-prometheus-community" +spec: + environment: "{{ .Values.globals.environment }}" + subdomain: "{{ .Values.grafana.subdomain }}" + destination: + host: "{{ .Release.Name }}-prometheus-community-grafana.{{ .Release.Namespace }}.svc.cluster.local" + port: + number: 80 + +--- +apiVersion: homelab.mortenolsen.pro/v1 +kind: OidcClient +metadata: + name: "{{ .Release.Name }}-grafana" +spec: + environment: "{{ .Values.globals.environment }}" + redirectUris: + - path: /login/generic_oauth + subdomain: "{{ .Values.grafana.subdomain }}" + matchingMode: strict diff --git a/charts/monitoring/templates/kyverno.yaml b/charts/monitoring/templates/kyverno.yaml new file mode 100644 index 0000000..8845eb5 --- /dev/null +++ b/charts/monitoring/templates/kyverno.yaml @@ -0,0 +1,25 @@ +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmRepository +metadata: + name: '{{ .Release.Name }}-kyverno' +spec: + interval: 1h + url: https://kyverno.github.io/kyverno/ + +--- +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: '{{ .Release.Name }}-kyverno' +spec: + chart: + spec: + chart: kyverno + reconcileStrategy: ChartVersion + sourceRef: + apiVersion: source.toolkit.fluxcd.io/v1 + kind: HelmRepository + name: '{{ .Release.Name }}-kyverno' + namespace: '{{ .Release.Namespace }}' + interval: 1h + values: {} diff --git a/charts/monitoring/templates/loki.yaml b/charts/monitoring/templates/loki.yaml new file mode 100644 index 0000000..2a1bafe --- /dev/null +++ b/charts/monitoring/templates/loki.yaml @@ -0,0 +1,121 @@ +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmRepository +metadata: + name: '{{ .Release.Name }}-loki' +spec: + interval: 1h + url: https://grafana.github.io/helm-charts + +--- +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: '{{ .Release.Name }}-loki' +spec: + chart: + spec: + chart: loki + reconcileStrategy: ChartVersion + sourceRef: + apiVersion: source.toolkit.fluxcd.io/v1 + kind: HelmRepository + name: '{{ .Release.Name }}-loki' + namespace: '{{ .Release.Namespace }}' + interval: 1h + values: + deploymentMode: SingleBinary + loki: + auth_enabled: false + server: + http_listen_port: 3100 + + # memberlist: + # join_members: + # - loki-memberlist + + schemaConfig: + configs: + - from: 2020-05-15 + store: tsdb + object_store: filesystem + schema: v13 + index: + prefix: index_ + period: 24h + + storage: + type: filesystem + + storage_config: + filesystem: + directory: /loki/chunks + + limits_config: + reject_old_samples: true + reject_old_samples_max_age: 168h + max_cache_freshness_per_query: 10m + split_queries_by_interval: 15m + volume_enabled: true + + common: + path_prefix: /loki + storage: + filesystem: + chunks_directory: /loki/chunks + rules_directory: /loki/rules + replication_factor: 1 + ring: + instance_addr: 127.0.0.1 + kvstore: + store: inmemory + + # Enable persistent storage + singleBinary: + persistence: + enabled: true + size: 10Gi + storageClass: '{{ .Values.globals.environment }}' # Uses default storage class + extraVolumeMounts: + - name: storage + mountPath: /loki + + backend: + replicas: 0 + read: + replicas: 0 + write: + replicas: 0 + + ingester: + replicas: 0 + querier: + replicas: 0 + queryFrontend: + replicas: 0 + queryScheduler: + replicas: 0 + distributor: + replicas: 0 + compactor: + replicas: 0 + indexGateway: + replicas: 0 + bloomCompactor: + replicas: 0 + bloomGateway: + replicas: 0 + promtail: + enabled: true + config: + snippets: + extraScrapeConfigs: | + - job_name: kubernetes-pods + kubernetes_sd_configs: + - role: pod + relabel_configs: + - source_labels: ["__meta_kubernetes_pod_container_name"] + target_label: "container" + - source_labels: ["__meta_kubernetes_pod_name"] + target_label: "pod" + - source_labels: ["__meta_kubernetes_pod_namespace"] + target_label: "namespace" diff --git a/charts/monitoring/templates/trivy.yaml b/charts/monitoring/templates/trivy.yaml new file mode 100644 index 0000000..e7cfa89 --- /dev/null +++ b/charts/monitoring/templates/trivy.yaml @@ -0,0 +1,25 @@ +apiVersion: source.toolkit.fluxcd.io/v1 +kind: HelmRepository +metadata: + name: '{{ .Release.Name }}-aqua' +spec: + interval: 1h + url: https://aquasecurity.github.io/helm-charts/ + +--- +apiVersion: helm.toolkit.fluxcd.io/v2 +kind: HelmRelease +metadata: + name: '{{ .Release.Name }}-aqua' +spec: + chart: + spec: + chart: trivy-operator + reconcileStrategy: ChartVersion + sourceRef: + apiVersion: source.toolkit.fluxcd.io/v1 + kind: HelmRepository + name: '{{ .Release.Name }}-aqua' + namespace: '{{ .Release.Namespace }}' + interval: 1h + values: {} diff --git a/charts/monitoring/values.yaml b/charts/monitoring/values.yaml new file mode 100644 index 0000000..5718646 --- /dev/null +++ b/charts/monitoring/values.yaml @@ -0,0 +1,4 @@ +globals: + environment: prod +grafana: + subdomain: grafana diff --git a/charts/rules/Chart.yaml b/charts/rules/Chart.yaml new file mode 100644 index 0000000..9163119 --- /dev/null +++ b/charts/rules/Chart.yaml @@ -0,0 +1,3 @@ +apiVersion: v2 +version: '1.0.0' +name: rules diff --git a/charts/rules/templates/enforce-read-only-root-filesystem.yaml b/charts/rules/templates/enforce-read-only-root-filesystem.yaml new file mode 100644 index 0000000..c60018d --- /dev/null +++ b/charts/rules/templates/enforce-read-only-root-filesystem.yaml @@ -0,0 +1,32 @@ +apiVersion: kyverno.io/v1 +kind: Policy +metadata: + name: enforce-immutable-filesystem + annotations: + policies.kyverno.io/category: Security + policies.kyverno.io/severity: medium + policies.kyverno.io/description: | + This policy automatically sets 'readOnlyRootFilesystem: true' for all containers + within new Pods, enforcing an immutable root filesystem. This enhances security + by preventing applications from writing to their root filesystem at runtime, + making it harder for attackers to persist changes or introduce malware. +spec: + validationFailureAction: Audit + rules: + - name: enforce-read-only-root-filesystem + match: + any: + - resources: + kinds: + - Pod + mutate: + patchStrategicMerge: + spec: + containers: + - (name): '*' # Apply to all containers + securityContext: + readOnlyRootFilesystem: true + initContainers: + - (name): '*' # Apply to all init containers + securityContext: + readOnlyRootFilesystem: true diff --git a/helmfile.yaml.gotmpl b/helmfile.yaml.gotmpl new file mode 100644 index 0000000..c55c20e --- /dev/null +++ b/helmfile.yaml.gotmpl @@ -0,0 +1,83 @@ +environments: + default: {} +--- + +releases: + - name: volumes + chart: charts/apps/volumes + namespace: prod + - name: audiobookshelf + chart: charts/apps/audiobookshelf + namespace: prod + - name: baikal + chart: charts/apps/baikal + namespace: prod + - name: bytestash + chart: charts/apps/bytestash + namespace: prod + - name: calibre-web + chart: charts/apps/calibre-web + namespace: prod + - name: coder + chart: charts/apps/coder + namespace: prod + - name: data + chart: charts/apps/data + namespace: prod + - name: esphome + chart: charts/apps/esphome + namespace: prod + - name: gitea + chart: charts/apps/gitea + namespace: prod + - name: homarr + chart: charts/apps/homarr + namespace: prod + - name: home-assistant + chart: charts/apps/home-assistant + namespace: prod + - name: jellyfin + chart: charts/apps/jellyfin + namespace: prod + - name: linkwarden + chart: charts/apps/linkwarden + namespace: prod + - name: mealie + chart: charts/apps/mealie + namespace: prod + - name: metamcp + chart: charts/apps/metamcp + namespace: prod + - name: miniflux + chart: charts/apps/miniflux + namespace: prod + - name: mqtt + chart: charts/apps/mqtt + namespace: prod + - name: music-assistant + chart: charts/apps/music-assistant + namespace: prod + - name: n8n + chart: charts/apps/n8n + namespace: prod + - name: nocodb + chart: charts/apps/nocodb + namespace: prod + - name: ollama + chart: charts/apps/ollama + namespace: prod + - name: openwebui + chart: charts/apps/openwebui + namespace: prod + - name: photoprism + chart: charts/apps/photoprism + namespace: prod + - name: readeck + chart: charts/apps/readeck + namespace: prod + - name: signal + chart: charts/apps/signal + namespace: prod + - name: zot + chart: charts/apps/zot + namespace: prod diff --git a/renovate.json5 b/renovate.json5 new file mode 100644 index 0000000..126ad37 --- /dev/null +++ b/renovate.json5 @@ -0,0 +1,28 @@ +{ + "$schema": "https://docs.renovatebot.com/renovate-schema.json", + "extends": [ + "config:base" + ], + "packageRules": [ + { + "groupName": "Docker images", + "groupSlug": "dockerimages", + "matchDatasources": ["docker"], + "pinDigests": true + } + ], + "helm-values": { + "fileMatch": ["^charts/.*/values\\.yaml$"] + }, + "regexManagers": [ + { + "fileMatch": ["^charts/.*/values\\.yaml$"], + "matchStrings": [ + "repository:\s*'(?.*?)'\n\s*tag:\s*'(?.*?)'", + "repository:\s*\"(?.*?)\"\n\s*tag:\s*\"(?.*?)\"", + "repository:\s*(?.*?)\n\s*tag:\s*(?.*)" + ], + "datasourceTemplate": "docker" + } + ] +}