commit 694cfc2ffb8fed42bca4d0c2b9cdd3b1d47a0c1a Author: Tanguy Herbron Date: Thu Mar 27 20:16:56 2025 +0100 feat: Initial commit diff --git a/README.md b/README.md new file mode 100644 index 0000000..0f23eb3 --- /dev/null +++ b/README.md @@ -0,0 +1,22 @@ +# Mastodon + +## Installation + +Before being able to run the Mastodon, the following command needs to be ran to create the db (from inside one of the pods): +```bash +bin/rails db:prepare +``` + +Create admin account +```bash +RAILS_ENV=production bin/tootctl accounts create admin --email admin@example.com --confirmed --role Owner +``` + +If you get a `Your application is pending review by our staff.` error, run the following command +```bash +RAILS_ENV=production bin/tootctl accounts modify admin --approve +``` + +## TODO + +Fix Redis configuration to enable Mastodon to work diff --git a/manifests/database-backup.yaml b/manifests/database-backup.yaml new file mode 100644 index 0000000..8167503 --- /dev/null +++ b/manifests/database-backup.yaml @@ -0,0 +1,10 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: ScheduledBackup +metadata: + name: mastodon-db-backup + namespace: mastodon +spec: + schedule: "0 0 0 * * *" + backupOwnerReference: self + cluster: + name: mastodon-db diff --git a/manifests/database-ondemand-backup.yaml b/manifests/database-ondemand-backup.yaml new file mode 100644 index 0000000..28b2b09 --- /dev/null +++ b/manifests/database-ondemand-backup.yaml @@ -0,0 +1,8 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Backup +metadata: + name: mastodon-db-ondemand-backup-280225 + namespace: mastodon +spec: + cluster: + name: mastodon-db diff --git a/manifests/database-recovery.yaml b/manifests/database-recovery.yaml new file mode 100644 index 0000000..8a1cd77 --- /dev/null +++ b/manifests/database-recovery.yaml @@ -0,0 +1,49 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: mastodon-db + namespace: mastodon + +spec: + imageName: ghcr.io/tensorchord/cloudnative-pgvecto.rs:16.5-v0.3.0 + instances: 1 + + storage: + size: 1Gi + storageClass: local-path + + bootstrap: + recovery: + source: mastodon-db + + postgresql: + pg_hba: + - host all all all md5 + + externalClusters: + - name: mastodon-db + barmanObjectStore: + serverName: mastodon-db + destinationPath: "s3://halis/cloudnativepg" + endpointURL: https://s3.halia.dev + s3Credentials: + accessKeyId: + name: s3-secret + key: AWS_ACCESS_KEY_ID + secretAccessKey: + name: s3-secret + key: AWS_SECRET_ACCESS_KEY + region: + name: s3-secret + key: AWS_REGION + wal: + compression: gzip + maxParallel: 8 + + resources: + requests: + cpu: 100m + memory: 512Mi + limits: + cpu: 500m + memory: 1Gi diff --git a/manifests/database.yaml b/manifests/database.yaml new file mode 100644 index 0000000..24cd6e6 --- /dev/null +++ b/manifests/database.yaml @@ -0,0 +1,52 @@ +apiVersion: postgresql.cnpg.io/v1 +kind: Cluster +metadata: + name: mastodon-db + namespace: mastodon + +spec: + instances: 3 + + storage: + size: 1Gi + storageClass: local-path + + bootstrap: + initdb: + database: mastodon + owner: mastodon + secret: + name: mastodon-db + + postgresql: + pg_hba: + - host all all all md5 + + backup: + barmanObjectStore: + destinationPath: "s3://halis/cloudnativepg" + endpointURL: https://s3.halia.dev + s3Credentials: + accessKeyId: + name: s3-secret + key: AWS_ACCESS_KEY_ID + secretAccessKey: + name: s3-secret + key: AWS_SECRET_ACCESS_KEY + region: + name: s3-secret + key: AWS_REGION + wal: + compression: gzip + maxParallel: 8 + + resources: + requests: + cpu: 100m + memory: 512Mi + limits: + cpu: 500m + memory: 1Gi + + monitoring: + enablePodMonitor: true diff --git a/manifests/deployment.yaml b/manifests/deployment.yaml new file mode 100644 index 0000000..20c04cf --- /dev/null +++ b/manifests/deployment.yaml @@ -0,0 +1,215 @@ +apiVersion: apps/v1 +kind: Deployment +metadata: + name: mastodon + namespace: mastodon +spec: + replicas: 1 + selector: + matchLabels: + app: mastodon + template: + metadata: + labels: + app: mastodon + spec: + securityContext: + runAsUser: 991 + runAsGroup: 991 + fsGroup: 991 + containers: + - name: mastodon-web + image: ghcr.io/mastodon/mastodon:v4.3.6 + command: ["bundle", "exec", "puma", "-C", "config/puma.rb"] + ports: + - containerPort: 3000 + - containerPort: 9394 + name: web-metrics + env: + - name: LOCAL_DOMAIN + value: "halis.io" + - name: WEB_DOMAIN + value: "mastodon.halis.io" + - name: REDIS_HOST + value: "redis-svc.mastodon.svc.cluster.local" + - name: REDIS_PORT + value: "6379" + - name: DB_HOST + value: "mastodon-db-rw.mastodon.svc.cluster.local" + - name: DB_USER + valueFrom: + secretKeyRef: + name: mastodon-db + key: username + - name: DB_PASS + valueFrom: + secretKeyRef: + name: mastodon-db + key: password + - name: DB_NAME + value: "mastodon" + - name: DB_PORT + value: "5432" + - name: SECRET_KEY_BASE + valueFrom: + secretKeyRef: + name: mastodon-secrets + key: SECRET_KEY_BASE + - name: OTP_SECRET + valueFrom: + secretKeyRef: + name: mastodon-secrets + key: OTP_SECRET + - name: ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY + valueFrom: + secretKeyRef: + name: mastodon-secrets + key: ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY + - name: ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT + valueFrom: + secretKeyRef: + name: mastodon-secrets + key: ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT + - name: ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY + valueFrom: + secretKeyRef: + name: mastodon-secrets + key: ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY + - name: IP_RETENTION_PERIOD + value: "31556952" + - name: SESSION_RETENTION_PERIOD + value: "31556952" + - name: FETCH_REPLIES_ENABLED + value: "false" + - name: FETCH_REPLIES_COOLDOWN_MINUTES + value: "15" + - name: FETCH_REPLIES_INITIAL_WAIT_MINUTES + value: "5" + - name: FETCH_REPLIES_MAX_GLOBAL + value: "1000" + - name: FETCH_REPLIEX_MAX_SINGLE + value: "500" + - name: FETCH_REPLIES_MAX_PAGES + value: "500" + - name: STREAMING_API_BASE_URL + value: "http://mastodon-svc.mastodon.svc.cluster.local:4000" + - name: MASTODON_PROMETHEUS_EXPORTER_ENABLED + value: "true" + - name: MASTODON_PROMETHEUS_EXPORTER_LOCAL + value: "true" + - name: MASTODON_PROMETHEUS_EXPORTER_HOST + value: "127.0.0.1" + - name: MASTODON_PROMETHEUS_EXPORTER_PORT + value: "9394" + volumeMounts: + - mountPath: "/mastodon/public/system" + name: mastodon-data + - name: mastodon-streaming + image: ghcr.io/mastodon/mastodon-streaming:v4.3.6 + command: ["node", "./streaming/index.js"] + ports: + - containerPort: 4000 + name: streaming + env: + - name: ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY + valueFrom: + secretKeyRef: + name: mastodon-secrets + key: ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY + - name: ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT + valueFrom: + secretKeyRef: + name: mastodon-secrets + key: ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT + - name: ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY + valueFrom: + secretKeyRef: + name: mastodon-secrets + key: ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY + - name: REDIS_HOST + value: "redis-svc.mastodon.svc.cluster.local" + - name: REDIS_PORT + value: "6379" + - name: mastodon-sidekiq + image: ghcr.io/mastodon/mastodon:v4.3.6 + command: ["bundle", "exec", "sidekiq"] + ports: + - containerPort: 9395 + name: sidekiq-metrics + env: + - name: LOCAL_DOMAIN + value: "halis.io" + - name: WEB_DOMAIN + value: "mastodon.halis.io" + - name: REDIS_HOST + value: "redis-svc.mastodon.svc.cluster.local" + - name: REDIS_PORT + value: "6379" + - name: DB_HOST + value: "mastodon-db-rw.mastodon.svc.cluster.local" + - name: DB_USER + valueFrom: + secretKeyRef: + name: mastodon-db + key: username + - name: DB_PASS + valueFrom: + secretKeyRef: + name: mastodon-db + key: password + - name: DB_NAME + value: "mastodon" + - name: DB_PORT + value: "5432" + - name: SECRET_KEY_BASE + valueFrom: + secretKeyRef: + name: mastodon-secrets + key: SECRET_KEY_BASE + - name: OTP_SECRET + valueFrom: + secretKeyRef: + name: mastodon-secrets + key: OTP_SECRET + - name: ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY + valueFrom: + secretKeyRef: + name: mastodon-secrets + key: ACTIVE_RECORD_ENCRYPTION_DETERMINISTIC_KEY + - name: ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT + valueFrom: + secretKeyRef: + name: mastodon-secrets + key: ACTIVE_RECORD_ENCRYPTION_KEY_DERIVATION_SALT + - name: ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY + valueFrom: + secretKeyRef: + name: mastodon-secrets + key: ACTIVE_RECORD_ENCRYPTION_PRIMARY_KEY + - name: STREAMING_API_BASE_URL + value: "http://mastodon-svc.mastodon.svc.cluster.local:4000" + - name: MASTODON_PROMETHEUS_EXPORTER_ENABLED + value: "true" + - name: MASTODON_PROMETHEUS_EXPORTER_LOCAL + value: "true" + - name: MASTODON_PROMETHEUS_EXPORTER_HOST + value: "0.0.0.0" + - name: MASTODON_PROMETHEUS_EXPORTER_PORT + value: "9395" + volumeMounts: + - mountPath: "/mastodon/public/system" + name: mastodon-data + - name: redis + image: redis:7.4.2 + ports: + - containerPort: 6379 + volumeMounts: + - mountPath: "/data" + name: redis-data + volumes: + - name: mastodon-data + persistentVolumeClaim: + claimName: mastodon-pvc + - name: redis-data + persistentVolumeClaim: + claimName: redis-pvc diff --git a/manifests/ingress.yaml b/manifests/ingress.yaml new file mode 100644 index 0000000..4d40061 --- /dev/null +++ b/manifests/ingress.yaml @@ -0,0 +1,29 @@ +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: mastodon-ingress + namespace: mastodon + annotations: + cert-manager.io/cluster-issuer: letsencrypt-production + kubernetes.io/ingress.class: nginx-external + acme.cert-manager.io/http01-edit-in-place: "true" + nginx.ingress.kubernetes.io/proxy-body-size: "0" + nginx.ingress.kubernetes.io/proxy-read-timeout: "600" + nginx.ingress.kubernetes.io/proxy-send-timeout: "600" +spec: + tls: + - hosts: + - mastodon.halis.io + secretName: mastodon-halis-io-tls + ingressClassName: nginx-external + rules: + - host: mastodon.halis.io + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: mastodon-svc + port: + number: 80 diff --git a/manifests/kustomization.yaml b/manifests/kustomization.yaml new file mode 100644 index 0000000..2d9ce3d --- /dev/null +++ b/manifests/kustomization.yaml @@ -0,0 +1,14 @@ +apiVersion: kustomize.config.k8s.io/v1beta1 +kind: Kustomization + +resources: + - namespace.yaml + - secrets.yaml + - database.yaml + - deployment.yaml + - database-backup.yaml + - service.yaml + - servicemonitor.yaml + - redis-service.yaml + - ingress.yaml + - pvc.yaml diff --git a/manifests/namespace.yaml b/manifests/namespace.yaml new file mode 100644 index 0000000..1bef519 --- /dev/null +++ b/manifests/namespace.yaml @@ -0,0 +1,4 @@ +apiVersion: v1 +kind: Namespace +metadata: + name: mastodon diff --git a/manifests/pvc.yaml b/manifests/pvc.yaml new file mode 100644 index 0000000..1e711e8 --- /dev/null +++ b/manifests/pvc.yaml @@ -0,0 +1,31 @@ +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: mastodon-pvc + namespace: mastodon + labels: + recurring-job.longhorn.io/source: enabled + recurring-job-group.longhorn.io/standard-pvc: enabled +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 50Gi + storageClassName: redundant-storage-class +--- +apiVersion: v1 +kind: PersistentVolumeClaim +metadata: + name: redis-pvc + namespace: mastodon + labels: + recurring-job.longhorn.io/source: enabled + recurring-job-group.longhorn.io/standard-pvc: enabled +spec: + accessModes: + - ReadWriteOnce + resources: + requests: + storage: 10Gi + storageClassName: redundant-storage-class diff --git a/manifests/redis-service.yaml b/manifests/redis-service.yaml new file mode 100644 index 0000000..9603b99 --- /dev/null +++ b/manifests/redis-service.yaml @@ -0,0 +1,15 @@ +apiVersion: v1 +kind: Service +metadata: + name: redis-svc + namespace: mastodon + labels: + app.kubernetes.io/name: mastodon +spec: + ports: + - name: http + port: 6379 + protocol: TCP + targetPort: 6379 + selector: + app: mastodon diff --git a/manifests/secrets.yaml b/manifests/secrets.yaml new file mode 100644 index 0000000..e1d7c15 --- /dev/null +++ b/manifests/secrets.yaml @@ -0,0 +1,24 @@ +apiVersion: argoproj.io/v1alpha1 +kind: Application +metadata: + name: mastodon-secrets + namespace: argocd + finalizers: + - resources-finalizer.argocd.argoproj.io +spec: + project: default + source: + repoURL: https://git.halis.io/athens-school/k3s-secrets + targetRevision: prod-migration + path: mastodon + syncPolicy: + automated: + prune: true + selfHeal: true + syncOptions: + - CreateNamespace=false + - ApplyOutOfSyncOnly=true + - PruneLast=true + destination: + server: https://kubernetes.default.svc + namespace: mastodon diff --git a/manifests/service.yaml b/manifests/service.yaml new file mode 100644 index 0000000..8740a05 --- /dev/null +++ b/manifests/service.yaml @@ -0,0 +1,19 @@ +apiVersion: v1 +kind: Service +metadata: + name: mastodon-svc + namespace: mastodon + labels: + app.kubernetes.io/name: mastodon +spec: + ports: + - name: http + port: 80 + protocol: TCP + targetPort: 3000 + - name: streaming + port: 4000 + protocol: TCP + targetPort: 4000 + selector: + app: mastodon diff --git a/manifests/servicemonitor.yaml b/manifests/servicemonitor.yaml new file mode 100644 index 0000000..4380695 --- /dev/null +++ b/manifests/servicemonitor.yaml @@ -0,0 +1,18 @@ +apiVersion: monitoring.coreos.com/v1 +kind: ServiceMonitor +metadata: + name: mastodon + namespace: mastodon + labels: + team: core +spec: + selector: + matchLabels: + app.kubernetes.io/name: mastodon + endpoints: + - port: streaming + path: /metrics + - port: web-metrics + path: /metrics + - port: sidekiq-metrics + path: /metrics