Add Lemmy.

This commit is contained in:
2026-01-04 19:36:23 +00:00
parent 0ba33a315d
commit f17fea6910
13 changed files with 500 additions and 0 deletions

36
lemmy/configmap.yaml Normal file
View File

@@ -0,0 +1,36 @@
apiVersion: v1
kind: ConfigMap
metadata:
name: lemmy-config
namespace: {{ .namespace }}
data:
lemmy.hjson: |
{
hostname: "{{ .domain }}"
bind: "0.0.0.0"
port: {{ .backendPort }}
tls_enabled: false
database: {
uri: "postgresql://{{ .dbUser }}:DBPASSWORD@{{ .dbHost }}:{{ .dbPort }}/{{ .dbName }}"
}
pictrs: {
url: "http://lemmy-pictrs:{{ .pictrsPort }}/"
api_key: "PICTRS_API_KEY"
}
email: {
smtp_server: "{{ .smtp.host }}:{{ .smtp.port }}"
smtp_login: "{{ .smtp.user }}"
smtp_password: "SMTP_PASSWORD"
smtp_from_address: "{{ .smtp.from }}"
tls_type: "{{ if eq .smtp.tls "true" }}tls{{ else }}none{{ end }}"
}
setup: {
admin_username: "admin"
admin_password: "ADMIN_PASSWORD"
site_name: "Lemmy"
}
}

76
lemmy/db-init-job.yaml Normal file
View File

@@ -0,0 +1,76 @@
apiVersion: batch/v1
kind: Job
metadata:
name: lemmy-db-init
namespace: {{ .namespace }}
spec:
template:
metadata:
labels:
component: db-init
spec:
restartPolicy: OnFailure
securityContext:
runAsNonRoot: true
runAsUser: 999
runAsGroup: 999
seccompProfile:
type: RuntimeDefault
containers:
- name: db-init
image: postgres:16-alpine
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
readOnlyRootFilesystem: false
env:
- name: PGHOST
value: "{{ .dbHost }}"
- name: PGPORT
value: "{{ .dbPort }}"
- name: PGUSER
value: postgres
- name: PGPASSWORD
valueFrom:
secretKeyRef:
name: lemmy-secrets
key: postgres.password
- name: DB_NAME
value: "{{ .dbName }}"
- name: DB_USER
value: "{{ .dbUser }}"
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: lemmy-secrets
key: dbPassword
command:
- sh
- -c
- |
set -e
echo "Waiting for PostgreSQL to be ready..."
until pg_isready -h $PGHOST -p $PGPORT -U $PGUSER; do
echo "Waiting for database connection..."
sleep 2
done
echo "Creating database and user..."
psql -v ON_ERROR_STOP=1 <<-EOSQL
SELECT 'CREATE DATABASE ${DB_NAME}' WHERE NOT EXISTS (SELECT FROM pg_database WHERE datname = '${DB_NAME}')\gexec
DO \$\$
BEGIN
IF NOT EXISTS (SELECT FROM pg_user WHERE usename = '${DB_USER}') THEN
CREATE USER ${DB_USER} WITH PASSWORD '${DB_PASSWORD}';
ELSE
ALTER USER ${DB_USER} WITH PASSWORD '${DB_PASSWORD}';
END IF;
END
\$\$;
GRANT ALL PRIVILEGES ON DATABASE ${DB_NAME} TO ${DB_USER};
\c ${DB_NAME}
GRANT ALL ON SCHEMA public TO ${DB_USER};
EOSQL
echo "Database initialization completed successfully"

View File

