diff --git a/apps/charts/immich.disabled/templates/database.yaml b/apps/charts/immich.disabled/templates/database.yaml deleted file mode 100644 index 6a30b53..0000000 --- a/apps/charts/immich.disabled/templates/database.yaml +++ /dev/null @@ -1,6 +0,0 @@ -apiVersion: homelab.mortenolsen.pro/v1 -kind: PostgresDatabase -metadata: - name: '{{ .Release.Name }}' -spec: - environment: '{{ .Values.globals.environment }}' diff --git a/apps/charts/immich.disabled/templates/deployment.yaml b/apps/charts/immich.disabled/templates/deployment.yaml deleted file mode 100644 index 6b7441f..0000000 --- a/apps/charts/immich.disabled/templates/deployment.yaml +++ /dev/null @@ -1,105 +0,0 @@ -apiVersion: apps/v1 -kind: Deployment -metadata: - name: "{{ .Release.Name }}-server" -spec: - strategy: - type: Recreate - replicas: 1 - revisionHistoryLimit: 0 - selector: - matchLabels: - app: "{{ .Release.Name }}-server" - template: - metadata: - labels: - app: "{{ .Release.Name }}-server" - spec: - containers: - - name: "{{ .Release.Name }}-server" - image: "{{ .Values.server.image.repository }}:{{ .Values.server.image.tag }}" - imagePullPolicy: "{{ .Values.server.image.pullPolicy }}" - env: - - name: DB_URL - valueFrom: - secretKeyRef: - name: "{{ .Release.Name }}-pg-connection" - key: url - - name: DB_VECTOR_EXTENSION - value: pgvector - - name: REDIS_HOST - value: "{{ .Release.name }}-valkey.{{ .Release.Namespace }}.svc.cluster.local" - - name: IMMICH_PORT - value: "3003" - ports: - - name: http - containerPort: 3003 - protocol: TCP - livenessProbe: - tcpSocket: - port: http - readinessProbe: - tcpSocket: - port: http - ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: "{{ .Release.Name }}-ml" -spec: - strategy: - type: Recreate - replicas: 1 - revisionHistoryLimit: 0 - selector: - matchLabels: - app: "{{ .Release.Name }}-ml" - template: - metadata: - labels: - app: "{{ .Release.Name }}-ml" - spec: - containers: - - name: "{{ .Release.Name }}-ml" - image: "{{ .Values.ml.image.repository }}:{{ .Values.ml.image.tag }}" - imagePullPolicy: "{{ .Values.ml.image.pullPolicy }}" - env: - - name: DB_URL - valueFrom: - secretKeyRef: - name: "{{ .Release.Name }}-pg-connection" - key: url - # - name: DB_VECTOR_EXTENSION - # value: pgvector - - name: REDIS_HOST - value: "{{ .Release.name }}-valkey" - - name: IMMICH_PORT - value: "3003" ---- -apiVersion: apps/v1 -kind: Deployment -metadata: - name: "{{ .Release.Name }}-valkey" -spec: - strategy: - type: Recreate - replicas: 1 - revisionHistoryLimit: 0 - selector: - matchLabels: - app: "{{ .Release.Name }}-valkey" - template: - metadata: - labels: - app: "{{ .Release.Name }}-valkey" - spec: - containers: - - name: "{{ .Release.Name }}-valkey" - image: "{{ .Values.valkey.image.repository }}:{{ .Values.valkey.image.tag }}" - imagePullPolicy: "{{ .Values.valkey.image.pullPolicy }}" - ports: - - name: tcp - containerPort: 6379 - protocol: TCP - diff --git a/apps/charts/immich.disabled/templates/external-http-service.yaml b/apps/charts/immich.disabled/templates/external-http-service.yaml deleted file mode 100644 index f865728..0000000 --- a/apps/charts/immich.disabled/templates/external-http-service.yaml +++ /dev/null @@ -1,11 +0,0 @@ -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/apps/charts/immich.disabled/templates/virtual-service.yaml b/apps/charts/immich.disabled/templates/virtual-service.yaml deleted file mode 100644 index 0af9b24..0000000 --- a/apps/charts/immich.disabled/templates/virtual-service.yaml +++ /dev/null @@ -1,18 +0,0 @@ -apiVersion: networking.istio.io/v1 -kind: VirtualService -metadata: - name: "{{ .Release.Name }}" - namespace: "{{ .Release.Namespace }}" -spec: - gateways: - - "{{ .Values.globals.istio.gateway }}" - - mesh - hosts: - - "{{ .Values.subdomain }}.{{ .Values.globals.domain }}" - - mesh - http: - - route: - - destination: - host: "{{ .Release.Name }}" - port: - number: 80 diff --git a/apps/charts/immich.disabled/values.yaml b/apps/charts/immich.disabled/values.yaml deleted file mode 100644 index ee47b7f..0000000 --- a/apps/charts/immich.disabled/values.yaml +++ /dev/null @@ -1,16 +0,0 @@ -subdomain: penpot -server: - image: - repository: ghcr.io/immich-app/immich-server - tag: release@sha256:e6a6298e67ae077808fdb7d8d5565955f60b0708191576143fc02d30ab1389d1 - pullPolicy: IfNotPresent -ml: - image: - repository: ghcr.io/immich-app/immich-machine-learning - tag: release@sha256:b3deefd1826f113824e9d7bc30d905e7f823535887d03f869330946b6db3b44a - pullPolicy: IfNotPresent -valkey: - image: - repository: valkey/valkey - tag: 9.0@sha256:546304417feac0874c3dd576e0952c6bb8f06bb4093ea0c9ca303c73cf458f63 - pullPolicy: IfNotPresent diff --git a/apps/charts/immich.disabled/Chart.yaml b/apps/charts/immich/Chart.yaml similarity index 100% rename from apps/charts/immich.disabled/Chart.yaml rename to apps/charts/immich/Chart.yaml diff --git a/apps/charts/immich.disabled/templates/client.yaml b/apps/charts/immich/templates/client.yaml similarity index 55% rename from apps/charts/immich.disabled/templates/client.yaml rename to apps/charts/immich/templates/client.yaml index e20f15d..f8335dc 100644 --- a/apps/charts/immich.disabled/templates/client.yaml +++ b/apps/charts/immich/templates/client.yaml @@ -1,10 +1,10 @@ apiVersion: homelab.mortenolsen.pro/v1 kind: OidcClient metadata: - name: "{{ .Release.Name }}" + name: '{{ .Release.Name }}' spec: - environment: "{{ .Values.globals.environment }}" + environment: '{{ .Values.globals.environment }}' redirectUris: - path: /api/oauth/mobile-redirect - subdomain: "{{ .Values.subdomain }}" + subdomain: '{{ .Values.subdomain }}' matchingMode: strict diff --git a/apps/charts/immich/templates/database.yaml b/apps/charts/immich/templates/database.yaml new file mode 100644 index 0000000..37e87a2 --- /dev/null +++ b/apps/charts/immich/templates/database.yaml @@ -0,0 +1,114 @@ +apiVersion: homelab.mortenolsen.pro/v1 +kind: GenerateSecret +metadata: + name: "{{ .Release.Name }}-postgres-secret" +spec: + fields: + - name: password + encoding: base64 + length: 64 + +--- +apiVersion: v1 +kind: Secret +metadata: + name: "{{ .Release.Name }}-postgres" +type: Opaque +stringData: + POSTGRES_DB: immich + POSTGRES_USER: immich + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}-postgres" +spec: + strategy: + type: Recreate + replicas: 1 + revisionHistoryLimit: 0 + selector: + matchLabels: + app: "{{ .Release.Name }}-postgres" + template: + metadata: + labels: + app: "{{ .Release.Name }}-postgres" + spec: + containers: + - name: postgres + image: "{{ .Values.postgres.image.repository }}:{{ .Values.postgres.image.tag }}" + imagePullPolicy: "{{ .Values.postgres.image.pullPolicy }}" + env: + - name: POSTGRES_DB + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-postgres" + key: POSTGRES_DB + - name: POSTGRES_USER + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-postgres" + key: POSTGRES_USER + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + name: "{{ .Release.Name }}-postgres-secret" + key: password + - name: PGDATA + value: /var/lib/postgresql/data/pgdata + ports: + - name: postgres + containerPort: 5432 + protocol: TCP + volumeMounts: + - mountPath: /var/lib/postgresql/data + name: postgres-data + livenessProbe: + exec: + command: + - /bin/sh + - -c + - pg_isready -U immich + readinessProbe: + exec: + command: + - /bin/sh + - -c + - pg_isready -U immich + volumes: + - name: postgres-data + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-postgres-data" + +--- +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}-postgres" + labels: + app: "{{ .Release.Name }}-postgres" +spec: + type: ClusterIP + ports: + - port: 5432 + targetPort: 5432 + protocol: TCP + name: postgres + selector: + app: "{{ .Release.Name }}-postgres" + +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: "{{ .Release.Name }}-postgres-data" +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Gi + storageClassName: "{{ .Values.globals.environment }}" + diff --git a/apps/charts/immich/templates/db-config-job.yaml b/apps/charts/immich/templates/db-config-job.yaml new file mode 100644 index 0000000..d674358 --- /dev/null +++ b/apps/charts/immich/templates/db-config-job.yaml @@ -0,0 +1,85 @@ +apiVersion: batch/v1 +kind: Job +metadata: + name: "{{ .Release.Name }}-db-config-generator" + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-weight": "5" + "helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded +spec: + template: + metadata: + annotations: + sidecar.istio.io/inject: "false" + spec: + restartPolicy: OnFailure + serviceAccountName: "{{ .Release.Name }}-db-config-sa" + containers: + - name: generator + image: python:3.11-slim + command: + - /bin/bash + - -c + - | + set -e + # Install kubectl + apt-get update -qq && apt-get install -y -qq curl > /dev/null 2>&1 && \ + curl -sSL "https://dl.k8s.io/release/$(curl -sL https://dl.k8s.io/release/stable.txt)/bin/linux/amd64/kubectl" -o /tmp/kubectl && \ + chmod +x /tmp/kubectl && mv /tmp/kubectl /usr/local/bin/kubectl + + PASSWORD=$(cat /secrets/password) + # URL encode the password to handle special characters using Python + ENCODED_PASSWORD=$(python3 -c "import urllib.parse; import sys; print(urllib.parse.quote(sys.stdin.read().strip(), safe=''))" <<< "$PASSWORD") + DB_URL="postgresql://immich:${ENCODED_PASSWORD}@{{ .Release.Name }}-postgres.{{ .Release.Namespace }}.svc.cluster.local:5432/immich" + # Create or update the ConfigMap + kubectl create configmap {{ .Release.Name }}-db-config --from-literal=url="${DB_URL}" --dry-run=client -o yaml | kubectl apply -f - + echo "ConfigMap {{ .Release.Name }}-db-config created/updated successfully" + volumeMounts: + - name: postgres-secret + mountPath: /secrets + readOnly: true + volumes: + - name: postgres-secret + secret: + secretName: "{{ .Release.Name }}-postgres-secret" + +--- +apiVersion: v1 +kind: ServiceAccount +metadata: + name: "{{ .Release.Name }}-db-config-sa" + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-weight": "-10" + "helm.sh/hook-delete-policy": before-hook-creation + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: Role +metadata: + name: "{{ .Release.Name }}-db-config-role" + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-weight": "-9" + "helm.sh/hook-delete-policy": before-hook-creation +rules: + - apiGroups: [""] + resources: ["configmaps"] + verbs: ["get", "create", "update", "patch", "delete"] + +--- +apiVersion: rbac.authorization.k8s.io/v1 +kind: RoleBinding +metadata: + name: "{{ .Release.Name }}-db-config-rolebinding" + annotations: + "helm.sh/hook": pre-install,pre-upgrade + "helm.sh/hook-weight": "-8" + "helm.sh/hook-delete-policy": before-hook-creation +subjects: + - kind: ServiceAccount + name: "{{ .Release.Name }}-db-config-sa" +roleRef: + kind: Role + name: "{{ .Release.Name }}-db-config-role" + apiGroup: rbac.authorization.k8s.io diff --git a/apps/charts/immich/templates/deployment.yaml b/apps/charts/immich/templates/deployment.yaml new file mode 100644 index 0000000..5949289 --- /dev/null +++ b/apps/charts/immich/templates/deployment.yaml @@ -0,0 +1,194 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}-server" +spec: + strategy: + type: Recreate + replicas: 1 + revisionHistoryLimit: 0 + selector: + matchLabels: + app: "{{ .Release.Name }}-server" + template: + metadata: + labels: + app: "{{ .Release.Name }}-server" + spec: + containers: + - name: "{{ .Release.Name }}-server" + image: "{{ .Values.server.image.repository }}:{{ .Values.server.image.tag }}" + imagePullPolicy: "{{ .Values.server.image.pullPolicy }}" + env: + - name: DB_URL + valueFrom: + configMapKeyRef: + name: "{{ .Release.Name }}-db-config" + key: url + - name: DB_VECTOR_EXTENSION + value: pgvector + - name: REDIS_HOSTNAME + value: "{{ .Release.Name }}-valkey.{{ .Release.Namespace }}.svc.cluster.local" + - name: REDIS_HOST + value: "{{ .Release.Name }}-valkey.{{ .Release.Namespace }}.svc.cluster.local" + - name: REDIS_PORT + value: "6379" + - name: REDIS_URL + value: "redis://{{ .Release.Name }}-valkey.{{ .Release.Namespace }}.svc.cluster.local:6379" + - name: IMMICH_REDIS_HOSTNAME + value: "{{ .Release.Name }}-valkey.{{ .Release.Namespace }}.svc.cluster.local" + - name: IMMICH_PORT + value: "3003" + - name: IMMICH_UPLOAD_LOCATION + value: /usr/src/app/upload + - name: IMMICH_MACHINE_LEARNING_URL + value: http://{{ .Release.Name }}-ml.{{ .Release.Namespace }}.svc.cluster.local:3003 + - name: OAUTH_AUTO_REGISTER + value: "true" + - name: OAUTH_AUTO_LAUNCH + value: "true" + - name: OAUTH_BUTTON_TEXT + value: "Login with OAuth" + - name: OAUTH_ENABLED + value: "true" + - name: OAUTH_ISSUER_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: OAUTH_SCOPE + value: "openid profile email" + - name: OAUTH_STORAGE_LABEL_CLAIM + value: "preferred_username" + ports: + - name: http + containerPort: 3003 + protocol: TCP + volumeMounts: + - mountPath: /usr/src/app/upload + name: upload + - mountPath: /usr/src/app/library + name: library + - mountPath: /mnt/media/nas + name: nas + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + volumes: + - name: upload + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-upload" + - name: library + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-library" + - name: nas + persistentVolumeClaim: + claimName: pictures + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}-ml" +spec: + strategy: + type: Recreate + replicas: 1 + revisionHistoryLimit: 0 + selector: + matchLabels: + app: "{{ .Release.Name }}-ml" + template: + metadata: + labels: + app: "{{ .Release.Name }}-ml" + spec: + containers: + - name: "{{ .Release.Name }}-ml" + image: "{{ .Values.ml.image.repository }}:{{ .Values.ml.image.tag }}" + imagePullPolicy: "{{ .Values.ml.image.pullPolicy }}" + env: + - name: DB_URL + valueFrom: + configMapKeyRef: + name: "{{ .Release.Name }}-db-config" + key: url + - name: DB_VECTOR_EXTENSION + value: pgvector + - name: REDIS_HOSTNAME + value: "{{ .Release.Name }}-valkey.{{ .Release.Namespace }}.svc.cluster.local" + - name: REDIS_HOST + value: "{{ .Release.Name }}-valkey.{{ .Release.Namespace }}.svc.cluster.local" + - name: REDIS_PORT + value: "6379" + - name: REDIS_URL + value: "redis://{{ .Release.Name }}-valkey.{{ .Release.Namespace }}.svc.cluster.local:6379" + - name: IMMICH_REDIS_HOSTNAME + value: "{{ .Release.Name }}-valkey.{{ .Release.Namespace }}.svc.cluster.local" + - name: IMMICH_PORT + value: "3003" + - name: IMMICH_MACHINE_LEARNING_MODEL_PATH + value: /cache + ports: + - name: http + containerPort: 3003 + protocol: TCP + volumeMounts: + - mountPath: /cache + name: model-cache + livenessProbe: + tcpSocket: + port: http + readinessProbe: + tcpSocket: + port: http + volumes: + - name: model-cache + persistentVolumeClaim: + claimName: "{{ .Release.Name }}-model-cache" + +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: "{{ .Release.Name }}-valkey" +spec: + strategy: + type: Recreate + replicas: 1 + revisionHistoryLimit: 0 + selector: + matchLabels: + app: "{{ .Release.Name }}-valkey" + template: + metadata: + labels: + app: "{{ .Release.Name }}-valkey" + spec: + containers: + - name: "{{ .Release.Name }}-valkey" + image: "{{ .Values.valkey.image.repository }}:{{ .Values.valkey.image.tag }}" + imagePullPolicy: "{{ .Values.valkey.image.pullPolicy }}" + ports: + - name: tcp + containerPort: 6379 + protocol: TCP + livenessProbe: + tcpSocket: + port: tcp + readinessProbe: + tcpSocket: + port: tcp diff --git a/apps/charts/immich/templates/external-http-service.yaml b/apps/charts/immich/templates/external-http-service.yaml new file mode 100644 index 0000000..e28916d --- /dev/null +++ b/apps/charts/immich/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/apps/charts/immich/templates/pvc.yaml b/apps/charts/immich/templates/pvc.yaml new file mode 100644 index 0000000..fe91408 --- /dev/null +++ b/apps/charts/immich/templates/pvc.yaml @@ -0,0 +1,37 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: "{{ .Release.Name }}-upload" +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Gi + storageClassName: "{{ .Values.globals.environment }}" + +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: "{{ .Release.Name }}-library" +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 100Gi + storageClassName: "{{ .Values.globals.environment }}" + +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: "{{ .Release.Name }}-model-cache" +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi + storageClassName: "{{ .Values.globals.environment }}" diff --git a/apps/charts/immich.disabled/templates/service.yaml b/apps/charts/immich/templates/service.yaml similarity index 58% rename from apps/charts/immich.disabled/templates/service.yaml rename to apps/charts/immich/templates/service.yaml index 8ad857d..c8caaa3 100644 --- a/apps/charts/immich.disabled/templates/service.yaml +++ b/apps/charts/immich/templates/service.yaml @@ -14,13 +14,30 @@ spec: selector: app: "{{ .Release.Name }}-valkey" +--- +apiVersion: v1 +kind: Service +metadata: + name: "{{ .Release.Name }}-ml" + labels: + app: "{{ .Release.Name }}-ml" +spec: + type: ClusterIP + ports: + - port: 3003 + targetPort: 3003 + protocol: TCP + name: http + selector: + app: "{{ .Release.Name }}-ml" + --- apiVersion: v1 kind: Service metadata: name: "{{ .Release.Name }}" labels: - app: "{{ .Release.Name }}" + app: "{{ .Release.Name }}-server" spec: type: ClusterIP ports: @@ -29,5 +46,4 @@ spec: protocol: TCP name: http selector: - app: "{{ .Release.Name }}" - + app: "{{ .Release.Name }}-server" diff --git a/apps/charts/immich/values.yaml b/apps/charts/immich/values.yaml new file mode 100644 index 0000000..e505b25 --- /dev/null +++ b/apps/charts/immich/values.yaml @@ -0,0 +1,21 @@ +subdomain: immich +server: + image: + repository: ghcr.io/immich-app/immich-server + tag: release + pullPolicy: IfNotPresent +ml: + image: + repository: ghcr.io/immich-app/immich-machine-learning + tag: release + pullPolicy: IfNotPresent +valkey: + image: + repository: valkey/valkey + tag: 9.0 + pullPolicy: IfNotPresent +postgres: + image: + repository: pgvector/pgvector + tag: pg16 + pullPolicy: IfNotPresent