diff --git a/main.tf b/main.tf index 6ebaf117..cd612081 100644 --- a/main.tf +++ b/main.tf @@ -55,6 +55,7 @@ variable "finance_app_graphql_api_secret" {} variable "finance_app_gocardless_secret_key" {} variable "finance_app_gocardless_secret_id" {} variable "headscale_config" {} +variable "immich_postgresql_password" {} variable "ansible_prefix" { default = "ANSIBLE_VAULT_PASSWORD_FILE=~/.ansible/vault_pass.txt ansible-playbook -i playbook/hosts.yaml playbook/linux.yml -t linux/initial_setup" @@ -277,6 +278,8 @@ module "kubernetes_cluster" { finance_app_gocardless_secret_id = var.finance_app_gocardless_secret_id headscale_config = var.headscale_config + + immich_postgresql_password = var.immich_postgresql_password } diff --git a/modules/kubernetes/immich/chart_values.tpl b/modules/kubernetes/immich/chart_values.tpl new file mode 100644 index 00000000..6c999d7e --- /dev/null +++ b/modules/kubernetes/immich/chart_values.tpl @@ -0,0 +1,128 @@ +## This chart relies on the common library chart from bjw-s +## You can find it at https://github.com/bjw-s/helm-charts/tree/main/charts/library/common +## Refer there for more detail about the supported values + +# These entries are shared between all the Immich components + +env: + # REDIS_HOSTNAME: '{{ printf "%s-redis-master" .Release.Name }}' + REDIS_HOSTNAME: "redis.redis.svc.cluster.local" + # DB_HOSTNAME: "{{ .Release.Name }}-postgresql" + # DB_USERNAME: "{{ .Values.postgresql.global.postgresql.auth.username }}" + # DB_DATABASE_NAME: "{{ .Values.postgresql.global.postgresql.auth.database }}" + # # -- You should provide your own secret outside of this helm-chart and use `postgresql.global.postgresql.auth.existingSecret` to provide credentials to the postgresql instance + # DB_PASSWORD: "{{ .Values.postgresql.global.postgresql.auth.password }}" + # TYPESENSE_ENABLED: "{{ .Values.typesense.enabled }}" + TYPESENSE_ENABLED: "1" + # TYPESENSE_API_KEY: "{{ .Values.typesense.env.TYPESENSE_API_KEY }}" + # TYPESENSE_HOST: '{{ printf "%s-typesense" .Release.Name }}' + # IMMICH_WEB_URL: '{{ printf "http://%s-web:3000" .Release.Name }}' + IMMICH_WEB_URL: "http://immich-web.immich.svc.cluster.local:3000" + # IMMICH_SERVER_URL: '{{ printf "http://%s-server:3001" .Release.Name }}' + IMMICH_SERVER_URL: "http://immich-server.immich.svc.cluster.local:3001" + # IMMICH_MACHINE_LEARNING_URL: '{{ printf "http://%s-machine-learning:3003" .Release.Name }}' + IMMICH_MACHINE_LEARNING_URL: "http://immich-machine-learning.immich.svc.cluster.local:3003" + +image: + tag: v1.87.0 + +immich: + persistence: + # Main data store for all photos shared between different components. + library: + # Automatically creating the library volume is not supported by this chart + # You have to specify an existing PVC to use + existingClaim: immich + +# Dependencies + +postgresql: + enabled: true + global: + postgresql: + auth: + username: immich + database: immich + password: "${postgresql_password}" + +redis: + enabled: false + architecture: standalone + auth: + enabled: false + +typesense: + enabled: true + env: + TYPESENSE_DATA_DIR: /tsdata + TYPESENSE_API_KEY: typesense + persistence: + tsdata: + # Enabling typesense persistence is recommended to avoid slow reindexing + enabled: true + accessMode: ReadWriteOnce + size: 1Gi + # storageClass: storage-class + image: + repository: docker.io/typesense/typesense + tag: 0.24.0 + pullPolicy: IfNotPresent + +# Immich components + +server: + enabled: true + image: + repository: ghcr.io/immich-app/immich-server + pullPolicy: IfNotPresent + +microservices: + enabled: true + env: + REVERSE_GEOCODING_DUMP_DIRECTORY: /geodata-cache + persistence: + geodata-cache: + enabled: true + size: 1Gi + # Optional: Set this to pvc to avoid downloading the geodata every start. + type: emptyDir + accessMode: ReadWriteMany + # storageClass: your-class + image: + repository: ghcr.io/immich-app/immich-server + pullPolicy: IfNotPresent + +machine-learning: + enabled: true + image: + repository: ghcr.io/immich-app/immich-machine-learning + pullPolicy: IfNotPresent + env: + TRANSFORMERS_CACHE: /cache + persistence: + cache: + enabled: true + size: 10Gi + # Optional: Set this to pvc to avoid downloading the ML models every start. + type: emptyDir + accessMode: ReadWriteMany + # storageClass: your-class + +web: + enabled: true + image: + repository: ghcr.io/immich-app/immich-web + pullPolicy: IfNotPresent + persistence: + library: + enabled: false + +proxy: + enabled: true + image: + repository: ghcr.io/immich-app/immich-proxy + pullPolicy: IfNotPresent + + persistence: + library: + enabled: false diff --git a/modules/kubernetes/immich/main.tf b/modules/kubernetes/immich/main.tf new file mode 100644 index 00000000..20437192 --- /dev/null +++ b/modules/kubernetes/immich/main.tf @@ -0,0 +1,163 @@ +variable "tls_secret_name" {} +variable "postgresql_password" {} + +module "tls_secret" { + source = "../setup_tls_secret" + namespace = "immich" + tls_secret_name = var.tls_secret_name +} + +resource "kubernetes_namespace" "immich" { + metadata { + name = "immich" + } +} + +resource "kubernetes_persistent_volume" "immich-postgresql" { + metadata { + name = "immich-postgresql" + } + spec { + capacity = { + "storage" = "10Gi" + } + access_modes = ["ReadWriteOnce"] + persistent_volume_source { + nfs { + path = "/mnt/main/immich/data-immich-postgresql" + server = "10.0.10.15" + } + } + } +} + +resource "kubernetes_persistent_volume" "immich" { + metadata { + name = "immich" + } + spec { + capacity = { + "storage" = "100Gi" + } + access_modes = ["ReadWriteOnce"] + persistent_volume_source { + nfs { + path = "/mnt/main/immich/immich" + server = "10.0.10.15" + } + } + } +} + +resource "kubernetes_persistent_volume" "immich-typesense-tsdata" { + metadata { + name = "immich-typesense-tsdata" + } + spec { + capacity = { + "storage" = "5Gi" + } + access_modes = ["ReadWriteOnce"] + persistent_volume_source { + nfs { + path = "/mnt/main/immich/typesense-tsdata" + server = "10.0.10.15" + } + } + } +} +resource "kubernetes_persistent_volume_claim" "immich" { + metadata { + name = "immich" + namespace = "immich" + } + spec { + access_modes = ["ReadWriteOnce"] + resources { + requests = { + "storage" = "20Gi" + } + } + volume_name = "immich" + } +} + +resource "helm_release" "immich" { + namespace = "immich" + name = "immich" + + repository = "https://immich-app.github.io/immich-charts" + chart = "immich" + atomic = true + + values = [templatefile("${path.module}/chart_values.tpl", { postgresql_password = var.postgresql_password })] +} + +resource "kubernetes_ingress_v1" "immich" { + metadata { + name = "immich" + namespace = "immich" + annotations = { + "kubernetes.io/ingress.class" = "nginx" + # "nginx.ingress.kubernetes.io/auth-url" : "https://oauth2.viktorbarzin.me/oauth2/auth" + # "nginx.ingress.kubernetes.io/auth-signin" : "https://oauth2.viktorbarzin.me/oauth2/start?rd=/redirect/$http_host$escaped_request_uri" + "nginx.ingress.kubernetes.io/proxy-body-size" : "5000m" + } + } + + spec { + tls { + hosts = ["immich.viktorbarzin.me"] + secret_name = var.tls_secret_name + } + rule { + host = "immich.viktorbarzin.me" + http { + path { + path = "/" + backend { + service { + name = "immich-proxy" + port { + number = 8080 + } + } + } + } + } + } + } +} +resource "kubernetes_ingress_v1" "photos" { + metadata { + name = "photos" + namespace = "immich" + annotations = { + "kubernetes.io/ingress.class" = "nginx" + "nginx.ingress.kubernetes.io/proxy-body-size" : "5000m" + } + } + + spec { + tls { + hosts = ["photos.viktorbarzin.me"] + secret_name = var.tls_secret_name + } + rule { + host = "photos.viktorbarzin.me" + http { + path { + path = "/" + backend { + service { + name = "immich-proxy" + port { + number = 8080 + } + } + } + } + } + } + } +} diff --git a/modules/kubernetes/main.tf b/modules/kubernetes/main.tf index 0607c0bb..200b7dbb 100644 --- a/modules/kubernetes/main.tf +++ b/modules/kubernetes/main.tf @@ -42,6 +42,7 @@ variable "finance_app_graphql_api_secret" {} variable "finance_app_gocardless_secret_key" {} variable "finance_app_gocardless_secret_id" {} variable "headscale_config" {} +variable "immich_postgresql_password" {} resource "null_resource" "core_services" { # List all the core modules that must be provisioned first @@ -332,3 +333,13 @@ module "ytdlp" { source = "./youtube_dl" tls_secret_name = var.tls_secret_name } + +module "immich" { + source = "./immich" + tls_secret_name = var.tls_secret_name + postgresql_password = var.immich_postgresql_password +} + +# module "nginx-ingress" { +# source = "./nginx-ingress" +# }