@@ -0,0 +1,102 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: lemmy-backend
namespace: {{ .namespace }}
spec:
replicas: {{ .backendReplicas }}
selector:
matchLabels:
component: backend
template:
metadata:
labels:
component: backend
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
fsGroup: 1000
seccompProfile:
type: RuntimeDefault
initContainers:
- name: config-prep
image: busybox:stable
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
readOnlyRootFilesystem: true
command:
- sh
- -c
- |
cp /config-template/lemmy.hjson /config/lemmy.hjson
sed -i "s|DBPASSWORD|${DB_PASSWORD}|g" /config/lemmy.hjson
sed -i "s|PICTRS_API_KEY|${PICTRS_API_KEY}|g" /config/lemmy.hjson
sed -i "s|SMTP_PASSWORD|${SMTP_PASSWORD}|g" /config/lemmy.hjson
sed -i "s|ADMIN_PASSWORD|${ADMIN_PASSWORD}|g" /config/lemmy.hjson
env:
- name: DB_PASSWORD
valueFrom:
secretKeyRef:
name: lemmy-secrets
key: dbPassword
- name: PICTRS_API_KEY
valueFrom:
secretKeyRef:
name: lemmy-secrets
key: jwtSecret
- name: SMTP_PASSWORD
valueFrom:
secretKeyRef:
name: lemmy-secrets
key: smtpPassword
- name: ADMIN_PASSWORD
valueFrom:
secretKeyRef:
name: lemmy-secrets
key: adminPassword
volumeMounts:
- name: config-template
mountPath: /config-template
- name: config
mountPath: /config
containers:
- name: backend
image: {{ .backendImage }}
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
readOnlyRootFilesystem: false
env:
- name: LEMMY_CONFIG_LOCATION
value: /config/lemmy.hjson
- name: TZ
value: "{{ .timezone }}"
ports:
- containerPort: {{ .backendPort }}
name: http
volumeMounts:
- name: config
mountPath: /config
livenessProbe:
httpGet:
path: /api/v3/site
port: {{ .backendPort }}
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /api/v3/site
port: {{ .backendPort }}
initialDelaySeconds: 10
periodSeconds: 5
volumes:
- name: config-template
configMap:
name: lemmy-config
- name: config
emptyDir: {}

View File

@@ -0,0 +1,77 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: lemmy-pictrs
namespace: {{ .namespace }}
spec:
replicas: {{ .pictrsReplicas }}
selector:
matchLabels:
component: pictrs
template:
metadata:
labels:
component: pictrs
spec:
securityContext:
runAsNonRoot: true
runAsUser: 991
runAsGroup: 991
fsGroup: 991
seccompProfile:
type: RuntimeDefault
containers:
- name: pictrs
image: {{ .pictrsImage }}
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
readOnlyRootFilesystem: false
env:
- name: PICTRS__SERVER__BIND
value: "0.0.0.0:{{ .pictrsPort }}"
- name: PICTRS__MEDIA__VIDEO_CODEC
value: vp9
- name: PICTRS__MEDIA__GIF__MAX_WIDTH
value: "256"
- name: PICTRS__MEDIA__GIF__MAX_HEIGHT
value: "256"
- name: PICTRS__MEDIA__GIF__MAX_AREA
value: "65536"
- name: PICTRS__MEDIA__GIF__MAX_FRAME_COUNT
value: "400"
- name: RUST_LOG
value: debug
- name: RUST_BACKTRACE
value: full
- name: PICTRS__REPO__TYPE
value: sled
- name: PICTRS__REPO__PATH
value: /mnt/sled-repo
- name: PICTRS__STORE__TYPE
value: filesystem
- name: PICTRS__STORE__PATH
value: /mnt/files
ports:
- containerPort: {{ .pictrsPort }}
name: http
volumeMounts:
- name: storage
mountPath: /mnt
livenessProbe:
httpGet:
path: /healthz
port: {{ .pictrsPort }}
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /healthz
port: {{ .pictrsPort }}
initialDelaySeconds: 10
periodSeconds: 5
volumes:
- name: storage
persistentVolumeClaim:
claimName: lemmy-pictrs-storage

51
lemmy/deployment-ui.yaml Normal file
View File

@@ -0,0 +1,51 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: lemmy-ui
namespace: {{ .namespace }}
spec:
replicas: {{ .uiReplicas }}
selector:
matchLabels:
component: ui
template:
metadata:
labels:
component: ui
spec:
securityContext:
runAsNonRoot: true
runAsUser: 1000
runAsGroup: 1000
seccompProfile:
type: RuntimeDefault
containers:
- name: ui
image: {{ .uiImage }}
securityContext:
allowPrivilegeEscalation: false
capabilities:
drop: [ALL]
readOnlyRootFilesystem: false
env:
- name: LEMMY_UI_LEMMY_INTERNAL_HOST
value: "lemmy-backend:{{ .backendPort }}"
- name: LEMMY_UI_LEMMY_EXTERNAL_HOST
value: "{{ .domain }}"
- name: LEMMY_UI_HTTPS
value: "true"
ports:
- containerPort: {{ .uiPort }}
name: http
livenessProbe:
httpGet:
path: /
port: {{ .uiPort }}
initialDelaySeconds: 30
periodSeconds: 10
readinessProbe:
httpGet:
path: /
port: {{ .uiPort }}
initialDelaySeconds: 10
periodSeconds: 5

42
lemmy/ingress.yaml Normal file
View File

