feat(immich): add immich (#3942)

* feat(immich): add immich

* quote bool

* mount nginx config on proxy

* run as node user

* fix CM

* hmm

* make entrypoint executables

* server entrypoint

* whoops

* chmod something..

* add mapbox keys

* fix cm

* fix cm

* add some probes

* one mroe probe

* split configmap

* add ui

* add all db envs to ML

* passwds also
This commit is contained in:
Stavros Kois
2022-09-29 01:08:30 +03:00
committed by GitHub
parent 8b02189f7e
commit 0b354fa151
14 changed files with 697 additions and 0 deletions
+30
View File
@@ -0,0 +1,30 @@
# Patterns to ignore when building packages.
# This supports shell glob matching, relative path matching, and
# negation (prefixed with !). Only one pattern per line.
.DS_Store
# Common VCS dirs
.git/
.gitignore
.bzr/
.bzrignore
.hg/
.hgignore
.svn/
# Common backup files
*.swp
*.bak
*.tmp
*~
# Various IDEs
.project
.idea/
*.tmproj
.vscode/
# OWNERS file for Kubernetes
OWNERS
# helm-docs templates
*.gotmpl
# docs folder
/docs
# icon
icon.png
+33
View File
@@ -0,0 +1,33 @@
apiVersion: v2
appVersion: "10.6.2"
dependencies:
- name: common
repository: https://library-charts.truecharts.org
version: 10.6.4
- condition: postgresql.enabled
name: postgresql
repository: https://charts.truecharts.org/
version: 8.0.88
- condition: redis.enabled
name: redis
repository: https://charts.truecharts.org
version: 3.0.85
description: High performance self-hosted photo and video backup solution.
home: https://truecharts.org/docs/charts/stable/airsonic
icon: https://truecharts.org/img/hotlink-ok/chart-icons/airsonic.png
keywords:
- photos
kubeVersion: ">=1.16.0-0"
maintainers:
- email: info@truecharts.org
name: TrueCharts
url: https://truecharts.org
name: immich
sources:
- https://github.com/immich-app/immich
version: 0.0.1
annotations:
truecharts.org/catagories: |
- media
truecharts.org/SCALE-support: "true"
truecharts.org/grade: U
View File
Binary file not shown.

After

Width:  |  Height:  |  Size: 69 KiB

+166
View File
@@ -0,0 +1,166 @@
# Include{groups}
portals:
open:
# Include{portalLink}
questions:
# Include{global}
# Include{controller}
# Include{controllerDeployment}
# Include{replicas}
# Include{replica1}
# Include{strategy}
# Include{recreate}
# Include{controllerExpert}
# Include{controllerExpertExtraArgs}
- variable: immich
group: Container Configuration
label: Immich Configuration
schema:
additional_attrs: true
type: dict
attrs:
- variable: public_login_page_message
label: Public Login Page Message
description: Custom message on the login page, should be written in HTML form.
schema:
type: string
default: ""
- variable: disable_reverse_geocoding
label: Disable Reverse Geocoding
schema:
type: boolean
default: false
- variable: reverse_geocoding_precision
label: Reverse Geocoding Precision
description: Reverse geocoding is done locally which has a small impact on memory usage. (Valid options 0 - 3)
schema:
type: int
show_if: [["disable_reverse_geocoding", "=", "false"]]
default: 3
- variable: mapbox_enable
label: Enable MapBox
schema:
type: boolean
default: false
- variable: mapbox_key
label: MaxBox Key
schema:
type: string
private: true
show_if: [["maxbox_enable", "=", "false"]]
default: ""
- variable: log_level
label: Log Level
schema:
type: string
default: simple
enum:
- value: simple
description: simple
- value: verbose
description: verbose
# Include{containerConfig}
# Include{serviceRoot}
- variable: main
label: Main Service
description: The Primary service on which the healthcheck runs, often the webUI
schema:
additional_attrs: true
type: dict
attrs:
# Include{serviceSelectorLoadBalancer}
# Include{serviceSelectorExtras}
- variable: main
label: Main Service Port Configuration
schema:
additional_attrs: true
type: dict
attrs:
- variable: port
label: Port
description: This port exposes the container port on the service
schema:
type: int
default: 10323
required: true
# Include{advancedPortHTTP}
- variable: targetPort
label: Target Port
description: The internal(!) port on the container the Application runs on
schema:
type: int
default: 10323
# Include{serviceExpertRoot}
default: false
# Include{serviceExpert}
# Include{serviceList}
# Include{persistenceRoot}
- variable: uploads
label: App Uploads Storage
description: Stores the Application Uploads.
schema:
additional_attrs: true
type: dict
attrs:
# Include{persistenceBasic}
# Include{persistenceAdvanced}
# Include{persistenceList}
# Include{ingressRoot}
- variable: main
label: Main Ingress
schema:
additional_attrs: true
type: dict
attrs:
# Include{ingressDefault}
# Include{ingressTLS}
# Include{ingressTraefik}
# Include{ingressExpert}
# Include{ingressList}
# Include{security}
# Include{securityContextAdvancedRoot}
- variable: privileged
label: Privileged mode
schema:
type: boolean
default: false
- variable: readOnlyRootFilesystem
label: ReadOnly Root Filesystem
schema:
type: boolean
default: false
- variable: allowPrivilegeEscalation
label: Allow Privilege Escalation
schema:
type: boolean
default: false
- variable: runAsNonRoot
label: runAsNonRoot
schema:
type: boolean
default: false
# Include{securityContextAdvanced}
# Include{podSecurityContextRoot}
- variable: runAsUser
label: runAsUser
description: The UserID of the user running the application
schema:
type: int
default: 0
- variable: runAsGroup
label: runAsGroup
description: The groupID this App of the user running the application
schema:
type: int
default: 0
- variable: fsGroup
label: fsGroup
description: The group that should own ALL storage.
schema:
type: int
default: 568
# Include{podSecurityContextAdvanced}
# Include{resources}
# Include{advanced}
# Include{addons}
# Include{documentation}
@@ -0,0 +1,142 @@
{{/* Define the configmap */}}
{{- define "immich.config" -}}
{{- $serverConfigName := printf "%s-server-config" (include "tc.common.names.fullname" .) }}
{{- $commonConfigName := printf "%s-common-config" (include "tc.common.names.fullname" .) }}
{{- $proxyConfigName := printf "%s-proxy-config" (include "tc.common.names.fullname" .) }}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ $serverConfigName }}
labels:
{{- include "tc.common.labels" . | nindent 4 }}
data:
DB_HOSTNAME: {{ printf "%v-%v" .Release.Name "postgresql" }}
DB_USERNAME: {{ .Values.postgresql.postgresqlUsername }}
DB_DATABASE_NAME: {{ .Values.postgresql.postgresqlDatabase }}
DB_PORT: "5432"
REDIS_HOSTNAME: {{ printf "%v-%v" .Release.Name "redis" }}
REDIS_PORT: "6379"
REDIS_DBINDEX: "0"
{{/* User Defined */}}
DISABLE_REVERSE_GEOCODING: {{ .Values.immich.disable_reverse_geocoding | quote }}
REVERSE_GEOCODING_PRECISION: {{ .Values.immich.reverse_geocoding_precision | quote }}
ENABLE_MAPBOX: {{ .Values.immich.mapbox_enable | quote }}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ $commonConfigName }}
labels:
{{- include "tc.common.labels" . | nindent 4 }}
data:
NODE_ENV: production
{{/* User Defined */}}
PUBLIC_LOGIN_PAGE_MESSAGE: {{ .Values.immich.public_login_page_message }}
LOG_LEVEL: {{ .Values.immich.log_level }}
---
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ $proxyConfigName }}
labels:
{{- include "tc.common.labels" . | nindent 4 }}
data:
nginx.conf: |
worker_processes auto;
error_log /var/log/nginx/error.log;
pid /tmp/nginx.pid;
# Load dynamic modules. See /usr/share/doc/nginx/README.dynamic.
include /usr/share/nginx/modules/*.conf;
events {
worker_connections 1024;
}
http {
map $http_upgrade $connection_upgrade {
default upgrade;
'' close;
}
client_body_temp_path /tmp/client_temp;
proxy_temp_path /tmp/proxy_temp_path;
fastcgi_temp_path /tmp/fastcgi_temp;
uwsgi_temp_path /tmp/uwsgi_temp;
scgi_temp_path /tmp/scgi_temp;
# events {
# worker_connections 1000;
# }
server {
gzip on;
gzip_min_length 1000;
gunzip on;
client_max_body_size 50000M;
listen {{ .Values.service.main.ports.main.port }};
access_log off;
location /api {
# Compression
gzip_static on;
gzip_min_length 1000;
gzip_comp_level 2;
proxy_buffering off;
proxy_buffer_size 16k;
proxy_busy_buffers_size 24k;
proxy_buffers 64 4k;
proxy_force_ranges on;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
rewrite /api/(.*) /$1 break;
# Server Container
proxy_pass http://localhost:3001;
}
location / {
# Compression
gzip_static on;
gzip_min_length 1000;
gzip_comp_level 2;
proxy_buffering off;
proxy_buffer_size 16k;
proxy_busy_buffers_size 24k;
proxy_buffers 64 4k;
proxy_force_ranges on;
proxy_http_version 1.1;
proxy_set_header Host $host;
proxy_set_header X-Real-IP $remote_addr;
proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for;
proxy_set_header X-Forwarded-Proto $scheme;
proxy_set_header Upgrade $http_upgrade;
proxy_set_header Connection "upgrade";
proxy_set_header Host $host;
# Web Container
proxy_pass http://localhost:3000;
}
}
}
{{- end -}}
@@ -0,0 +1,49 @@
{{/* Define the ml container */}}
{{- define "immich.microservices" -}}
image: {{ .Values.image.repository }}:{{ .Values.image.tag }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
securityContext:
runAsUser: {{ .Values.podSecurityContext.runAsUser }}
runAsGroup: {{ .Values.podSecurityContext.runAsGroup }}
readOnlyRootFilesystem: {{ .Values.securityContext.readOnlyRootFilesystem }}
runAsNonRoot: {{ .Values.securityContext.runAsNonRoot }}
command:
- /bin/sh
- -c
- ./start-microservices.sh
volumeMounts:
- name: uploads
mountPath: {{ .Values.persistence.uploads.mountPath }}
envFrom:
- secretRef:
name: '{{ include "tc.common.names.fullname" . }}-immich-secret'
- configMapRef:
name: '{{ include "tc.common.names.fullname" . }}-common-config'
- configMapRef:
name: '{{ include "tc.common.names.fullname" . }}-server-config'
#TODO: Add probes, probably checking if process is running?
# readinessProbe:
# httpGet:
# path: /
# port: {{ .Values.service.main.ports.main.port }}
# initialDelaySeconds: {{ .Values.probes.readiness.spec.initialDelaySeconds }}
# timeoutSeconds: {{ .Values.probes.readiness.spec.timeoutSeconds }}
# periodSeconds: {{ .Values.probes.readiness.spec.periodSeconds }}
# failureThreshold: {{ .Values.probes.readiness.spec.failureThreshold }}
# livenessProbe:
# httpGet:
# path: /
# port: {{ .Values.service.main.ports.main.port }}
# initialDelaySeconds: {{ .Values.probes.liveness.spec.initialDelaySeconds }}
# timeoutSeconds: {{ .Values.probes.liveness.spec.timeoutSeconds }}
# periodSeconds: {{ .Values.probes.liveness.spec.periodSeconds }}
# failureThreshold: {{ .Values.probes.liveness.spec.failureThreshold }}
# startupProbe:
# httpGet:
# path: /
# port: {{ .Values.service.main.ports.main.port }}
# initialDelaySeconds: {{ .Values.probes.startup.spec.initialDelaySeconds }}
# timeoutSeconds: {{ .Values.probes.startup.spec.timeoutSeconds }}
# periodSeconds: {{ .Values.probes.startup.spec.periodSeconds }}
# failureThreshold: {{ .Values.probes.startup.spec.failureThreshold }}
{{- end -}}
+49
View File
@@ -0,0 +1,49 @@
{{/* Define the ml container */}}
{{- define "immich.ml" -}}
image: {{ .Values.imageML.repository }}:{{ .Values.imageML.tag }}
imagePullPolicy: {{ .Values.imageML.pullPolicy }}
securityContext:
runAsUser: {{ .Values.podSecurityContext.runAsUser }}
runAsGroup: {{ .Values.podSecurityContext.runAsGroup }}
readOnlyRootFilesystem: {{ .Values.securityContext.readOnlyRootFilesystem }}
runAsNonRoot: {{ .Values.securityContext.runAsNonRoot }}
command:
- /bin/sh
- -c
- chmod +x ./entrypoint.sh && ./entrypoint.sh
volumeMounts:
- name: uploads
mountPath: {{ .Values.persistence.uploads.mountPath }}
envFrom:
- configMapRef:
name: '{{ include "tc.common.names.fullname" . }}-common-config'
- configMapRef:
name: '{{ include "tc.common.names.fullname" . }}-server-config'
- secretRef:
name: '{{ include "tc.common.names.fullname" . }}-immich-secret'
#TODO: Add probes, probably checking if process is running?
# readinessProbe:
# httpGet:
# path: /
# port: {{ .Values.service.main.ports.main.port }}
# initialDelaySeconds: {{ .Values.probes.readiness.spec.initialDelaySeconds }}
# timeoutSeconds: {{ .Values.probes.readiness.spec.timeoutSeconds }}
# periodSeconds: {{ .Values.probes.readiness.spec.periodSeconds }}
# failureThreshold: {{ .Values.probes.readiness.spec.failureThreshold }}
# livenessProbe:
# httpGet:
# path: /
# port: {{ .Values.service.main.ports.main.port }}
# initialDelaySeconds: {{ .Values.probes.liveness.spec.initialDelaySeconds }}
# timeoutSeconds: {{ .Values.probes.liveness.spec.timeoutSeconds }}
# periodSeconds: {{ .Values.probes.liveness.spec.periodSeconds }}
# failureThreshold: {{ .Values.probes.liveness.spec.failureThreshold }}
# startupProbe:
# httpGet:
# path: /
# port: {{ .Values.service.main.ports.main.port }}
# initialDelaySeconds: {{ .Values.probes.startup.spec.initialDelaySeconds }}
# timeoutSeconds: {{ .Values.probes.startup.spec.timeoutSeconds }}
# periodSeconds: {{ .Values.probes.startup.spec.periodSeconds }}
# failureThreshold: {{ .Values.probes.startup.spec.failureThreshold }}
{{- end -}}
@@ -0,0 +1,44 @@
{{/* Define the proxy container */}}
{{- define "immich.proxy" -}}
image: {{ .Values.imageProxy.repository }}:{{ .Values.imageProxy.tag }}
imagePullPolicy: {{ .Values.imageProxy.pullPolicy }}
securityContext:
runAsUser: {{ .Values.podSecurityContext.runAsUser }}
runAsGroup: {{ .Values.podSecurityContext.runAsGroup }}
readOnlyRootFilesystem: {{ .Values.securityContext.readOnlyRootFilesystem }}
runAsNonRoot: {{ .Values.securityContext.runAsNonRoot }}
envFrom:
- configMapRef:
name: '{{ include "tc.common.names.fullname" . }}-common-config'
volumeMounts:
- name: proxy-conf
mountPath: /etc/nginx
readOnly: true
ports:
- containerPort: {{ .Values.service.main.ports.main.port }}
name: main
readinessProbe:
httpGet:
path: /api/server-info/ping
port: {{ .Values.service.main.ports.main.port }}
initialDelaySeconds: {{ .Values.probes.readiness.spec.initialDelaySeconds }}
timeoutSeconds: {{ .Values.probes.readiness.spec.timeoutSeconds }}
periodSeconds: {{ .Values.probes.readiness.spec.periodSeconds }}
failureThreshold: {{ .Values.probes.readiness.spec.failureThreshold }}
livenessProbe:
httpGet:
path: /api/server-info/ping
port: {{ .Values.service.main.ports.main.port }}
initialDelaySeconds: {{ .Values.probes.liveness.spec.initialDelaySeconds }}
timeoutSeconds: {{ .Values.probes.liveness.spec.timeoutSeconds }}
periodSeconds: {{ .Values.probes.liveness.spec.periodSeconds }}
failureThreshold: {{ .Values.probes.liveness.spec.failureThreshold }}
startupProbe:
httpGet:
path: /api/server-info/ping
port: {{ .Values.service.main.ports.main.port }}
initialDelaySeconds: {{ .Values.probes.startup.spec.initialDelaySeconds }}
timeoutSeconds: {{ .Values.probes.startup.spec.timeoutSeconds }}
periodSeconds: {{ .Values.probes.startup.spec.periodSeconds }}
failureThreshold: {{ .Values.probes.startup.spec.failureThreshold }}
{{- end -}}
@@ -0,0 +1,27 @@
{{/* Define the secret */}}
{{- define "immich.secret" -}}
{{- $secretName := printf "%s-immich-secret" (include "tc.common.names.fullname" .) }}
---
apiVersion: v1
kind: Secret
type: Opaque
metadata:
name: {{ $secretName }}
labels:
{{- include "tc.common.labels" . | nindent 4 }}
data:
{{/* Secret Key */}}
{{- with (lookup "v1" "Secret" .Release.Namespace $secretName) }}
JWT_SECRET: {{ index .data "JWT_SECRET" }}
{{- else }}
JWT_SECRET: {{ randAlphaNum 32 | b64enc }}
{{- end }}
DB_PASSWORD: {{ .Values.postgresql.postgresqlPassword | trimAll "\"" | b64enc }}
REDIS_PASSWORD: {{ .Values.redis.redisPassword | trimAll "\"" | b64enc }}
{{- with .Values.immich.mapbox_key }}
MAPBOX_KEY: {{ . }}
{{- end }}
{{- end }}
@@ -0,0 +1,41 @@
{{/* Define the web container */}}
{{- define "immich.web" -}}
image: {{ .Values.imageWeb.repository }}:{{ .Values.imageWeb.tag }}
imagePullPolicy: {{ .Values.imageWeb.pullPolicy }}
securityContext:
runAsUser: {{ .Values.podSecurityContext.runAsUser }}
runAsGroup: {{ .Values.podSecurityContext.runAsGroup }}
readOnlyRootFilesystem: {{ .Values.securityContext.readOnlyRootFilesystem }}
runAsNonRoot: {{ .Values.securityContext.runAsNonRoot }}
command:
- /bin/sh
- -c
- chmod +x ./entrypoint.sh && ./entrypoint.sh
envFrom:
- configMapRef:
name: '{{ include "tc.common.names.fullname" . }}-common-config'
readinessProbe:
httpGet:
path: /
port: 3000
initialDelaySeconds: {{ .Values.probes.readiness.spec.initialDelaySeconds }}
timeoutSeconds: {{ .Values.probes.readiness.spec.timeoutSeconds }}
periodSeconds: {{ .Values.probes.readiness.spec.periodSeconds }}
failureThreshold: {{ .Values.probes.readiness.spec.failureThreshold }}
livenessProbe:
httpGet:
path: /
port: 3000
initialDelaySeconds: {{ .Values.probes.liveness.spec.initialDelaySeconds }}
timeoutSeconds: {{ .Values.probes.liveness.spec.timeoutSeconds }}
periodSeconds: {{ .Values.probes.liveness.spec.periodSeconds }}
failureThreshold: {{ .Values.probes.liveness.spec.failureThreshold }}
startupProbe:
httpGet:
path: /
port: 3000
initialDelaySeconds: {{ .Values.probes.startup.spec.initialDelaySeconds }}
timeoutSeconds: {{ .Values.probes.startup.spec.timeoutSeconds }}
periodSeconds: {{ .Values.probes.startup.spec.periodSeconds }}
failureThreshold: {{ .Values.probes.startup.spec.failureThreshold }}
{{- end -}}
@@ -0,0 +1,15 @@
{{/* Make sure all variables are set properly */}}
{{- include "tc.common.loader.init" . }}
{{/* Render secret */}}
{{- include "immich.secret" . }}
{{/* Render config */}}
{{- include "immich.config" . }}
{{- $_ := set .Values.additionalContainers "proxy" (include "immich.proxy" . | fromYaml) -}}
{{- $_ := set .Values.additionalContainers "web" (include "immich.web" . | fromYaml) -}}
{{- $_ := set .Values.additionalContainers "ml" (include "immich.ml" . | fromYaml) -}}
{{/* Render the templates */}}
{{ include "tc.common.loader.apply" . }}
+99
View File
@@ -0,0 +1,99 @@
image:
repository: tccr.io/truecharts/immich-server
tag: 1.29.5_44@sha256:8245bc309da22c436eb29a838d2292f504d77e24f4d098d6c0e65df877180ff3
pullPolicy: IfNotPresent
imageML:
repository: tccr.io/truecharts/immich-ml
tag: 1.29.5_44@sha256:2df7b6368beb52ff1ffd946aaacc4df21f278b97ee3c592e2021118b3dcb5fec
pullPolicy: IfNotPresent
imageWeb:
repository: tccr.io/truecharts/immich-web
tag: 1.29.5_44@sha256:c17ec4c2a174bac8fc2c58ebaedc7db70600fa2480695cf0920d54127c8bb32e
pullPolicy: IfNotPresent
imageProxy:
repository: tccr.io/truecharts/immich-proxy
tag: 1.29.5_44@sha256:a4c24a70cc1e1bbbdecc3df371af08528430846709ef22ca16e2a923aa8da509
pullPolicy: IfNotPresent
command:
- /bin/sh
- -c
- chmod +x ./start-server.sh && ./start-server.sh
securityContext:
readOnlyRootFilesystem: false
runAsNonRoot: false
podSecurityContext:
runAsUser: 0
runAsGroup: 0
immich:
public_login_page_message: Immich
disable_reverse_geocoding: false
reverse_geocoding_precision: 3
# simple | verbose
log_level: simple
mapbox_enable: false
mapbox_key: ""
envFrom:
- configMapRef:
name: '{{ include "tc.common.names.fullname" . }}-server-config'
- configMapRef:
name: '{{ include "tc.common.names.fullname" . }}-common-config'
- secretRef:
name: '{{ include "tc.common.names.fullname" . }}-immich-secret'
probes:
liveness:
path: /server-info/ping
type: HTTP
port: 3001
readines:
path: /server-info/ping
type: HTTP
port: 3001
startup:
path: /server-info/ping
type: HTTP
port: 3001
service:
main:
ports:
main:
port: 10323
protocol: HTTP
persistence:
uploads:
enabled: true
mountPath: /usr/src/app/upload
proxy-conf:
enabled: true
noMount: true
type: custom
mountPath: /etc/nginx/
volumeSpec:
configMap:
name: '{{ include "tc.common.names.fullname" . }}-proxy-config'
items:
- key: nginx.conf
path: nginx.conf
postgresql:
enabled: true
existingSecret: dbcreds
postgresqlUsername: immich
postgresqlDatabase: immich
redis:
enabled: true
existingSecret: rediscreds
portal:
enabled: true
+2
View File
@@ -86,6 +86,7 @@ words:
- hyperthread - hyperthread
- iban - iban
- idtool - idtool
- immich
- ingressclasses - ingressclasses
- ingressroutes - ingressroutes
- ingressroutetcps - ingressroutetcps
@@ -127,6 +128,7 @@ words:
- loolwsd - loolwsd
- mailenabled - mailenabled
- mailgun - mailgun
- mapbox
- mariadbcreds - mariadbcreds
- mattwebbio - mattwebbio
- maxmind - maxmind