diff --git a/charts/lemmy/.helmignore b/charts/lemmy/.helmignore new file mode 100644 index 0000000..0e8a0eb --- /dev/null +++ b/charts/lemmy/.helmignore @@ -0,0 +1,23 @@ +# 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 +*.orig +*~ +# Various IDEs +.project +.idea/ +*.tmproj +.vscode/ diff --git a/charts/lemmy/Chart.yaml b/charts/lemmy/Chart.yaml new file mode 100644 index 0000000..c0b04f6 --- /dev/null +++ b/charts/lemmy/Chart.yaml @@ -0,0 +1,19 @@ +--- +apiVersion: v2 +name: lemmy +description: A link aggregator and forum for the fediverse +icon: https://join-lemmy.org/static/assets/images/lemmy.svg +appVersion: 0.17.3 + +type: application +version: 0.1.0 + +maintainers: + - name: Alexander Olofsson + email: ace@haxalot.com + +dependencies: + - name: postgresql + version: ^12.5 + repository: https://charts.bitnami.com/bitnami + condition: postgresql.enabled diff --git a/charts/lemmy/templates/NOTES.txt b/charts/lemmy/templates/NOTES.txt new file mode 100644 index 0000000..09392d5 --- /dev/null +++ b/charts/lemmy/templates/NOTES.txt @@ -0,0 +1,36 @@ +1. Get the application URL by running these commands: +{{- if .Values.ingress.enabled }} + http{{ if $.Values.config.tls }}s{{ end }}://{{ .Values.serverName }}/ +{{- else if .Values.proxy.enabled }} + {{- if contains "NodePort" .Values.proxy.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "lemmy.proxyname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT + {{- else if contains "LoadBalancer" .Values.proxy.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "lemmy.proxyname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "lemmy.proxyname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.proxy.service.port }} + {{- else if contains "ClusterIP" .Values.proxy.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "lemmy.name" . }},app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/component=proxy" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT + {{- end }} +{{- else }} + {{- if contains "NodePort" .Values.ui.service.type }} + export NODE_PORT=$(kubectl get --namespace {{ .Release.Namespace }} -o jsonpath="{.spec.ports[0].nodePort}" services {{ include "lemmy.uiname" . }}) + export NODE_IP=$(kubectl get nodes --namespace {{ .Release.Namespace }} -o jsonpath="{.items[0].status.addresses[0].address}") + echo http://$NODE_IP:$NODE_PORT + {{- else if contains "LoadBalancer" .Values.ui.service.type }} + NOTE: It may take a few minutes for the LoadBalancer IP to be available. + You can watch the status of by running 'kubectl get --namespace {{ .Release.Namespace }} svc -w {{ include "lemmy.uiname" . }}' + export SERVICE_IP=$(kubectl get svc --namespace {{ .Release.Namespace }} {{ include "lemmy.uiname" . }} --template "{{"{{ range (index .status.loadBalancer.ingress 0) }}{{.}}{{ end }}"}}") + echo http://$SERVICE_IP:{{ .Values.ui.service.port }} + {{- else if contains "ClusterIP" .Values.ui.service.type }} + export POD_NAME=$(kubectl get pods --namespace {{ .Release.Namespace }} -l "app.kubernetes.io/name={{ include "lemmy.name" . }},app.kubernetes.io/instance={{ .Release.Name }},app.kubernetes.io/component=frontend" -o jsonpath="{.items[0].metadata.name}") + export CONTAINER_PORT=$(kubectl get pod --namespace {{ .Release.Namespace }} $POD_NAME -o jsonpath="{.spec.containers[0].ports[0].containerPort}") + echo "Visit http://127.0.0.1:8080 to use your application" + kubectl --namespace {{ .Release.Namespace }} port-forward $POD_NAME 8080:$CONTAINER_PORT + {{- end }} +{{- end }} diff --git a/charts/lemmy/templates/_helpers.tpl b/charts/lemmy/templates/_helpers.tpl new file mode 100644 index 0000000..c5d8254 --- /dev/null +++ b/charts/lemmy/templates/_helpers.tpl @@ -0,0 +1,154 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "lemmy.name" -}} +{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +If release name contains chart name it will be used as a full name. +*/}} +{{- define "lemmy.fullname" -}} +{{- if .Values.fullnameOverride }} +{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- $name := default .Chart.Name .Values.nameOverride }} +{{- if contains $name .Release.Name }} +{{- .Release.Name | trunc 63 | trimSuffix "-" }} +{{- else }} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} +{{- end }} +{{- end }} +{{- end }} + +{{- define "lemmy.uiname" -}} +{{- printf "%s-%s" (include "lemmy.fullname" $) "ui" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{- define "lemmy.proxyname" -}} +{{- printf "%s-%s" (include "lemmy.fullname" $) "proxy" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{- define "lemmy.pictrsname" -}} +{{- printf "%s-%s" (include "lemmy.fullname" $) "pictrs" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "lemmy.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "lemmy.labels" -}} +helm.sh/chart: {{ include "lemmy.chart" . }} +{{ include "lemmy.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "lemmy.selectorLabels" -}} +app.kubernetes.io/name: {{ include "lemmy.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + +{{/* +Create the name of the service account to use +*/}} +{{- define "lemmy.serviceAccountName" -}} +{{- if .Values.serviceAccount.create }} +{{- default (include "lemmy.fullname" .) .Values.serviceAccount.name }} +{{- else }} +{{- default "default" .Values.serviceAccount.name }} +{{- end }} +{{- end }} + + +{{/* +Create a default fully qualified app name. +We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). +*/}} +{{- define "lemmy.postgresql.fullname" -}} +{{- $name := .Values.postgresql.nameOverride | default "postgresql" -}} +{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" -}} +{{- end -}} + +{{/* +Set postgres host +*/}} +{{- define "lemmy.postgresql.host" -}} +{{- if .Values.postgresql.enabled -}} +{{- template "lemmy.postgresql.fullname" . -}} +{{- else -}} +{{ required "A valid postgresql.host is required" .Values.postgresql.host }} +{{- end -}} +{{- end -}} + +{{/* +Set postgres secret +*/}} +{{- define "lemmy.postgresql.secret" -}} +{{- if .Values.postgresql.enabled -}} +{{- template "lemmy.postgresql.fullname" . -}} +{{- else -}} +{{- template "lemmy.fullname" . -}} +{{- end -}} +{{- end -}} + +{{/* +Set postgres port +*/}} +{{- define "lemmy.postgresql.port" -}} +{{- if .Values.postgresql.enabled -}} +{{- if .Values.postgresql.service -}} +{{- .Values.postgresql.service.port | default 5432 }} +{{- else -}} +5432 +{{- end -}} +{{- else -}} +5432 +{{- end -}} +{{- end -}} + +{{/* +Set postgresql username +*/}} +{{- define "lemmy.postgresql.username" -}} +{{- if .Values.postgresql.enabled -}} +{{- .Values.postgresql.auth.username | default "postgres" }} +{{- else -}} +{{ required "A valid postgresql.auth.username is required" .Values.postgresql.auth.username }} +{{- end -}} +{{- end -}} + +{{/* +Set postgresql password +*/}} +{{- define "lemmy.postgresql.password" -}} +{{- if .Values.postgresql.enabled -}} +{{- .Values.postgresql.auth.password | default "" }} +{{- else -}} +{{ required "A valid postgresql.auth.password is required" .Values.postgresql.auth.password }} +{{- end -}} +{{- end -}} + +{{/* +Set postgresql database +*/}} +{{- define "lemmy.postgresql.database" -}} +{{- if .Values.postgresql.enabled -}} +{{- .Values.postgresql.auth.database | default "lemmy" }} +{{- else -}} +{{ required "A valid postgresql.auth.database is required" .Values.postgresql.auth.database }} +{{- end -}} +{{- end -}} diff --git a/charts/lemmy/templates/configmap-proxy.yaml b/charts/lemmy/templates/configmap-proxy.yaml new file mode 100644 index 0000000..a38d4dd --- /dev/null +++ b/charts/lemmy/templates/configmap-proxy.yaml @@ -0,0 +1,76 @@ +{{- if .Values.proxy.enabled -}} +--- +apiVersion: v1 +kind: ConfigMap +metadata: + name: {{ include "lemmy.proxyname" . }} + labels: + {{- include "lemmy.labels" . | nindent 4 }} + app.kubernetes.io/component: proxy +data: + nginx.conf: | + worker_processes 1; + events { + worker_connections 1024; + } + http { + upstream lemmy { + # this needs to map to the lemmy (server) docker service hostname + server "{{ include "lemmy.fullname" . }}:{{ .Values.backend.service.port }}"; + } + upstream lemmy-ui { + # this needs to map to the lemmy-ui docker service hostname + server "{{ include "lemmy.uiname" . }}:{{ .Values.frontend.service.port }}"; + } + + server { + listen 8536; + + server_name {{ .Values.serverName }}; + server_tokens off; + + gzip on; + gzip_types text/css application/javascript image/svg+xml; + gzip_vary on; + + client_max_body_size 20M; + + add_header X-Frame-Options SAMEORIGIN; + add_header X-Content-Type-Options nosniff; + add_header X-XSS-Protection "1; mode=block"; + + location / { + set $proxpass "http://lemmy-ui"; + + if ($http_accept = "application/activity+json") { + set $proxpass "http://lemmy"; + } + if ($http_accept = "application/ld+json; profile=\"https://www.w3.org/ns/activitystreams\"") { + set $proxpass "http://lemmy"; + } + if ($request_method = POST) { + set $proxpass "http://lemmy"; + } + proxy_pass $proxpass; + + rewrite ^(.+)/+$ $1 permanent; + + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + + location ~ ^/(api|pictrs|feeds|nodeinfo|.well-known) { + proxy_pass "http://lemmy"; + + proxy_http_version 1.1; + proxy_set_header Upgrade $http_upgrade; + proxy_set_header Connection "upgrade"; + + proxy_set_header X-Real-IP $remote_addr; + proxy_set_header Host $host; + proxy_set_header X-Forwarded-For $proxy_add_x_forwarded_for; + } + } + } +{{- end }} diff --git a/charts/lemmy/templates/deployment-backend.yaml b/charts/lemmy/templates/deployment-backend.yaml new file mode 100644 index 0000000..4903d5d --- /dev/null +++ b/charts/lemmy/templates/deployment-backend.yaml @@ -0,0 +1,83 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "lemmy.fullname" . }} + labels: + {{- include "lemmy.labels" . | nindent 4 }} + app.kubernetes.io/component: backend +spec: + replicas: {{ .Values.backend.replicaCount }} + selector: + matchLabels: + {{- include "lemmy.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: backend + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/secret-configuration.yaml") . | sha256sum }} + {{- with .Values.backend.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "lemmy.selectorLabels" . | nindent 8 }} + app.kubernetes.io/component: backend + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "lemmy.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.backend.podSecurityContext | nindent 8 }} + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.backend.securityContext | nindent 12 }} + image: "{{ .Values.backend.image.repository | default .Values.image.repository }}:{{ .Values.backend.image.tag | default .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.backend.image.pullPolicy | default .Values.image.pullPolicy }} + {{- with .Values.backend.env }} + env: + {{- range $key, $value := . }} + - name: {{ $key }} + value: {{ $value | toString | quote }} + {{- end }} + {{- end }} + {{- with .Values.backend.envFrom }} + envFrom: + {{- toYaml . | nindent 12 }} + {{- end }} + ports: + - name: http + containerPort: 8536 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + readinessProbe: + httpGet: + path: / + port: http + resources: + {{- toYaml .Values.backend.resources | nindent 12 }} + volumeMounts: + - name: config + mountPath: /config/config.hjson + subPath: config.hjson + {{- with .Values.backend.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.backend.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.backend.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: config + secret: + secretName: {{ include "lemmy.fullname" . }} diff --git a/charts/lemmy/templates/deployment-frontend.yaml b/charts/lemmy/templates/deployment-frontend.yaml new file mode 100644 index 0000000..6d2b1f8 --- /dev/null +++ b/charts/lemmy/templates/deployment-frontend.yaml @@ -0,0 +1,80 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "lemmy.uiname" . }} + labels: + {{- include "lemmy.labels" . | nindent 4 }} + app.kubernetes.io/component: frontend +spec: + replicas: {{ .Values.frontend.replicaCount }} + selector: + matchLabels: + {{- include "lemmy.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: frontend + template: + metadata: + {{- with .Values.frontend.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "lemmy.selectorLabels" . | nindent 8 }} + app.kubernetes.io/component: frontend + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "lemmy.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.frontend.podSecurityContext | nindent 8 }} + containers: + - name: frontend + securityContext: + {{- toYaml .Values.frontend.securityContext | nindent 12 }} + image: "{{ .Values.frontend.image.repository }}:{{ .Values.frontend.image.tag | default .Values.image.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.frontend.image.pullPolicy | default .Values.image.pullPolicy }} + env: + - name: LEMMY_UI_LEMMY_INTERNAL_HOST + value: "{{ include "lemmy.fullname" . }}:{{ .Values.backend.service.port }}" + - name: LEMMY_UI_LEMMY_EXTERNAL_HOST + value: {{ .Values.serverName | quote }} + - name: LEMMY_UI_HTTPS + value: {{ printf "%t" .Values.config.tls | quote }} + {{- with .Values.frontend.env }} + {{- range $key, $value := . }} + - name: {{ $key }} + value: {{ $value | toString | quote }} + {{- end }} + {{- end }} + {{- with .Values.frontend.envFrom }} + envFrom: + {{- toYaml . | nindent 12 }} + {{- end }} + ports: + - name: http + containerPort: 1234 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + readinessProbe: + httpGet: + path: / + port: http + resources: + {{- toYaml .Values.frontend.resources | nindent 12 }} + {{- with .Values.frontend.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.frontend.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.frontend.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/lemmy/templates/deployment-pictrs.yaml b/charts/lemmy/templates/deployment-pictrs.yaml new file mode 100644 index 0000000..8b94f9a --- /dev/null +++ b/charts/lemmy/templates/deployment-pictrs.yaml @@ -0,0 +1,97 @@ +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "lemmy.pictrsname" . }} + labels: + {{- include "lemmy.labels" . | nindent 4 }} + app.kubernetes.io/component: pictrs +spec: + replicas: {{ .Values.pictrs.replicaCount }} + selector: + matchLabels: + {{- include "lemmy.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: pictrs + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/secret-pictrs.yaml") . | sha256sum }} + {{- with .Values.pictrs.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "lemmy.selectorLabels" . | nindent 8 }} + app.kubernetes.io/component: pictrs + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "lemmy.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.pictrs.podSecurityContext | nindent 8 }} + containers: + - name: pictrs + securityContext: + {{- toYaml .Values.pictrs.securityContext | nindent 12 }} + image: "{{ .Values.pictrs.image.repository }}:{{ .Values.pictrs.image.tag }}" + imagePullPolicy: {{ .Values.pictrs.image.pullPolicy }} + env: + - name: PICTRS__API_KEY + valueFrom: + secretKeyRef: + name: {{ include "lemmy.fullname" . }} + key: pictrs_apikey + {{- with .Values.pictrs.env }} + {{- range $key, $value := . }} + - name: {{ $key }} + value: {{ $value | toString | quote }} + {{- end }} + {{- end }} + envFrom: + - secretRef: + name: {{ include "lemmy.pictrsname" . }} + {{- with .Values.pictrs.envFrom }} + {{- toYaml . | nindent 12 }} + {{- end }} + ports: + - name: http + containerPort: 8080 + protocol: TCP + livenessProbe: + httpGet: + path: /healthz + port: http + readinessProbe: + httpGet: + path: /healthz + port: http + volumeMounts: + - name: data + mountPath: /mnt/database + subPath: database + - name: data + mountPath: /mnt/media + subPath: media + resources: + {{- toYaml .Values.pictrs.resources | nindent 12 }} + volumes: + - name: data + {{- if .Values.pictrs.persistence.enabled }} + persistentVolumeClaim: + claimName: {{ .Values.pictrs.persistence.existingClaim | default (include "lemmy.pictrsname" $) }} + {{- else }} + emptyDir: {} + {{- end }} + {{- with .Values.pictrs.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.pictrs.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.pictrs.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/charts/lemmy/templates/deployment-proxy.yaml b/charts/lemmy/templates/deployment-proxy.yaml new file mode 100644 index 0000000..133b37e --- /dev/null +++ b/charts/lemmy/templates/deployment-proxy.yaml @@ -0,0 +1,74 @@ +{{- if .Values.proxy.enabled -}} +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "lemmy.proxyname" . }} + labels: + {{- include "lemmy.labels" . | nindent 4 }} + app.kubernetes.io/component: proxy +spec: + replicas: {{ .Values.proxy.replicaCount }} + selector: + matchLabels: + {{- include "lemmy.selectorLabels" . | nindent 6 }} + app.kubernetes.io/component: proxy + template: + metadata: + annotations: + checksum/config: {{ include (print $.Template.BasePath "/configmap-proxy.yaml") . | sha256sum }} + {{- with .Values.proxy.podAnnotations }} + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + {{- include "lemmy.selectorLabels" . | nindent 8 }} + app.kubernetes.io/component: proxy + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + serviceAccountName: {{ include "lemmy.serviceAccountName" . }} + securityContext: + {{- toYaml .Values.proxy.podSecurityContext | nindent 8 }} + containers: + - name: proxy + securityContext: + {{- toYaml .Values.proxy.securityContext | nindent 12 }} + image: "{{ .Values.proxy.image.repository }}:{{ .Values.proxy.image.tag }}" + imagePullPolicy: {{ .Values.proxy.image.pullPolicy }} + ports: + - name: http + containerPort: 8536 + protocol: TCP + livenessProbe: + httpGet: + path: / + port: http + readinessProbe: + httpGet: + path: / + port: http + resources: + {{- toYaml .Values.proxy.resources | nindent 12 }} + volumeMounts: + - name: config + mountPath: /etc/nginx/nginx.conf + subPath: nginx.conf + {{- with .Values.proxy.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.proxy.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.proxy.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} + volumes: + - name: config + configMap: + name: {{ include "lemmy.proxyname" . }} +{{- end }} diff --git a/charts/lemmy/templates/ingress.yaml b/charts/lemmy/templates/ingress.yaml new file mode 100644 index 0000000..3673edd --- /dev/null +++ b/charts/lemmy/templates/ingress.yaml @@ -0,0 +1,61 @@ +{{- if and .Values.ingress.enabled .Values.proxy.enabled -}} +{{- $fullName := include "lemmy.fullname" . -}} +{{- $proxyName := include "lemmy.proxyname" . -}} +{{- $proxyPort := .Values.proxy.service.port -}} +{{- if and .Values.ingress.className (not (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion)) }} + {{- if not (hasKey .Values.ingress.annotations "kubernetes.io/ingress.class") }} + {{- $_ := set .Values.ingress.annotations "kubernetes.io/ingress.class" .Values.ingress.className}} + {{- end }} +{{- end }} +{{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1 +{{- else if semverCompare ">=1.14-0" .Capabilities.KubeVersion.GitVersion -}} +apiVersion: networking.k8s.io/v1beta1 +{{- else -}} +apiVersion: extensions/v1beta1 +{{- end }} +kind: Ingress +metadata: + name: {{ $fullName }} + labels: + {{- include "lemmy.labels" . | nindent 4 }} + {{- with .Values.ingress.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +spec: + {{- if and .Values.ingress.className (semverCompare ">=1.18-0" .Capabilities.KubeVersion.GitVersion) }} + ingressClassName: {{ .Values.ingress.className }} + {{- end }} + {{- if .Values.ingress.tls }} + tls: + {{- range .Values.ingress.tls }} + - hosts: + {{- range .hosts }} + - {{ . | quote }} + {{- end }} + secretName: {{ .secretName }} + {{- end }} + {{- end }} + rules: + {{- $hosts := concat (list .Values.serverName) (.Values.ingress.hosts | default list) }} + {{- range $hosts }} + - host: {{ . | quote }} + http: + paths: + - path: / + {{- if semverCompare ">=1.18-0" $.Capabilities.KubeVersion.GitVersion }} + pathType: Prefix + {{- end }} + backend: + {{- if semverCompare ">=1.19-0" $.Capabilities.KubeVersion.GitVersion }} + service: + name: {{ $proxyName }} + port: + number: {{ $proxyPort }} + {{- else }} + serviceName: {{ $proxyName }} + servicePort: {{ $proxyPort }} + {{- end }} + {{- end }} +{{- end }} diff --git a/charts/lemmy/templates/pvc.yaml b/charts/lemmy/templates/pvc.yaml new file mode 100644 index 0000000..9f91d9c --- /dev/null +++ b/charts/lemmy/templates/pvc.yaml @@ -0,0 +1,23 @@ +{{- if and .Values.pictrs.persistence.enabled (not .Values.pictrs.persistence.existingClaim) -}} +kind: PersistentVolumeClaim +apiVersion: v1 +metadata: + name: {{ template "lemmy.pictrsname" . }} + labels: + {{- include "lemmy.labels" . | nindent 4 }} + app.kubernetes.io/component: pictrs +spec: + accessModes: + - {{ .Values.pictrs.persistence.accessMode | quote }} + resources: + requests: + storage: {{ .Values.pictrs.persistence.size | quote }} +{{- if .Values.pictrs.persistence.storageClass }} +{{- if (eq "-" .Values.pictrs.persistence.storageClass) }} + storageClassName: "" +{{- else }} + storageClassName: "{{ .Values.pictrs.persistence.storageClass }}" +{{- end }} +{{- end }} +{{- end -}} + diff --git a/charts/lemmy/templates/secret-configuration.yaml b/charts/lemmy/templates/secret-configuration.yaml new file mode 100644 index 0000000..93f7a9f --- /dev/null +++ b/charts/lemmy/templates/secret-configuration.yaml @@ -0,0 +1,56 @@ +--- +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "lemmy.fullname" . }} + labels: + {{- include "lemmy.labels" . | nindent 4 }} +{{- $adminPassword := randAlphaNum 32 }} +{{- $pictrsApikey := randAlphaNum 64 }} + +{{- $existing := (lookup "v1" "Secret" .Release.Namespace (include "lemmy.fullname" .)) -}} +{{- if and $existing $existing.data.admin_password }} + {{- $adminPassword := b64dec $existing.data.admin_password }} +{{- end }} +{{- if and $existing $existing.data.pictrs_apikey }} + {{- $pictrsApikey := b64dec $existing.data.pictrs_apikey }} +{{- end }} + +{{- $config := dict + "database" + (dict + "user" (include "lemmy.postgresql.username" .) + "password" (include "lemmy.postgresql.password" .) + "host" (include "lemmy.postgresql.host" .) + "port" (include "lemmy.postgresql.port" . | int) + "database" (include "lemmy.postgresql.database" .) + ) + "pictrs" + (dict + "url" (printf "http://%s:%d" (include "lemmy.pictrsname" .) (int .Values.pictrs.service.port)) + "api_key" (.Values.pictrs.apikey | default $pictrsApikey) + ) + "email" + (dict + "smtp_server" .Values.smtp.server + "smtp_login" .Values.smtp.username + "smtp_password" .Values.smtp.password + "smtp_from_address" .Values.smtp.from + "tls_type" .Values.smtp.tls + ) + "setup" + (dict + "admin_username" (.Values.admin.username | default "lemmy") + "admin_password" (.Values.admin.password | default $adminPassword) + "admin_email" .Values.admin.email + "site_name" .Values.config.siteName + ) + "hostname" .Values.serverName + "bind" "0.0.0.0" + "port" 8536 + "tls_enabled" (.Values.config.tls | default true) +}} +data: + admin_password: {{ $adminPassword | b64enc }} + pictrs_apikey: {{ $pictrsApikey | b64enc }} + config.hjson: {{ $config | toPrettyJson | b64enc }} diff --git a/charts/lemmy/templates/secret-pictrs.yaml b/charts/lemmy/templates/secret-pictrs.yaml new file mode 100644 index 0000000..4e55bbe --- /dev/null +++ b/charts/lemmy/templates/secret-pictrs.yaml @@ -0,0 +1,27 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "lemmy.pictrsname" . }} + labels: + {{- include "lemmy.labels" . | nindent 4 }} + app.kubernetes.io/component: pictrs +data: + PICTRS__REPO__PATH: {{ "/mnt/database" | b64enc }} + PICTRS__STORE__TYPE: {{ .Values.pictrs.storage.method | b64enc }} + +{{- if (eq .Values.pictrs.storage.method "object_storage") }} + {{- $s3 := .Values.pictrs.storage.objectStorage }} + {{- if $s3.endpoint }} + PICTRS__STORE__ENDPOINT: {{ $s3.endpoint | b64enc }} + {{- end }} + PICTRS__STORE__USE_PATH_STYLE: {{ $s3.usePathStyle | default false | toString | b64enc }} + PICTRS__STORE__BUCKET_NAME: {{ required "S3 bucket must be specified" $s3.bucketName | b64enc }} + PICTRS__STORE__REGION: {{ required "S3 region must be specified" $s3.region | b64enc }} + PICTRS__STORE__ACCESS_KEY: {{ required "S3 access key must be specified" $s3.accessKey | b64enc }} + PICTRS__STORE__SECRET_KEY: {{ required "S3 secret key must be specified" $s3.secretKey | b64enc }} + {{- if $s3.sessionToken }} + PICTRS__STORE__SESSION_TOKEN: {{ $s3.sessionToken | b64enc }} + {{- end }} +{{- else }} + PICTRS__STORE__PATH: {{ "/mnt/media" | b64enc }} +{{- end }} diff --git a/charts/lemmy/templates/service-backend.yaml b/charts/lemmy/templates/service-backend.yaml new file mode 100644 index 0000000..dc14014 --- /dev/null +++ b/charts/lemmy/templates/service-backend.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "lemmy.fullname" . }} + labels: + {{- include "lemmy.labels" . | nindent 4 }} + app.kubernetes.io/component: backend +spec: + type: {{ .Values.backend.service.type }} + ports: + - port: {{ .Values.backend.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "lemmy.selectorLabels" . | nindent 4 }} + app.kubernetes.io/component: backend diff --git a/charts/lemmy/templates/service-frontend.yaml b/charts/lemmy/templates/service-frontend.yaml new file mode 100644 index 0000000..e0b3b17 --- /dev/null +++ b/charts/lemmy/templates/service-frontend.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "lemmy.uiname" . }} + labels: + {{- include "lemmy.labels" . | nindent 4 }} + app.kubernetes.io/component: frontend +spec: + type: {{ .Values.backend.service.type }} + ports: + - port: {{ .Values.backend.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "lemmy.selectorLabels" . | nindent 4 }} + app.kubernetes.io/component: frontend diff --git a/charts/lemmy/templates/service-pictrs.yaml b/charts/lemmy/templates/service-pictrs.yaml new file mode 100644 index 0000000..15d8fd1 --- /dev/null +++ b/charts/lemmy/templates/service-pictrs.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "lemmy.pictrsname" . }} + labels: + {{- include "lemmy.labels" . | nindent 4 }} + app.kubernetes.io/component: pictrs +spec: + type: {{ .Values.backend.service.type }} + ports: + - port: {{ .Values.backend.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "lemmy.selectorLabels" . | nindent 4 }} + app.kubernetes.io/component: pictrs diff --git a/charts/lemmy/templates/service-proxy.yaml b/charts/lemmy/templates/service-proxy.yaml new file mode 100644 index 0000000..d12b29d --- /dev/null +++ b/charts/lemmy/templates/service-proxy.yaml @@ -0,0 +1,19 @@ +{{- if .Values.proxy.enabled -}} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "lemmy.proxyname" . }} + labels: + {{- include "lemmy.labels" . | nindent 4 }} + app.kubernetes.io/component: proxy +spec: + type: {{ .Values.backend.service.type }} + ports: + - port: {{ .Values.backend.service.port }} + targetPort: http + protocol: TCP + name: http + selector: + {{- include "lemmy.selectorLabels" . | nindent 4 }} + app.kubernetes.io/component: proxy +{{- end }} diff --git a/charts/lemmy/templates/serviceaccount.yaml b/charts/lemmy/templates/serviceaccount.yaml new file mode 100644 index 0000000..724717b --- /dev/null +++ b/charts/lemmy/templates/serviceaccount.yaml @@ -0,0 +1,12 @@ +{{- if .Values.serviceAccount.create -}} +apiVersion: v1 +kind: ServiceAccount +metadata: + name: {{ include "lemmy.serviceAccountName" . }} + labels: + {{- include "lemmy.labels" . | nindent 4 }} + {{- with .Values.serviceAccount.annotations }} + annotations: + {{- toYaml . | nindent 4 }} + {{- end }} +{{- end }} diff --git a/charts/lemmy/templates/tests/test-connection.yaml b/charts/lemmy/templates/tests/test-connection.yaml new file mode 100644 index 0000000..cf21af1 --- /dev/null +++ b/charts/lemmy/templates/tests/test-connection.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Pod +metadata: + name: "{{ include "lemmy.fullname" . }}-test-connection" + labels: + {{- include "lemmy.labels" . | nindent 4 }} + annotations: + "helm.sh/hook": test +spec: + containers: + - name: wget + image: busybox + command: ['wget'] +{{- if .Values.proxy.enabled }} + args: ['{{ include "lemmy.proxyname" . }}:{{ .Values.proxy.service.port }}'] +{{- else }} + args: ['{{ include "lemmy.fullname" . }}:{{ .Values.backend.service.port }}'] +{{- end }} + restartPolicy: Never diff --git a/charts/lemmy/values.yaml b/charts/lemmy/values.yaml new file mode 100644 index 0000000..3f2d4d6 --- /dev/null +++ b/charts/lemmy/values.yaml @@ -0,0 +1,278 @@ +--- +image: + repository: dessalines/lemmy + pullPolicy: IfNotPresent + # Overrides the image tag whose default is the chart appVersion. + #tag: latest + +## The domain of the Lemmy instance +serverName: "localhost" + +smtp: + server: smtp.example.com + # username: lemmy + # password: + from: lemmy@example.com + tls: none + +admin: + username: lemmy + ## Will be generated on first install if left empty + # password: + email: lemmy@example.com + +config: + siteName: Lemmy on Kubernetes + ## Requires valid certificates, but is also required for federation support + tls: true + +imagePullSecrets: [] +nameOverride: "" +fullnameOverride: "" + +serviceAccount: + # Specifies whether a service account should be created + create: false + # Annotations to add to the service account + annotations: {} + # The name of the service account to use. + # If not set and create is true, a name is generated using the fullname template + name: "" + +backend: + image: + _keep: true + # repository: dessalines/lemmy + # pullPolicy: IfNotPresent + # tag: + + env: + # RUST_BACKTRACE: 1 + + envFrom: + # - secretRef: + # name: my-extra-secrets + + replicaCount: 1 + + podAnnotations: {} + + podSecurityContext: {} + # fsGroup: 2000 + + securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + + service: + type: ClusterIP + port: 80 + + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + + nodeSelector: {} + + tolerations: [] + + affinity: {} + +frontend: + image: + repository: dessalines/lemmy-ui + #pullPolicy: IfNotPresent + #tag: + + replicaCount: 1 + + env: + # LEMMY_UI_DEBUG: true + + envFrom: + # - secretRef: + # name: my-extra-secrets + + podAnnotations: {} + + podSecurityContext: {} + # fsGroup: 2000 + + securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + + service: + type: ClusterIP + port: 80 + + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + + nodeSelector: {} + + tolerations: [] + + affinity: {} + +pictrs: + replicaCount: 1 + + ## Generated on first install if left empty + # apiKey: + + storage: + ## Storage method for media, can be filesystem or object_storage + method: filesystem + + objectStorage: + ## For self-hosted S3 + # endpoint: https://minio.example.com + usePathStyle: false + + bucketName: lemmy-pictrs + # region: + # accessKey: + # secretKey: + # sessionToken: + + # existingSecret: pictrs-secret + # existingSecretAccessKey: access-key + # existingSecretSecretKey: secret-key + + env: + PICTRS__MEDIA__VIDEO_CODEC: vp9 + PICTRS__MEDIA__GIF__MAX_WIDTH: 256 + PICTRS__MEDIA__GIF__MAX_HEIGHT: 256 + PICTRS__MEDIA__GIF__MAX_AREA: 65536 + PICTRS__MEDIA__GIF__MAX_FRAME_COUNT: 400 + + envFrom: + # - secretRef: + # name: my-extra-secrets + + image: + repository: asonix/pictrs + pullPolicy: IfNotPresent + tag: 0.4.0-beta.19 + + ## Used by both the sled database and also media itself if using the filesystem storage method + persistence: + enabled: true + accessMode: ReadWriteOnce + size: 16Gi + # existingClaim: + # storageClass: + + podAnnotations: {} + + podSecurityContext: {} + # fsGroup: 2000 + + securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + + service: + type: ClusterIP + port: 80 + + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + + nodeSelector: {} + + tolerations: [] + + affinity: {} + +proxy: + enabled: true + replicaCount: 1 + + image: + repository: nginx + pullPolicy: Always + tag: 1-alpine + + podAnnotations: {} + + podSecurityContext: {} + # fsGroup: 2000 + + securityContext: {} + # capabilities: + # drop: + # - ALL + # readOnlyRootFilesystem: true + # runAsNonRoot: true + # runAsUser: 1000 + + service: + type: ClusterIP + port: 80 + + resources: {} + # limits: + # cpu: 100m + # memory: 128Mi + # requests: + # cpu: 100m + # memory: 128Mi + + nodeSelector: {} + + tolerations: [] + + affinity: {} + +postgresql: + enabled: true + # host: + + auth: + username: lemmy + database: lemmy + # password: + + service: + port: 5432 + +ingress: + enabled: true + className: "" + annotations: {} + # kubernetes.io/ingress.class: nginx + # kubernetes.io/tls-acme: "true" + hosts: + # - chart-example.local + tls: [] + # - secretName: chart-example-tls + # hosts: + # - chart-example.local