From 8d83e333c8cb711e21f54d45b2203d1d501587ce Mon Sep 17 00:00:00 2001 From: Janne Mareike Koschinski <janne@kuschku.de> Date: Wed, 30 Nov 2022 21:56:55 +0100 Subject: [PATCH] feat: add mastodon chart --- .gitlab-ci.yml | 1 + mastodon/Chart.yaml | 6 + mastodon/pipeline.yml | 21 ++++ mastodon/templates/_helpers.tpl | 56 +++++++++ mastodon/templates/deployment-sidekiq.yaml | 85 +++++++++++++ mastodon/templates/deployment-streaming.yaml | 78 ++++++++++++ mastodon/templates/deployment-web.yaml | 86 +++++++++++++ mastodon/templates/ingress.yaml | 37 ++++++ mastodon/templates/pod-tootctl.yaml | 50 ++++++++ mastodon/templates/secret.yaml | 97 +++++++++++++++ mastodon/templates/service-streaming.yaml | 17 +++ mastodon/templates/service-web.yaml | 17 +++ mastodon/values.yaml | 122 +++++++++++++++++++ 13 files changed, 673 insertions(+) create mode 100644 mastodon/Chart.yaml create mode 100644 mastodon/pipeline.yml create mode 100644 mastodon/templates/_helpers.tpl create mode 100644 mastodon/templates/deployment-sidekiq.yaml create mode 100644 mastodon/templates/deployment-streaming.yaml create mode 100644 mastodon/templates/deployment-web.yaml create mode 100644 mastodon/templates/ingress.yaml create mode 100644 mastodon/templates/pod-tootctl.yaml create mode 100644 mastodon/templates/secret.yaml create mode 100644 mastodon/templates/service-streaming.yaml create mode 100644 mastodon/templates/service-web.yaml create mode 100644 mastodon/values.yaml diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 889e30a..44b6dcd 100644 --- a/.gitlab-ci.yml +++ b/.gitlab-ci.yml @@ -13,6 +13,7 @@ include: - /jellyfin/pipeline.yml - /languagetool/pipeline.yml - /mailu/pipeline.yml +- /mastodon/pipeline.yml - /oauth2-proxy/pipeline.yml - /quassel/pipeline.yml - /restic/pipeline.yml diff --git a/mastodon/Chart.yaml b/mastodon/Chart.yaml new file mode 100644 index 0000000..2e029b7 --- /dev/null +++ b/mastodon/Chart.yaml @@ -0,0 +1,6 @@ +apiVersion: v2 +name: mastodon +description: Helm Chart for mastodon +type: application +version: 0.3.0 +appVersion: "v4.0" diff --git a/mastodon/pipeline.yml b/mastodon/pipeline.yml new file mode 100644 index 0000000..8b2a2bc --- /dev/null +++ b/mastodon/pipeline.yml @@ -0,0 +1,21 @@ +lint-mastodon: + stage: lint + rules: + - changes: + - mastodon/**/* + script: + - helm lint mastodon + +release-mastodon: + stage: release + needs: + - lint-mastodon + rules: + - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH' + changes: + - mastodon/**/* + script: + - apk add --no-cache git + - helm plugin install https://github.com/chartmuseum/helm-push.git + - helm repo add --username gitlab-ci-token --password $CI_JOB_TOKEN repo ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/helm/stable + - helm cm-push mastodon repo diff --git a/mastodon/templates/_helpers.tpl b/mastodon/templates/_helpers.tpl new file mode 100644 index 0000000..f926d62 --- /dev/null +++ b/mastodon/templates/_helpers.tpl @@ -0,0 +1,56 @@ +{{/* +Expand the name of the chart. +*/}} +{{- define "mastodon-helm.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 "mastodon-helm.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 }} + +{{/* +Create chart name and version as used by the chart label. +*/}} +{{- define "mastodon-helm.chart" -}} +{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} +{{- end }} + +{{/* +Common labels +*/}} +{{- define "mastodon-helm.labels" -}} +helm.sh/chart: {{ include "mastodon-helm.chart" . }} +{{ include "mastodon-helm.selectorLabels" . }} +{{- if .Chart.AppVersion }} +app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} +{{- end }} +app.kubernetes.io/managed-by: {{ .Release.Service }} +{{- end }} + +{{/* +Selector labels +*/}} +{{- define "mastodon-helm.selectorLabels" -}} +app.kubernetes.io/name: {{ include "mastodon-helm.name" . }} +app.kubernetes.io/instance: {{ .Release.Name }} +{{- end }} + + +{{- define "mastodon-helm.sslPath" -}} +/certs +{{- end }} diff --git a/mastodon/templates/deployment-sidekiq.yaml b/mastodon/templates/deployment-sidekiq.yaml new file mode 100644 index 0000000..7d46ee5 --- /dev/null +++ b/mastodon/templates/deployment-sidekiq.yaml @@ -0,0 +1,85 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "mastodon-helm.fullname" . }}-sidekiq + labels: + component: sidekiq + {{- include "mastodon-helm.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + component: sidekiq + {{- include "mastodon-helm.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + component: sidekiq + {{- include "mastodon-helm.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + volumes: + - name: data + {{- .Values.volumes.data | nindent 10 }} + - name: tmp + emptyDir: + medium: Memory + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.sidekiq.repository }}:{{ .Values.sidekiq.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.sidekiq.pullPolicy }} + command: + - "bundle" + - "exec" + - "sidekiq" + envFrom: + - secretRef: + name: {{ include "mastodon-helm.fullname" . }} + startupProbe: + exec: + command: + - "/bin/sh" + - "-c" + - "ps aux | grep '[s]idekiq\ 6' || false" + livenessProbe: + exec: + command: + - "/bin/sh" + - "-c" + - "ps aux | grep '[s]idekiq\ 6' || false" + readinessProbe: + exec: + command: + - "/bin/sh" + - "-c" + - "ps aux | grep '[s]idekiq\ 6' || false" + resources: + {{- toYaml .Values.sidekiq.resources | nindent 12 }} + volumeMounts: + - mountPath: "/mastodon/public/system" + name: data + - mountPath: "/opt/mastodon/tmp" + name: tmp + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/mastodon/templates/deployment-streaming.yaml b/mastodon/templates/deployment-streaming.yaml new file mode 100644 index 0000000..f4d0541 --- /dev/null +++ b/mastodon/templates/deployment-streaming.yaml @@ -0,0 +1,78 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "mastodon-helm.fullname" . }}-streaming + labels: + component: streaming + {{- include "mastodon-helm.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + component: streaming + {{- include "mastodon-helm.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + component: streaming + {{- include "mastodon-helm.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + volumes: + - name: tmp + emptyDir: + medium: Memory + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.streaming.repository }}:{{ .Values.streaming.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.streaming.pullPolicy }} + command: + - "node" + - "./streaming" + envFrom: + - secretRef: + name: {{ include "mastodon-helm.fullname" . }} + ports: + - containerPort: 4000 + name: websocket + protocol: TCP + startupProbe: + httpGet: + port: websocket + path: /api/v1/streaming/health + livenessProbe: + httpGet: + port: websocket + path: /api/v1/streaming/health + readinessProbe: + httpGet: + port: websocket + path: /api/v1/streaming/health + resources: + {{- toYaml .Values.streaming.resources | nindent 12 }} + volumeMounts: + - mountPath: "/opt/mastodon/tmp" + name: tmp + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/mastodon/templates/deployment-web.yaml b/mastodon/templates/deployment-web.yaml new file mode 100644 index 0000000..4d99db6 --- /dev/null +++ b/mastodon/templates/deployment-web.yaml @@ -0,0 +1,86 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: {{ include "mastodon-helm.fullname" . }}-web + labels: + component: web + {{- include "mastodon-helm.labels" . | nindent 4 }} +spec: + replicas: {{ .Values.replicaCount }} + selector: + matchLabels: + component: web + {{- include "mastodon-helm.selectorLabels" . | nindent 6 }} + template: + metadata: + {{- with .Values.podAnnotations }} + annotations: + {{- toYaml . | nindent 8 }} + {{- end }} + labels: + component: web + {{- include "mastodon-helm.selectorLabels" . | nindent 8 }} + spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 8 }} + {{- end }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 8 }} + volumes: + - name: data + {{- .Values.volumes.data | nindent 10 }} + - name: tmp + emptyDir: + medium: Memory + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 12 }} + image: "{{ .Values.web.repository }}:{{ .Values.web.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.web.pullPolicy }} + command: + - "bundle" + - "exec" + - "rails" + - "s" + - "-p" + - "3000" + envFrom: + - secretRef: + name: {{ include "mastodon-helm.fullname" . }} + ports: + - containerPort: 3000 + name: http + protocol: TCP + startupProbe: + httpGet: + port: http + path: /health + livenessProbe: + httpGet: + port: http + path: /health + readinessProbe: + httpGet: + port: http + path: /health + resources: + {{- toYaml .Values.web.resources | nindent 12 }} + volumeMounts: + - mountPath: "/mastodon/public/system" + name: data + - mountPath: "/opt/mastodon/tmp" + name: tmp + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 8 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 8 }} + {{- end }} diff --git a/mastodon/templates/ingress.yaml b/mastodon/templates/ingress.yaml new file mode 100644 index 0000000..6354a7a --- /dev/null +++ b/mastodon/templates/ingress.yaml @@ -0,0 +1,37 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: {{ include "mastodon-helm.fullname" . }} + labels: + {{- include "mastodon-helm.labels" . | nindent 4 }} + annotations: + {{- .Values.ingress.annotations | toYaml | nindent 4 }} +spec: + rules: + - host: "{{ .Values.config.domainWeb }}" + http: + paths: + - path: "{{ .Values.ingress.webPath }}" + backend: + service: + name: {{ include "mastodon-helm.fullname" . }}-web + port: + name: http + pathType: Prefix + - path: "{{ .Values.ingress.streamingPath }}" + backend: + service: + name: {{ include "mastodon-helm.fullname" . }}-streaming + port: + name: websocket + pathType: Prefix + - host: "{{ .Values.config.domainHandle }}" + http: + paths: + - path: "/.well-known/webfinger" + backend: + service: + name: {{ include "mastodon-helm.fullname" . }}-web + port: + name: http + pathType: Prefix diff --git a/mastodon/templates/pod-tootctl.yaml b/mastodon/templates/pod-tootctl.yaml new file mode 100644 index 0000000..a8e7e53 --- /dev/null +++ b/mastodon/templates/pod-tootctl.yaml @@ -0,0 +1,50 @@ +apiVersion: v1 +kind: Pod +metadata: + name: {{ include "mastodon-helm.fullname" . }}-tootctl + labels: + component: tootctl + {{- include "mastodon-helm.labels" . | nindent 4 }} +spec: + {{- with .Values.imagePullSecrets }} + imagePullSecrets: + {{- toYaml . | nindent 4 }} + {{- end }} + securityContext: + {{- toYaml .Values.podSecurityContext | nindent 4 }} + volumes: + - name: data + {{- .Values.volumes.data | nindent 6 }} + - name: tmp + emptyDir: + medium: Memory + containers: + - name: {{ .Chart.Name }} + securityContext: + {{- toYaml .Values.securityContext | nindent 8 }} + image: "{{ .Values.web.repository }}:{{ .Values.web.tag | default .Chart.AppVersion }}" + imagePullPolicy: {{ .Values.web.pullPolicy }} + command: + - "/bin/sh" + - "-c" + - "while true; do sleep 60; done" + envFrom: + - secretRef: + name: {{ include "mastodon-helm.fullname" . }} + volumeMounts: + - mountPath: "/mastodon/public/system" + name: data + - mountPath: "/opt/mastodon/tmp" + name: tmp + {{- with .Values.nodeSelector }} + nodeSelector: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.affinity }} + affinity: + {{- toYaml . | nindent 4 }} + {{- end }} + {{- with .Values.tolerations }} + tolerations: + {{- toYaml . | nindent 4 }} + {{- end }} diff --git a/mastodon/templates/secret.yaml b/mastodon/templates/secret.yaml new file mode 100644 index 0000000..e9f6076 --- /dev/null +++ b/mastodon/templates/secret.yaml @@ -0,0 +1,97 @@ +apiVersion: v1 +kind: Secret +metadata: + name: {{ include "mastodon-helm.fullname" . }} + labels: + {{- include "mastodon-helm.labels" . | nindent 4 }} +stringData: + # This is a sample configuration file. You can generate your configuration + # with the `rake mastodon:setup` interactive setup wizard, but to customize + # your setup even further, you'll need to edit it manually. This sample does + # not demonstrate all available configuration options. Please look at + # https://docs.joinmastodon.org/admin/config/ for the full documentation. + + # Note that this file accepts slightly different syntax depending on whether + # you are using `docker-compose` or not. In particular, if you use + # `docker-compose`, the value of each declared variable will be taken verbatim, + # including surrounding quotes. + # See: https://github.com/mastodon/mastodon/issues/16895 + + # Mode + RAILS_ENV: production + NODE_ENV: production + + # Federation and access + # ---------- + # This identifies your server and cannot be changed safely later + # ---------- + LOCAL_DOMAIN: "{{ .Values.config.domainHandle }}" + WEB_DOMAIN: "{{ .Values.config.domainWeb }}" + TRUSTED_PROXY_IP: "{{ .Values.config.trustedSubnet }}" + + # Redis + # ----- + REDIS_URL: "redis://:{{ .Values.redis.password }}@{{ .Values.redis.hostname }}:{{ .Values.redis.port }}/{{ .Values.redis.database }}" + + # PostgreSQL + # ---------- + DB_HOST: "{{ .Values.postgres.hostname }}" + DB_PORT: "{{ .Values.postgres.port}}" + DB_USER: "{{ .Values.postgres.username }}" + DB_NAME: "{{ .Values.postgres.database }}" + DB_PASS: "{{ .Values.postgres.password }}" + + # Elasticsearch (optional) + # ------------------------ + ES_ENABLED: "{{ .Values.elasticsearch.enabled }}" + ES_HOST: "{{ .Values.elasticsearch.hostname }}" + ES_PORT: "{{ .Values.elasticsearch.port }}" + ES_PREFIX: "{{ .Values.elasticsearch.database }}" + # Authentication for ES (optional) + ES_USER: "{{ .Values.elasticsearch.username }}" + ES_PASS: "{{ .Values.elasticsearch.password }}" + + # Secrets + # ------- + # Make sure to use `rake secret` to generate secrets + # ------- + SECRET_KEY_BASE: "{{ .Values.keys.secretKeyBase }}" + OTP_SECRET: "{{ .Values.keys.otpSecret }}" + + # Web Push + # -------- + # Generate with `rake mastodon:webpush:generate_vapid_key` + # -------- + VAPID_PRIVATE_KEY: "{{ .Values.keys.vapidPrivate }}" + VAPID_PUBLIC_KEY: "{{ .Values.keys.vapidPublic }}" + + # Sending mail + # ------------ + SMTP_SERVER: "{{ .Values.smtp.hostname }}" + SMTP_PORT: "{{ .Values.smtp.port }}" + SMTP_TLS: "{{ .Values.smtp.tls }}" + SMTP_ENABLE_STARTTLS: "{{ .Values.smtp.startTls }}" + SMTP_LOGIN: "{{ .Values.smtp.username }}" + SMTP_PASSWORD: "{{ .Values.smtp.password }}" + SMTP_FROM_ADDRESS: "{{ .Values.smtp.from }}" + + # File storage (optional) + # ----------------------- + S3_ENABLED: "{{ .Values.s3.enabled }}" + S3_PROTOCOL: "https" + S3_REGION: "us-east-1" + S3_HOSTNAME: "{{ .Values.s3.hostname }}" + S3_ENDPOINT: "https://{{ .Values.s3.hostname }}" + S3_BUCKET: "{{ .Values.s3.bucket }}" + AWS_ACCESS_KEY_ID: "{{ .Values.s3.accessKey }}" + AWS_SECRET_ACCESS_KEY: "{{ .Values.s3.secretKey }}" + #S3_ALIAS_HOST: "{{ .Values.s3.aliasHost }}" + + # IP and session retention + # ----------------------- + # Make sure to modify the scheduling of ip_cleanup_scheduler in config/sidekiq.yml + # to be less than daily if you lower IP_RETENTION_PERIOD below two days (172800). + # ----------------------- + IP_RETENTION_PERIOD: "31556952" + SESSION_RETENTION_PERIOD: "31556952" + diff --git a/mastodon/templates/service-streaming.yaml b/mastodon/templates/service-streaming.yaml new file mode 100644 index 0000000..80197cc --- /dev/null +++ b/mastodon/templates/service-streaming.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "mastodon-helm.fullname" . }}-streaming + labels: + component: streaming + {{- include "mastodon-helm.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: 4000 + targetPort: websocket + protocol: TCP + name: websocket + selector: + component: streaming + {{- include "mastodon-helm.selectorLabels" . | nindent 4 }} diff --git a/mastodon/templates/service-web.yaml b/mastodon/templates/service-web.yaml new file mode 100644 index 0000000..ff730b7 --- /dev/null +++ b/mastodon/templates/service-web.yaml @@ -0,0 +1,17 @@ +apiVersion: v1 +kind: Service +metadata: + name: {{ include "mastodon-helm.fullname" . }}-web + labels: + component: web + {{- include "mastodon-helm.labels" . | nindent 4 }} +spec: + type: {{ .Values.service.type }} + ports: + - port: 80 + targetPort: http + protocol: TCP + name: http + selector: + component: web + {{- include "mastodon-helm.selectorLabels" . | nindent 4 }} diff --git a/mastodon/values.yaml b/mastodon/values.yaml new file mode 100644 index 0000000..442bdbe --- /dev/null +++ b/mastodon/values.yaml @@ -0,0 +1,122 @@ +replicaCount: 1 + +imagePullSecrets: [ ] +nameOverride: "" +fullnameOverride: "" + +web: + repository: tootsuite/mastodon + pullPolicy: IfNotPresent + tag: "" + resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 10m + memory: 64Mi + +streaming: + repository: tootsuite/mastodon + pullPolicy: IfNotPresent + tag: "" + resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 10m + memory: 64Mi + +sidekiq: + repository: tootsuite/mastodon + pullPolicy: IfNotPresent + tag: "" + resources: + limits: + cpu: 500m + memory: 512Mi + requests: + cpu: 10m + memory: 64Mi + +config: + domainHandle: "example.com" + domainWeb: "mastodon.example.com" + trustedSubnet: "127.0.0.1" + +keys: + # Make sure to use `rake secret` to generate secrets + secretKeyBase: "" + otpSecret: "" + # Generate with `rake mastodon:webpush:generate_vapid_key` + vapidPrivate: "" + vapidPublic: "" + +redis: + hostname: "example.com" + port: 6379 + database: 0 + password: "hunter2" + +postgres: + hostname: "example.com" + port: 5432 + database: "mastodon" + username: "mastodon" + password: "hunter2" + +elasticsearch: + enabled: false + hostname: "example.com" + port: 80 + database: "mastodon" + username: "mastodon" + password: "hunter2" + +smtp: + hostname: "example.com" + port: 465 + username: "notifications" + password: "hunter2" + tls: false + startTls: "auto" # auto, always, never + from: "notifications@example.com" + +s3: + enabled: false + hostname: "s3.example.com" + bucket: "mastodon" + accessKey: "mastodon" + secretKey: "hunter2" + aliasHost: "mastodon.s3.example.com" + +volumes: + data: |- + emptyDir: {} + +service: + type: ClusterIP + +ingress: + webPath: "/" + streamingPath: "/streaming" + annotations: { } + +podAnnotations: { } + +podSecurityContext: + fsGroup: 2000 + +securityContext: + capabilities: + drop: + - ALL + runAsNonRoot: true + runAsUser: 1000 + +nodeSelector: { } + +tolerations: [ ] + +affinity: { } -- GitLab