@@ -0,0 +1,42 @@
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: lemmy-ingress
namespace: {{ .namespace }}
annotations:
cert-manager.io/cluster-issuer: letsencrypt-prod
traefik.ingress.kubernetes.io/router.entrypoints: websecure
traefik.ingress.kubernetes.io/router.tls: "true"
external-dns.alpha.kubernetes.io/target: {{ .externalDnsDomain }}
external-dns.alpha.kubernetes.io/cloudflare-proxied: "false"
spec:
ingressClassName: traefik
tls:
- hosts:
- {{ .domain }}
secretName: {{ .tlsSecretName }}
rules:
- host: {{ .domain }}
http:
paths:
- path: /api
pathType: Prefix
backend:
service:
name: lemmy-backend
port:
number: {{ .backendPort }}
- path: /pictrs
pathType: Prefix
backend:
service:
name: lemmy-pictrs
port:
number: {{ .pictrsPort }}
- path: /
pathType: Prefix
backend:
service:
name: lemmy-ui
port:
number: {{ .uiPort }}

21
lemmy/kustomization.yaml Normal file
View File

@@ -0,0 +1,21 @@
apiVersion: kustomize.config.k8s.io/v1beta1
kind: Kustomization
namespace: lemmy
labels:
- includeSelectors: true
pairs:
app: lemmy
managedBy: kustomize
partOf: wild-cloud
resources:
- namespace.yaml
- configmap.yaml
- pvc-pictrs.yaml
- db-init-job.yaml
- deployment-pictrs.yaml
- service-pictrs.yaml
- deployment-backend.yaml
- service-backend.yaml
- deployment-ui.yaml
- service-ui.yaml
- ingress.yaml

41
lemmy/manifest.yaml Normal file
View File

@@ -0,0 +1,41 @@
name: lemmy
is: lemmy
description: Lemmy is a selfhosted social link aggregation and discussion platform. It is an open source alternative to Reddit, designed for the fediverse.
version: 0.19.15
icon: https://cdn.jsdelivr.net/gh/homarr-labs/dashboard-icons/svg/lemmy.svg
requires:
- name: postgres
defaultConfig:
namespace: lemmy
backendImage: dessalines/lemmy:0.19.15
uiImage: dessalines/lemmy-ui:0.19.15
pictrsImage: asonix/pictrs:0.5.5
backendPort: 8536
uiPort: 1234
pictrsPort: 8080
backendReplicas: 1
uiReplicas: 1
pictrsReplicas: 1
storage: 10Gi
pictrsStorage: 50Gi
timezone: UTC
domain: lemmy.{{ .cloud.domain }}
externalDnsDomain: lemmy.{{ .cloud.baseDomain }}
tlsSecretName: lemmy-tls
dbName: lemmy
dbUser: lemmy
dbHost: postgres.postgres.svc.cluster.local
dbPort: 5432
smtp:
host: "{{ .cloud.smtp.host }}"
port: "{{ .cloud.smtp.port }}"
user: "{{ .cloud.smtp.user }}"
from: "noreply@{{ .cloud.baseDomain }}"
tls: "{{ .cloud.smtp.tls }}"
defaultSecrets:
- key: dbPassword
- key: adminPassword
- key: jwtSecret
- key: smtpPassword
requiredSecrets:
- postgres.password

4
lemmy/namespace.yaml Normal file
View File

@@ -0,0 +1,4 @@
apiVersion: v1
kind: Namespace
metadata:
name: {{ .namespace }}

11
lemmy/pvc-pictrs.yaml Normal file
View File

@@ -0,0 +1,11 @@
apiVersion: v1
kind: PersistentVolumeClaim
metadata:
name: lemmy-pictrs-storage
namespace: {{ .namespace }}
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: {{ .pictrsStorage }}

View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: lemmy-backend
namespace: {{ .namespace }}
spec:
type: ClusterIP
selector:
component: backend
ports:
- name: http
port: {{ .backendPort }}
targetPort: {{ .backendPort }}

13
lemmy/service-pictrs.yaml Normal file
View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: lemmy-pictrs
namespace: {{ .namespace }}
spec:
type: ClusterIP
selector:
component: pictrs
ports:
- name: http
port: {{ .pictrsPort }}
targetPort: {{ .pictrsPort }}

13
lemmy/service-ui.yaml Normal file
View File

@@ -0,0 +1,13 @@
apiVersion: v1
kind: Service
metadata:
name: lemmy-ui
namespace: {{ .namespace }}
spec:
type: ClusterIP
selector:
component: ui
ports:
- name: http
port: {{ .uiPort }}
targetPort: {{ .uiPort }}