Compare commits

...

53 Commits

Author SHA1 Message Date
bc910787df Open for node port 2025-12-04 03:07:18 -06:00
4e16bfc88e Add DB for Nextcloud 2025-12-04 03:02:23 -06:00
3b8be5c7ee Add DB for Nextcloud 2025-12-04 03:02:16 -06:00
6243db3cba Swap to using externalDb because Nextcloud chart absolutely sucks with defining custom values for the login info of the DB... 2025-12-04 03:02:01 -06:00
cff8972366 Fix Gitea c: 2025-12-04 03:01:19 -06:00
7aeee2f3c5 Alpha build at long last, finished 2025-12-03 01:39:57 -06:00
63b859b576 Add Velero and all remaining Matrix resources 2025-12-03 01:36:59 -06:00
96363ed7ca Add Velero 2025-12-03 01:36:46 -06:00
23b479a851 Add Velero annotations 2025-12-03 01:36:29 -06:00
8ad304a663 Define MMR DB 2025-12-03 01:35:58 -06:00
c6785f0b9b Flesh out homeserver 2025-12-03 01:35:41 -06:00
6b260de324 Clean up and remove httproute 2025-12-03 01:34:27 -06:00
07216ddae5 Properly set up DB for discord bridge 2025-12-03 01:33:57 -06:00
e26b421d44 Add Discord Bridge 2025-12-03 01:32:53 -06:00
e0c9e71fda Set correct port and add name 2025-12-03 01:32:38 -06:00
ae903af93c Add Matrix stack 2025-11-30 05:23:52 -06:00
11af17cd8a Add new resources 2025-11-30 05:23:39 -06:00
b0f9fa7205 Add to firewall 2025-11-30 05:23:25 -06:00
87fdd5b2fe Fix Prometheus 2025-11-30 05:23:13 -06:00
97ebd04d99 Fix Nextcloud (wtf broadcom) 2025-11-30 05:22:46 -06:00
e5ce37638e Define coturn (not enabling for awhile tho) 2025-11-30 05:22:28 -06:00
a920a01815 quickly outline mmr-db 2025-11-30 05:21:57 -06:00
0ac3993314 Define DB for just mautrix 2025-11-30 05:21:22 -06:00
bc6fc1dafe Split DB into two and delete the single resource here 2025-11-30 05:21:08 -06:00
350c7db62a Define MMR 2025-11-30 05:20:12 -06:00
01e405d125 Moved livekit into element-call 2025-11-30 05:19:53 -06:00
089f7045cc Since no more Caddy, Well-known needs to be split into its own resource 2025-11-30 05:19:30 -06:00
2be11cec39 Begin defining our homeserver 2025-11-30 05:19:05 -06:00
0b5e4285c7 Define Livekit Server 2025-11-30 05:18:47 -06:00
a3422f0e84 Define Livekit JWT 2025-11-30 05:18:31 -06:00
5261340c9e Define Element call 2025-11-30 05:18:20 -06:00
3caeb8cc0d Define Element 2025-11-30 05:17:58 -06:00
6e6410c824 Define Cinny 2025-11-30 05:15:29 -06:00
68946832dc add homeassistant 2025-11-30 05:15:17 -06:00
93da50fba1 Swap to using s3 w/ pvc and juicefs 2025-11-30 05:15:01 -06:00
2db2c19461 Add name to service port 2025-11-30 05:13:26 -06:00
ab7c7a1e04 Add name to service port 2025-11-30 05:13:16 -06:00
262468686f Add note for later 2025-11-29 16:34:12 -06:00
f84c10734d Change nextcloud to use new config style and add note for later 2025-11-29 16:33:59 -06:00
75b808a24f Move nextcloud to end 2025-11-29 16:15:14 -06:00
85d656ced0 Update SHA 2025-11-29 04:05:24 -06:00
8dd5e7aa3c Simplify wasabi-csi 2025-11-29 04:04:24 -06:00
2b1e4f012a Add juicefs redis 2025-11-29 04:03:49 -06:00
9855597b07 Remove explicit namespace 2025-11-29 04:03:42 -06:00
2722ab9869 Add PVC to foundry 2025-11-29 04:03:27 -06:00
41f04f8b85 Add juicefs 2025-11-29 04:02:56 -06:00
152030676e Stop hetzner-csi from trying to create kube-system namespace 2025-11-29 04:02:40 -06:00
275fd4376d Bump chart version and remove installCRDs 2025-11-29 04:02:27 -06:00
dcd765da15 Bump chart version 2025-11-29 04:02:12 -06:00
f758032876 Stop openbao from trying to create kube-system namespace 2025-11-29 04:02:01 -06:00
9987d7472f Add juicefs and second foundry to resource deployment configs 2025-11-29 04:01:36 -06:00
2d8c33b2b6 Add cronjob yaml (need to convert later) 2025-11-29 04:01:05 -06:00
8406246bb9 Add recovery steps 2025-11-29 04:00:23 -06:00
37 changed files with 1031 additions and 169 deletions

View File

@@ -201,6 +201,25 @@ node -e 'console.log("admin:" + require("bcryptjs").hashSync("password", 10))'
```
#### Restore Redis backup
If the JuiceFS pods are crashing saying "Database not formatted."
1. Download the backup Grab the latest JSON file from your pulumi-redis-backup bucket.
2. Restore the Metadata You need to run the load command. You can do this from a temporary pod or any machine that can talk to the Redis service.
Bash
###### Spin up a temporary toolbox pod
kubectl run -it --rm juicefs-restore --image=juicedata/mount:ce-v1.2.0 -- sh
###### Inside the pod:
1. Download your backup file (or copy/paste it if it's small)
(Assuming you copied the JSON content to a file named 'backup.json')
2. Run the load command
Format: juicefs load redis://:PASS@HOST:PORT/DB backup.json
juicefs load redis://:$(REDIS_PASS)@juicefs-redis.kube-system.svc.cluster.local:6379/1 backup.json
3. Restart the JuiceFS Pods Once the load command finishes, the metadata is back. Delete the JuiceFS CSI pods (or the application pods using them) to force them to restart. They will connect, see the valid filesystem, and mount instantly.
https://www.pulumi.com/registry/packages/docker-build/api-docs/image/
https://www.pulumi.com/registry/packages/docker/api-docs/buildxbuilder/#create

View File

@@ -1,10 +1,10 @@
{:paths ["src/main"]
:deps {
#_gigiaj/pulumicljs #_{:local/root "../pulumi-clojurescript"}
;;gigiaj/pulumicljs {:local/root "../pulumi-clojurescript"}
gigiaj/pulumicljs
{:git/url "https://github.com/GigiaJ/pulumi-clojurescript.git"
:git/sha "50c8098cbc6d0d07837afb1e8f763a818dd376d9"
:git/sha "b7467d9da44a86a185e3bfe4307a7fe71add4134"
}
funcool/promesa {:mvn/version "11.0.678"}
}}

View File

@@ -0,0 +1,72 @@
apiVersion: batch/v1
kind: CronJob
metadata:
name: juicefs-metadata-backup
namespace: kube-system
spec:
schedule: "0 3 * * *"
successfulJobsHistoryLimit: 3
failedJobsHistoryLimit: 1
jobTemplate:
spec:
template:
spec:
restartPolicy: OnFailure
volumes:
- name: backup-dir
emptyDir: {}
initContainers:
- name: dumper
image: juicedata/mount:ce-v1.2.0
command: ["/bin/sh", "-c"]
args:
- |
echo "Starting JuiceFS Metadata Dump..."
juicefs dump redis://:$(REDIS_PASS)@juicefs-redis.kube-system.svc.cluster.local:6379/1 > /backups/juicefs-meta.json
if [ -s /backups/juicefs-meta.json ]; then
echo "Dump successful (Size: $(du -h /backups/juicefs-meta.json | cut -f1))"
else
echo "Dump failed: File is empty"
exit 1
fi
volumeMounts:
- name: backup-dir
mountPath: /backups
env:
- name: REDIS_PASS
valueFrom:
secretKeyRef:
name: juicefs-redis-secrets
key: password
containers:
- name: uploader
image: minio/mc:latest
command: ["/bin/sh", "-c"]
args:
- |
echo "Configuring S3 Client..."
mc alias set s3storage $S3_ENDPOINT $S3_ACCESS_KEY $S3_SECRET_KEY
echo "Uploading backup..."
FILENAME="juicefs-meta-$(date +%Y-%m-%d).json"
mc cp /backups/juicefs-meta.json s3storage/$S3_BUCKET/backups/$FILENAME
echo "Backup Complete!"
volumeMounts:
- name: backup-dir
mountPath: /backups
env:
- name: S3_ENDPOINT
value: "http://wasabi-proxy.wasabi-proxy.svc.cluster.local"
- name: S3_BUCKET
value: "pulumi-redis-backup"
- name: S3_ACCESS_KEY
valueFrom:
secretKeyRef:
name: juicefs-csi-secrets
key: access-key
- name: S3_SECRET_KEY
valueFrom:
secretKeyRef:
name: juicefs-csi-secrets
key: secret-key

View File

@@ -10,7 +10,8 @@
initialize-resources-definition
shared-resources-definition
preparation-resources-definition
deployment-resources-definition]]
deployment-resources-definition
matrix-resources-definition]]
)
(:require-macros [pulumicljs.execution.general :refer [p->]]))
@@ -49,9 +50,10 @@
#(execute
shared-resources-definition
(fn [output] (let [secrets (p-> output .-harbor "vault:prepare" "stringData")]
#js {:url (p-> secrets .-host (fn [x] (str "https://" x)))
:username (p-> secrets .-username)
:password (p-> secrets .-password)})))))
#js {
:url (p-> secrets .-host (fn [x] (str "https://" x)))
:username (p-> secrets .-username)
:password (p-> secrets .-password)})))))
(def prepare-deployment-stack
(define-stack
@@ -67,6 +69,13 @@
"/home/jaggar/dotfiles/iac"
#(execute deployment-resources-definition (fn [output] {}))))
(def matrix-stack
(define-stack
"hetzner-k3s"
"matrix"
"/home/jaggar/dotfiles/iac"
#(execute matrix-resources-definition (fn [output] {}))))
(defn deploy-stack
([stack-definition inputs]
@@ -109,9 +118,10 @@
shared-outputs (deploy-stack shared-platform-stack
(conj reused-configs {:name "hetzner-k3s:apiToken" :value (-> cfg :apiToken) :secret true})
1000)
1000)
prepare-outputs (deploy-stack prepare-deployment-stack reused-configs 3000)
deployment-outputs (deploy-stack deployment-stack reused-configs 2000)
matrix-outputs (deploy-stack matrix-stack reused-configs 2000)
_ (.kill port-forward)]
"All stacks deployed and cleaned up successfully."))

View File

@@ -69,7 +69,10 @@
{:direction "in" :protocol "udp" :port "51820" :sourceIps ["0.0.0.0/0" "::/0"]}
{:direction "in" :protocol "tcp" :port "80" :sourceIps ["0.0.0.0/0" "::/0"]}
{:direction "in" :protocol "tcp" :port "443" :sourceIps ["0.0.0.0/0" "::/0"]}
{:direction "in" :protocol "icmp" :sourceIps ["0.0.0.0/0" "::/0"]}]}))
{:direction "in" :protocol "tcp" :port "30022" :sourceIps ["0.0.0.0/0" "::/0"]}
{:direction "in" :protocol "icmp" :sourceIps ["0.0.0.0/0" "::/0"]}
{:direction "in" :protocol "udp" :port "31000-31100" :sourceIps ["0.0.0.0/0" "::/0"]}
]}))
master (hcloud/Server.
"k3s-master-de"

View File

@@ -272,6 +272,7 @@
{:stack [:k8s:namespace :k8s:chart :generic:execute]
:app-namespace "vault"
:app-name "openbao"
:no-namespace true
:exec-fn execute-fn
:vault-load-yaml false
:k8s:chart-opts {:repositoryOpts {:repo "https://openbao.github.io/openbao-helm"}

View File

@@ -7,9 +7,8 @@
:is-prod? true
:k8s:chart-opts {:repositoryOpts {:repo "https://charts.jetstack.io"}
:chart "cert-manager"
:version "v1.15.0"
:namespace "cert-manager"
:values {:installCRDs true}}
:version "v1.19.1"
:namespace "cert-manager"}
:k8s:secret-opts {:metadata {:name "api-token-secret"}
:stringData {:apiToken 'token}}
:k8s:cluster-issuer-opts {:spec {:acme {:email 'email

View File

@@ -3,5 +3,5 @@
(def config
{:stack [:k8s:config-file]
:app-name "cert-manager"
:version "v1.15.0"
:version "v1.19.1"
:k8s:config-file-opts {:file '(str "https://github.com/cert-manager/cert-manager/releases/download/" version "/cert-manager.crds.yaml")}})

View File

@@ -0,0 +1,43 @@
(ns k8s.add-ons.csi-driver.extra.redis)
(def config
{:stack [:vault:prepare :k8s:secret :k8s:pvc :k8s:deployment :k8s:service]
:app-name "juicefs-redis"
:app-namespace "kube-system"
:no-namespace true
:k8s:pvc-opts
{:metadata {:name "juicefs-redis-data"
:namespace "kube-system"}
:spec {:accessModes ["ReadWriteOnce"]
:storageClassName "hcloud-volumes"
:resources {:requests {:storage "10Gi"}}}}
:k8s:deployment-opts
{:metadata {:name "juicefs-redis" :namespace "kube-system"}
:spec {:replicas 1
:selector {:matchLabels {:app "juicefs-redis"}}
:template {:metadata {:labels {:app "juicefs-redis"}}
:spec {:volumes [{:name "juicefs-redis-data"
:persistentVolumeClaim
{:claimName "juicefs-redis-data"}}]
:containers
[{:name "juicefs-redis"
:image "redis:7-alpine"
:args ["--requirepass" "$(REDIS_PASS)"
"--maxmemory-policy" "noeviction"
"--appendonly" "yes"]
:env [{:name "REDIS_PASS"
:valueFrom {:secretKeyRef {:name "juicefs-redis-secrets"
:key "password"}}}]
:ports [{:containerPort 6379}]
:volumeMounts [{:name "juicefs-redis-data"
:mountPath "/data"}]
}]}}}}
:k8s:service-opts
{:metadata {:name "juicefs-redis" :namespace "kube-system"}
:spec {:type "ClusterIP"
:selector {:app "juicefs-redis"}
:ports [{:name 'app-name
:port 6379 :targetPort 6379}]}}})

View File

@@ -5,6 +5,7 @@
(def config
{:stack [:k8s:secret :k8s:chart]
:app-namespace "kube-system"
:no-namespace true
:app-name "hcloud-csi"
:vault-load-yaml false
:k8s:secret-opts {:metadata {:name "hcloud"

View File

@@ -0,0 +1,29 @@
(ns k8s.add-ons.csi-driver.juicefs)
(def config
{:stack [:vault:prepare :k8s:secret :k8s:chart :k8s:csi-driver :k8s:storage-class]
:app-namespace "kube-system"
:no-namespace true
:app-name "juicefs-csi"
:k8s:csi-driver-opts
{:metadata {:name "csi.juicefs.com"}
:spec {:attachRequired false
:podInfoOnMount true
:volumeLifecycleModes ["Persistent"]}}
:k8s:chart-opts
{:repositoryOpts {:repo "https://juicedata.github.io/charts/"}
:chart "juicefs-csi-driver"
:version "0.30.3"
:namespace "kube-system"
:values {:kubeletDir "/var/lib/kubelet"}}
:k8s:storage-class-opts
{:metadata {:name "juicefs-sc"}
:provisioner "csi.juicefs.com"
:parameters {"csi.storage.k8s.io/provisioner-secret-name" "juicefs-csi-secrets"
"csi.storage.k8s.io/provisioner-secret-namespace" "kube-system"
"csi.storage.k8s.io/node-publish-secret-name" "juicefs-csi-secrets"
"csi.storage.k8s.io/node-publish-secret-namespace" "kube-system"
"csi.storage.k8s.io/controller-expand-secret-name" "juicefs-csi-secrets"
"csi.storage.k8s.io/controller-expand-secret-namespace" "kube-system"
"pathPattern" "${.pvc.namespace}/${.pvc.name}"}}})

View File

@@ -10,17 +10,7 @@
:repositoryOpts {:repo "https://yandex-cloud.github.io/k8s-csi-s3/charts"}
:values {:controller {:enabled false
:existingSecret {:name "wasabi-csi-secrets"}
:node {:existingSecret {:name "wasabi-csi-secrets"}}}}
#_:storageClass #_{:create true
:name "csi-s3-sc"
:singleBucket "pulumi-harbor"
:region "us-east-1"
:accessKeyID "something"
:secretAccessKey "something"
;;:bucket "pulumi-harbor"
}}
:node {:existingSecret {:name "wasabi-csi-secrets"}}}}}
:k8s:secret-opts {:stringData {:accessKeyID (-> cfg :wasabiId)
:secretAccessKey (-> cfg :wasabiKey)
:endpoint "http://wasabi-proxy.wasabi-proxy.svc.cluster.local"}}
:vault-load-yaml false})
:endpoint "http://wasabi-proxy.wasabi-proxy.svc.cluster.local"}}})

View File

@@ -54,6 +54,7 @@
:k8s:service-opts
{:spec
{:ports
[{:port 80
[{:name 'app-name
:port 80
:targetPort 80}]}}})

View File

@@ -1,7 +1,8 @@
(ns k8s.services.foundryvtt.service)
;; Need to automate license unlock
(def config
{:stack [:vault:prepare :harbor:robot-account :docker:image [:k8s :deployment :service :httproute]]
{:stack [:vault:prepare :harbor:robot-account :docker:image [:k8s :pvc :deployment :service :httproute]]
:image-port 30000
:app-namespace "generic"
:app-name "foundry"
@@ -14,11 +15,23 @@
:tags ['(str registry-base "/" registry-namespace "/" app-name)]
:push true}
:k8s:deployment-opts {:spec {:template {:spec {:imagePullSecrets [{:name "harbor-creds-secrets"}]
:containers [{:name 'app-name :image '(str registry-base "/" registry-namespace "/" app-name ":latest")}]}}}}
:volumes [{:name "data-vol"
:persistentVolumeClaim {:claimName "vtt-assets"}}]
:containers [{:name 'app-name :image '(str registry-base "/" registry-namespace "/" app-name ":latest")
:volumeMounts [{:name "data-vol"
:mountPath "/root/.local/share"
:mountPropagation "HostToContainer"}]
}]}}}}
:harbor:robot-account-opts {:name 'app-name
:permissions [{:kind "project"
:namespace 'registry-namespace
:access [{:action "pull" :resource "repository"}
{:action "push" :resource "repository"}
{:action "list" :resource "repository"}]}]}
:k8s:pvc-opts
{:metadata {:name "vtt-assets"
:namespace "generic"}
:spec {:storageClassName "juicefs-sc"
:accessModes ["ReadWriteMany"]
:resources {:requests {:storage "10Gi"}}}}
:k8s:httproute-opts {:spec {::hostnames ['host]}}})

View File

@@ -1,25 +1,51 @@
(ns k8s.services.gitea.service)
(def config
{:stack [:vault:prepare :k8s:deployment :k8s:service :k8s:httproute]
:image-port 3000
{:stack [:vault:prepare :k8s:pvc :k8s:deployment :k8s:service :k8s:httproute :k8s:tcproute]
:app-namespace "generic"
:app-name "gitea"
:k8s:deployment-opts {:spec {:template {:spec {:initContainers [
{:name "init-permissions"
:image "busybox:latest"
:command ["sh" "-c" "chown -R 1000:1000 /var/lib/gitea && chown -R 1000:1000 /etc/gitea"]
:volumeMounts [{:name "gitea-data" :mountPath "/var/lib/gitea"}
{:name "gitea-config" :mountPath "/etc/gitea"}]
:securityContext {:runAsUser 0 :runAsGroup 0}}
]
:containers [{:name 'app-name :image '(str repo "/" app-name ":latest-rootless")
:volumeMounts [{:name "gitea-data" :mountPath "/var/lib/gitea"}
{:name "gitea-config" :mountPath "/etc/gitea"}
{:name "timezone" :mountPath "/etc/timezone" :readOnly true}
{:name "localtime" :mountPath "/etc/localtime" :readOnly true}]}]
:volumes [{:name "gitea-data" :hostPath {:path "/opt/gitea/data" :type "DirectoryOrCreate"}}
{:name "gitea-config" :hostPath {:path "/opt/gitea/config" :type "DirectoryOrCreate"}}
{:name "timezone" :hostPath {:path "/etc/timezone" :type "File"}}
{:name "localtime" :hostPath {:path "/etc/localtime" :type "File"}}]}}}}
:k8s:httproute-opts {:spec {::hostnames ['host]}}})
:image-port 3000
:k8s:pvc-opts
{:metadata {:name "gitea-state"
:namespace "generic"}
:spec {:storageClassName "juicefs-sc"
:accessModes ["ReadWriteMany"]
:resources {:requests {:storage "1Ti"}}}}
:k8s:deployment-opts
{:spec
{:template
{:metadata {:annotations {"backup.velero.io/backup-volumes" "gitea-state"}}
:spec
{:containers
[{:name 'app-name
:image '(str repo "/" app-name ":latest-rootless")
:command ["/usr/local/bin/gitea"]
:args ["web"
"-c" "/var/lib/gitea/custom/conf/app.ini"]
:env [{:name "TZ" :value "America/Chicago"}]
:envFrom [{:secretRef {:name "gitea-secrets"}}]
:ports [{:name "ssh" :containerPort 2222}]
:volumeMounts [{:name "gitea-state" :mountPath "/var/lib/gitea"}]}]
:volumes
[{:name "gitea-state"
:persistentVolumeClaim {:claimName "gitea-state"}}]}}}}
:k8s:service-opts
{:spec
{:type "NodePort"
:selector {:app "gitea"}
:ports [{:name 'app-name :port 3000 :targetPort 3000}
{:name "ssh"
:port 22
:targetPort 2222
:nodePort 30022}]}}
:k8s:httproute-opts {:spec {::hostnames ['host]
:rules [{:matches [{:path {:type "PathPrefix"
:value "/"}}]
:backendRefs [{:name 'app-name
:port 3000}]}]}}})

View File

@@ -0,0 +1,34 @@
(ns k8s.services.homeassistant.service)
(def config
{:stack [:vault:prepare :k8s:pvc :k8s:deployment :k8s:service :k8s:httproute]
:image-port 8123
:app-namespace "home"
:app-name "homeassistant"
:k8s:pvc-opts
{"ha-config" {:storageClass "hcloud-volumes"
:accessModes ["ReadWriteOnce"]
:storage "10Gi"}}
:k8s:deployment-opts
{:spec
{:template
{:spec
{:containers
[{:name 'app-name
:image '(str repo "/home-assistant:stable")
:env [{:name "TZ" :value "America/Chicago"}]
:volumeMounts [{:name "config" :mountPath "/config"}]}]
:volumes
[{:name "config" :persistentVolumeClaim {:claimName "ha-config"}}]}}}}
:k8s:service-opts
{:spec {:selector {:app 'app-name}
:ports [{:name 'app-name :port 8123 :targetPort 8123}]}}
:k8s:httproute-opts
{:spec
{:hostnames ['host]
:rules [{:matches [{:path {:type "PathPrefix" :value "/"}}]
:backendRefs [{:name 'app-name :port 8123}]}]}}})

View File

@@ -1,12 +1,29 @@
(ns k8s.services.matrix.cinny.service)
(def config
{:stack [:vault-secrets :docker-image :deployment :service :ingress]
:image-port 80
{:stack [:vault:prepare
:harbor:robot-account
:docker:image
[:k8s :deployment :service :httproute]]
:app-namespace "matrix"
:app-name "cinny"
:image-opts {:build {:args {:FOUNDRY_USERNAME 'FOUNDRY_USERNAME
:FOUNDRY_PASSWORD 'FOUNDRY_PASSWORD}}
:imageName '(str repo "/" app-name ":latest")}
:deployment-opts {:spec {:template {:spec {:imagePullSecrets [{:name "harbor-creds-secrets"}]
:containers [{:name 'app-name :image '(str repo "/" app-name ":latest")}]}}}}})
:docker:image-opts {:context {:location "https://github.com/GigiaJ/cinny.git"}
:imageName '(str registry-base "/" registry-namespace "/" app-name ":latest")
:registry {:server '(str registry-base "/" registry-namespace)
:username '(-> :harbor:robot-account .-name)
:password '(-> :harbor:robot-account .-secret)}
:tags ['(str registry-base "/" registry-namespace "/" app-name)]
:push true}
:harbor:robot-account-opts {:name 'app-name
:permissions [{:kind "project"
:namespace 'registry-namespace
:access [{:action "pull" :resource "repository"}
{:action "push" :resource "repository"}
{:action "list" :resource "repository"}]}]}
:k8s:deployment-opts {:spec {:template {:spec {:imagePullSecrets [{:name "harbor-creds-secrets"}]
:containers [{:name 'app-name
:image '(str registry-base "/" registry-namespace "/" app-name ":latest")
:ports [{:containerPort 80}]}]}}}}
:k8s:httproute-opts {:spec {::hostnames ['host]}}})

View File

@@ -1,13 +0,0 @@
(ns k8s.services.matrix.database.service)
;; env_file:
;; - .env
;; volumes:
;; - ${PWD}/db-data/:/var/lib/postgresql/data/
(def config
{:stack [:deployment :service :ingress]
:image-port 80
:app-namespace "matrix"
:app-name "postgres"
:deployment-opts {:spec {:template {:spec {:containers [{:name 'app-name :image '(str repo "/" 'app-name ":latest")}]}}}}})

View File

@@ -1,14 +1,69 @@
;; volumes:
;; - ./personal/matrix/element-config.json:/app/config.json
;; environment:
;; ELEMENT_WEB_PORT: 3030
(ns k8s.services.matrix.element.service)
(def config
{:stack [:vault-secrets :docker-image :deployment :service :ingress]
:image-port 80
{:stack [:vault:prepare [:k8s :config-map :deployment :service :httproute]]
:image-port 80
:app-namespace "matrix"
:app-name "element"
:deployment-opts {:spec {:template {:spec {:imagePullSecrets [{:name "harbor-creds-secrets"}]
:containers [{:name 'app-name :image '(str repo "/" app-name ":latest")}]}}}}})
:app-name "element-web"
:k8s:config-map-opts {:data {"config.json"
'(stringify
{:default_server_name homeserver
:default_server_config
{:m.homeserver
{:base_url (str "https://" homeserver)}
:m.identity_server
{:base_url identity-server}}
:brand brand-name
:integrations_ui_url "https://scalar.vector.im/"
:integrations_rest_url "https://scalar.vector.im/api"
:integrations_widgets_urls
["https://scalar.vector.im/_matrix/integrations/v1"
"https://scalar.vector.im/api"
"https://scalar-staging.vector.im/_matrix/integrations/v1"
"https://scalar-staging.vector.im/api"
"https://scalar-staging.riot.im/scalar/api"]
:bug_report_endpoint_url "https://element.io/bugreports/submit"
:uisi_autorageshake_app "element-auto-uisi"
:show_labs_settings true
:room_directory
{:servers [homeserver]}
:enable_presence_by_hs_url
{"https://matrix.org" false
"https://matrix-client.matrix.org" false}
:terms_and_conditions_links
[{:url (str "https://" homeserver "/privacy")
:text "Privacy Policy"}
{:url (str "https://" homeserver "/cookie-policy")
:text "Cookie Policy"}]
:sentry
{:dsn "https://029a0eb289f942508ae0fb17935bd8c5@sentry.matrix.org/6"
:environment "develop"}
:posthog
{:project_api_key "phc_Jzsm6DTm6V2705zeU5dcNvQDlonOR68XvX2sh1sEOHO"
:api_host (str "https://posthog." homeserver)}
:privacy_policy_url (str "https://" homeserver "/cookie-policy")
:features
{:threadsActivityCentre true
:feature_video_rooms true
:feature_group_calls true
:feature_element_call_video_rooms true}
:setting_defaults
{:RustCrypto.staged_rollout_percent 100
:Registration.mobileRegistrationHelper true}
:element_call
{:url (str "https://livekit." homeserver)}
:map_style_url "https://api.maptiler.com/maps/streets/style.json?key=fU3vlMsMn4Jb6dnEIFsx"})}}
:k8s:deployment-opts {:spec
{:template
{:spec
{:volumes [{:name "config-vol"
:configMap {:name 'app-name}}]
:containers [{:name 'app-name :image '(str repo "/" app-name ":latest")
:env [{:name "ELEMENT_WEB_PORT" :value "80"}]
:volumeMounts [{:name "config-vol"
:mountPath "/app/config.json"
:subPath "config.json"}]}]}}}}
:k8s:httproute-opts {:spec {::hostnames ['host]}}})

View File

@@ -0,0 +1,22 @@
(ns k8s.services.matrix.element-call.livekit-jwt.service)
(def config
{:stack [:vault:prepare [:k8s :deployment :service :httproute]]
:image-port 8080
:app-namespace "matrix"
:app-name "livekit-jwt"
:k8s:deployment-opts {:spec
{:template
{:spec
{:containers [{:name 'app-name :image '(str repo "/" "lk-jwt-service" ":latest")
:env [{:name "LIVEKIT_KEY" :value 'key-name}
{:name "LIVEKIT_SECRET" :value 'dev-key}
{:name "LIVEKIT_JWT_PORT" :value "8080"}
{:name "LIVEKIT_URL" :value 'livekit-url}]}]}}}}
:k8s:httproute-opts
{:spec
{:hostnames ['host]
:rules [{:matches [{:path {:type "PathPrefix" :value "/livekit/jwt"}}]
:backendRefs [{:name 'app-name :port 80}]}
{:matches [{:path {:type "PathPrefix" :value "/sfu/get"}}]
:backendRefs [{:name 'app-name :port 80}]}]}}})

View File

@@ -0,0 +1,76 @@
(ns k8s.services.matrix.element-call.livekit-server.service)
(defn generate-all-ports [tcp-port start-udp end-udp]
(concat
[{:name "http"
:port tcp-port
:targetPort tcp-port
:containerPort tcp-port
:protocol "TCP"}]
(map (fn [p]
{:name (str "udp-" p)
:port p
:targetPort p
:nodePort p
:containerPort p
:protocol "UDP"})
(range start-udp (inc end-udp)))))
(def all-ports (generate-all-ports 7880 31000 31100))
(def config
{:stack [:vault:prepare [:k8s :config-map :deployment :service :httproute]]
:image-port nil
:app-namespace "matrix"
:app-name "livekit-server"
:k8s:config-map-opts
{:metadata {:name "livekit-config"}
:data {"livekit.yaml"
'(stringify
{:port 7880
:bind_addresses ["0.0.0.0"]
:rtc {:tcp_port 7881
:port_range_start 31000
:port_range_end 31100
:use_external_ip true} ;; Required for Hetzner Public IP discovery
:logging {:level "debug"}
:turn {:enabled false
:udp_port 443
:tls_port 5349}
:keys {:devkey dev-key}})}}
:k8s:deployment-opts
{:spec
{:template
{:spec
{:volumes [{:name "config-vol" :configMap {:name "livekit-config"}}]
:containers [{:name 'app-name
:image '(str repo "/" app-name ":latest")
:command ["/livekit-server"]
:args ["--config" "/etc/livekit.yaml"]
:ports (map #(select-keys % [:name :containerPort :protocol])
all-ports)
:volumeMounts [{:name "config-vol"
:mountPath "/etc/livekit.yaml"
:subPath "livekit.yaml"}]}]}}}}
:k8s:service-opts
{:spec {:type "NodePort"
:selector {:app 'app-name}
:ports (map #(select-keys % [:name :port :targetPort :nodePort :protocol])
all-ports)}}
:k8s:httproute-opts
{:spec
{:hostnames ['host]
:rules [{:matches [{:path {:type "PathPrefix" :value "/livekit/sfu"}}]
:filters [{:type "URLRewrite"
:urlRewrite {:path {:type "ReplacePrefixMatch"
:replacePrefixMatch "/"}}}]
:backendRefs [{:name 'app-name :port 7880}]}]}}})

View File

@@ -1,18 +1,26 @@
(ns k8s.services.matrix.element-call.service)
;; volumes:
;; - ./personal/matrix/elementcall/config.json:/app/config.json
(def config
{:stack [:vault-secrets :deployment :service :ingress]
{:stack [:vault:prepare [:k8s :config-map :deployment :service :httproute]]
:image-port 80
:app-namespace "matrix"
:app-name "element-call"
:deployment-opts {:spec {:template {:spec {:containers [{:name 'app-name :image '(str repo "/" app-name ":sha-1702b15")
:volumeMounts [{:name "data" :mountPath "/data"}]}]
:initContainers [{:name "init-permissions"
:image "busybox:latest"
:command ["sh" "-c" "chown -R 1000:1000 /data"]
:volumeMounts [{:name "data" :mountPath "/data"}]
:securityContext {:runAsUser 0 :runAsGroup 0}}]
:volumes [{:name "data" :hostPath {:path "/opt/mmr/data" :type "DirectoryOrCreate"}}]}}}}})
:k8s:config-map-opts {:data {"config.json"
'(stringify
{:default_server_config
{:m.homeserver
{:base_url (str "https://" homeserver)
:server_name homeserver}}
:features
{:feature_use_device_session_member_events true}
:ssla "https://static.element.io/legal/element-software-and-services-license-agreement-uk-1.pdf"})}}
:k8s:deployment-opts {:spec
{:template
{:spec
{:volumes [{:name "config-vol"
:configMap {:name 'app-name}}]
:containers [{:name 'app-name :image '(str repo "/" app-name ":latest")
:volumeMounts [{:name "config-vol"
:mountPath "/app/config.json"
:subPath "config.json"}]}]}}}}
:k8s:httproute-opts {:spec {::hostnames ['host]}}})

View File

@@ -1,10 +1,53 @@
;; homeserver:
;; volumes:
;; - db:/var/lib/conduwuit
(def config
{:stack [:vault-secrets :docker-image :deployment :service :ingress]
:image-port 80
(ns k8s.services.matrix.home-server.service)
(def config
{:stack [:vault:prepare [:k8s :pvc :deployment :service :httproute]]
:app-namespace "matrix"
:app-name "tuwunel"
:deployment-opts {:spec {:template {:spec {:containers [{:name 'app-name :image '(str repo "/" 'app-name ":latest")}]}}}}})
:k8s:pvc-opts
{:metadata {:name "conduwuit-db"
:namespace "matrix"}
:spec {:storageClassName "hcloud-volumes"
:accessModes ["ReadWriteOnce"]
:resources {:requests {:storage "50Gi"}}}}
:k8s:deployment-opts
{:spec
{:strategy {:type "Recreate"}
:template
{:metadata {:annotations {"backup.velero.io/backup-volumes" "db"}}
:spec
{:containers
[{:name 'app-name
:image '(str repo "/tuwunel:latest")
:envFrom [{:secretRef {:name '(str app-name "-secrets")}}]
:ports [{:containerPort 'port}]
:volumeMounts [{:name "db" :mountPath "/var/lib/conduwuit"}
#_{:name "discord-reg"
:mountPath "/etc/conduwuit/discord-registration.yaml"
:subPath "registration.yaml"}]}]
:volumes
[{:name "db" :persistentVolumeClaim {:claimName "conduwuit-db"}}
#_{:name "discord-reg" :configMap {:name "discord-bridge-config"}}
]}}}}
:k8s:service-opts
{:spec {:ports [{:name 'app-name :port 'port :targetPort 'port}]}}
:k8s:httproute-opts
{:spec
{:hostnames ['host]
:rules [{:matches [{:path {:type "PathPrefix" :value "/_matrix/media"}}]
:backendRefs [{:name "matrix-media-repo" :port 80}]}
{:matches [{:path {:type "PathPrefix" :value "/_matrix/client/v1/media"}}]
:backendRefs [{:name "matrix-media-repo" :port 80}]}
{:matches [{:path {:type "PathPrefix" :value "/.well-known/matrix"}}]
:backendRefs [{:name "matrix-well-known" :port 80}]}
{:matches [{:path {:type "PathPrefix" :value "/"}}]
:backendRefs [{:name 'app-name :port 'port}]}]}}})

View File

@@ -0,0 +1,27 @@
(ns k8s.services.matrix.home-server.well-known.service)
(def config
{:stack [:vault:prepare :k8s:config-map :k8s:deployment :k8s:service]
:app-namespace "matrix"
:app-name "matrix-well-known"
:k8s:config-map-opts
{:metadata {:name "well-known-json"}
:data {"server" "{\"m.server\": \"hampter.quest:443\"}"
"client" '(stringify
{:m.homeserver {:base_url (str "https://" homeserver)}
:org.matrix.msc4143.rtc_foci [{:type "livekit"
:livekit_service_url livekit-url}]})}}
:k8s:deployment-opts
{:spec
{:template
{:spec
{:containers
[{:name 'app-name
:ports [{:containerPort 80}]
:image '(str repo "/nginx:alpine")
:volumeMounts [{:name "config" :mountPath "/usr/share/nginx/html/.well-known/matrix"}]}]
:volumes [{:name "config" :configMap {:name "well-known-json"}}]}}}}
:k8s:service-opts
{:spec {:ports [{:name 'app-name :port 80 :targetPort 80}]}}})

View File

@@ -1,8 +0,0 @@
(ns k8s.services.matrix.livekit-jwt.service)
(def config
{:stack [:vault-secrets :docker-image :deployment :service :ingress]
:image-port 80
:app-namespace "matrix"
:app-name "livekit-jwt"
:deployment-opts {:spec {:template {:spec {:containers [{:name 'app-name :image '(str repo "/" lk-jwt-service ":0.2.3")}]}}}}})

View File

@@ -1,16 +0,0 @@
;; livekit:
;; command: --config /etc/livekit.yaml
;; - ./personal/matrix/elementcall/livekit.yaml:/etc/livekit.yaml
;; ports:
;; - 50100-50200:50100-50200/udp
(ns k8s.services.matrix.livekit-server.service)
(def config
{:stack [:vault-secrets :docker-image :deployment :service :ingress]
:image-port 80
:app-namespace "matrix"
:app-name "livekit-server"
:deployment-opts {:spec {:template {:spec {:containers [{:name 'app-name :image '(str repo "/" 'app-name ":latest")}]}}}}})

View File

@@ -0,0 +1,37 @@
(ns k8s.services.matrix.mautrix-discord.database.service)
(def config
{:stack [:vault:prepare :k8s:pvc :k8s:deployment :k8s:service]
:app-namespace "matrix"
:app-name "mautrix-discord-db"
:k8s:pvc-opts
{:metadata {:name "mautrix-discord-pg-data"
:namespace "matrix"}
:spec {:storageClassName "hcloud-volumes"
:accessModes ["ReadWriteOnce"]
:resources {:requests {:storage "10Gi"}}}}
:k8s:deployment-opts
{:spec
{:template
{:metadata
{:annotations
{"backup.velero.io/backup-volumes" "db"}}
:spec
{:containers
[{:name 'app-name
:image "postgres:14-alpine"
:ports [{:containerPort 5432}]
:env [{:name "PGDATA" :value "/var/lib/postgresql/data/pgdata"}
{:name "POSTGRES_USER" :value 'username}
{:name "POSTGRES_PASSWORD" :value 'password}
{:name "POSTGRES_DB" :value 'db-name}]
:volumeMounts [{:name "db" :mountPath "/var/lib/postgresql/data"}]}]
:volumes
[{:name "db" :persistentVolumeClaim {:claimName "mautrix-discord-pg-data"}}]}}}}
:k8s:service-opts
{:spec {:selector {:app 'app-name}
:ports [{:name 'app-name :port 5432 :targetPort 5432}]}}})

View File

@@ -1,10 +1,78 @@
;; - ./personal/matrix/discord/data:/data
(ns k8s.services.matrix.mautrix-discord.service)
(def config
{:stack [:vault-secrets :docker-image :deployment :service :ingress]
:image-port 80
{:stack [:vault:prepare :k8s:pvc :k8s:config-map :k8s:deployment :k8s:service]
:app-namespace "matrix"
:app-name "mautrix-discord"
:deployment-opts {:spec {:template {:spec {:containers [{:name 'app-name :image '(str repo "/" "discord" ":4927a73ce7411f3970803d35c22f0c8c96dc2d7e-amd64")}]}}}}})
:k8s:config-map-opts
{:metadata {:name "discord-bridge-config"}
:data {"config.yaml" '(stringify
{:homeserver {:address (str "https://" homeserver)
:domain homeserver}
:appservice {:port port
:address (str "http://mautrix-discord:" port)
:hostname "0.0.0.0"
:database {:type "postgres"
:uri db-login-url
:max_open_conns 20
:max_idle_cons 2}
:id "discord"
:as_token as-token
:hs_token hs-token
:ephemeral_events true
:bot {:username "discordbot"
:displayname "Discord bridge bot"}}
:bridge {:permissions (parse permissions)
;;:login_shared_secret_map (parse login-shared-secret-map)
;;:double_puppet_server_map (parse double-puppet-server-map)
:use_discord_cdn_upload true
:command_prefix "!discord"
:encryption {:allow false
:default false}}})
"registration.yaml" '(stringify {:id "discord"
:url (str "http://mautrix-discord:" port)
:as_token as-token
:hs_token hs-token
:sender_localpart sender-localpart
:rate_limited false
:namespaces {:users [{:regex user1-regex
:exclusive true}
{:regex user2-regex
:exclusive true}]}
:de.sorunome.msc2409.push_ephemeral true
:push_ephemeral true})}}
:k8s:pvc-opts
{:metadata {:name "discord-bridge-data"
:namespace "matrix"}
:spec {:storageClassName "juicefs-sc"
:accessModes ["ReadWriteMany"]
:resources {:requests {:storage "1Gi"}}}}
:k8s:deployment-opts
{:spec
{:template
{:spec
{:initContainers
[{:name "config-loader"
:image "busybox:latest"
:command ["sh" "-c" "cp -f /config_source/* /data/"]
:volumeMounts [{:name "data" :mountPath "/data"}
{:name "config" :mountPath "/config_source"}]}]
:containers
[{:name 'app-name
:image '(str repo "/discord:latest")
:args ["/usr/bin/mautrix-discord" "-c" "/data/config.yaml" "-r" "/data/registration.yaml"]
:ports [{:containerPort 'port}]
:volumeMounts [{:name "data" :mountPath "/data"}
#_{:name "config" :mountPath "/data/config.yaml" :subPath "config.yaml"}
#_{:name "config" :mountPath "/data/registration.yaml" :subPath "registration.yaml"}]}]
:volumes
[{:name "data" :persistentVolumeClaim {:claimName "discord-bridge-data"}}
{:name "config" :configMap {:name "discord-bridge-config"}}]}}}}
:k8s:service-opts
{:spec {:selector {:app 'app-name}
:ports [{:name 'app-name :port 'port :targetPort 'port}]}}})

View File

@@ -0,0 +1,37 @@
(ns k8s.services.matrix.mmr.database.service)
(def config
{:stack [:vault:prepare :k8s:pvc :k8s:deployment :k8s:service]
:app-namespace "matrix"
:app-name "mmr-db"
:k8s:pvc-opts
{:metadata {:name "mmr-pg-data"
:namespace "matrix"}
:spec {:storageClassName "hcloud-volumes"
:accessModes ["ReadWriteOnce"]
:resources {:requests {:storage "10Gi"}}}}
:k8s:deployment-opts
{:spec
{:template
{:metadata
{:annotations
{"backup.velero.io/backup-volumes" "db"}}
:spec
{:containers
[{:name 'app-name
:image "postgres:14-alpine"
:ports [{:containerPort 5432}]
:env [{:name "PGDATA" :value "/var/lib/postgresql/data/pgdata"}
{:name "POSTGRES_USER" :value 'username}
{:name "POSTGRES_PASSWORD" :value 'password}
{:name "POSTGRES_DB" :value 'db-name}]
:volumeMounts [{:name "db" :mountPath "/var/lib/postgresql/data"}]}]
:volumes
[{:name "db" :persistentVolumeClaim {:claimName "mmr-pg-data"}}]}}}}
:k8s:service-opts
{:spec {:selector {:app 'app-name}
:ports [{:name 'app-name :port 5432 :targetPort 5432}]}}})

View File

@@ -2,20 +2,57 @@
(ns k8s.services.matrix.mmr.service)
(def config
{:stack [:vault-secrets :deployment :service :ingress]
{:stack [:vault:prepare [:k8s :config-map :deployment :service]]
:image-port 80
:app-namespace "matrix"
:app-name "matrix-media-repo"
:deployment-opts {:spec {:template {:spec {:containers [{:name 'app-name :image '(str repo "/" app-name ":v1.3.8")
:volumeMounts [{:name "data" :mountPath "/data"}]}]
:initContainers [{:name "init-permissions"
:image "busybox:latest"
:command ["sh" "-c" "chown -R 1000:1000 /data"]
:volumeMounts [{:name "data" :mountPath "/data"}]
:securityContext {:runAsUser 0 :runAsGroup 0}}]
:volumes [{:name "data" :hostPath {:path "/opt/mmr/data" :type "DirectoryOrCreate"}}]}}}}})
:k8s:config-map-opts
{:metadata {:name "mmr-config"}
:data {"media-repo.yaml"
'(stringify
{:repo {:port port
:bindAddress "0.0.0.0"
:logLevel "debug"}
:database {:postgres db-login-url}
:homeservers [{:name homeserver
:csApi (str "https://" homeserver)}]
:accessTokens {:appservices [{:id "discord"
:asToken discord-app-service-token
:senderUserId discord-send-user-id
:userNamespaces [{:regex user-namespace-regex}]}]}
:admins [admin]
:datastores [{:type "s3"
:id s3-id
:forKinds ["all"]
:opts {:tempPath "/tmp/media-repo"
:endpoint s3-endpoint
:accessKeyId s3-access-key
:accessSecret s3-secret-key
:ssl true
:bucketName s3-bucket-name
:region s3-region}}]
:rateLimit {:enabled false}})}}
:k8s:deployment-opts
{:spec
{:template
{:spec
{:containers
[{:name 'app-name
:image '(str repo "/" app-name ":v1.3.8")
:command ["/usr/local/bin/media_repo"]
:args ["-config" "/data/media-repo.yaml"]
:volumeMounts [{:name "config-vol"
:mountPath "/data/media-repo.yaml"
:subPath "media-repo.yaml"}
{:name "temp-vol"
:mountPath "/tmp/media-repo"}]}]
:volumes
[{:name "config-vol" :configMap {:name "mmr-config"}}
{:name "temp-vol" :emptyDir {}}]}}}}
})
;;
;; - ./personal/matrix/mmr:/data

View File

@@ -1,14 +1,67 @@
(ns k8s.services.matrix.turn.service)
;; - ./personal/matrix/coturn.conf:/etc/coturn/turnserver.conf
(defn generate-all-ports [start-relay end-relay]
(concat
[{:name "signaling-udp" :port 3478 :targetPort 3478 :nodePort 30478 :containerPort 3478 :protocol "UDP"}
{:name "signaling-tcp" :port 3478 :targetPort 3478 :nodePort 30478 :containerPort 3478 :protocol "TCP"}
{:name "tls-udp" :port 5349 :targetPort 5349 :nodePort 30549 :containerPort 5349 :protocol "UDP"}
{:name "tls-tcp" :port 5349 :targetPort 5349 :nodePort 30549 :containerPort 5349 :protocol "TCP"}]
(map (fn [p]
{:name (str "relay-" p)
:port p
:targetPort p
:nodePort p
:containerPort p
:protocol "UDP"})
(range start-relay (inc end-relay)))))
(def all-ports (generate-all-ports 32000 32050))
(def config
{:stack [:vault-secrets :docker-image :deployment :service :ingress]
:image-port 80
{:stack [:vault:prepare [:k8s :config-map :deployment :service]]
:image-port nil
:app-namespace "matrix"
:app-name "coturn"
:image-opts {:build {:args {:FOUNDRY_USERNAME 'FOUNDRY_USERNAME
:FOUNDRY_PASSWORD 'FOUNDRY_PASSWORD}}
:imageName '(str repo "/" app-name ":latest")}
:deployment-opts {:spec {:template {:spec {:imagePullSecrets [{:name "harbor-creds-secrets"}]
:containers [{:name 'app-name :image '(str repo "/" app-name ":latest")}]}}}}})
:k8s:config-map-opts
{:metadata {:name "coturn-config"}
:data {"turnserver.conf"
'(str
"listening-port=3478\n"
"tls-listening-port=5349\n"
"min-port=32000\n"
"max-port=32050\n"
(str "external-ip=" public-ip "\n")
(str "realm" homeserver "\n")
(str "server-name=" host "\n")
"log-file=stdout\n"
"use-auth-secret\n"
(str "static-auth-secret=" secret-auth "\n")
"fingerprint\n"
"lt-cred-mech\n")}}
:k8s:deployment-opts
{:spec
{:template
{:spec
{:volumes [{:name "config" :configMap {:name "coturn-config"}}]
:containers [{:name 'app-name
:image "coturn/coturn:latest"
:ports (map #(select-keys % [:name :containerPort :protocol])
all-ports)
:volumeMounts [{:name "config"
:mountPath "/etc/coturn/turnserver.conf"
:subPath "turnserver.conf"}]}]}}}}
:k8s:service-opts
{:spec {:type "NodePort"
:selector {:app 'app-name}
:ports (map #(select-keys % [:name :port :targetPort :nodePort :protocol])
all-ports)}}})

View File

@@ -8,7 +8,7 @@
{:stack [:vault:prepare
:harbor:robot-account
:docker:image
[:k8s :namespace :deployment :service :httproute]]
[:k8s :deployment :service :httproute]]
:app-name "mesite"
:app-namespace "generic"
:docker:image-opts {:context {:location "https://codeberg.org/Gigia/mesite.git"}

View File

@@ -0,0 +1,40 @@
(ns k8s.services.nextcloud.database.service)
(def config
{:stack [:vault:prepare :k8s:pvc :k8s:deployment :k8s:service]
:app-namespace "nextcloud"
:app-name "nextcloud-db"
:k8s:pvc-opts
{:metadata {:name "nextcloud-mariadb-disk"
:namespace "nextcloud"}
:spec {:storageClassName "hcloud-volumes"
:accessModes ["ReadWriteOnce"]
:resources {:requests {:storage "10Gi"}}}}
:k8s:deployment-opts
{:spec
{:template
{:metadata
{:annotations {"backup.velero.io/backup-volumes" "db"}}
:spec
{:containers
[{:name 'app-name
:image "mariadb:10.6"
:ports [{:containerPort 3306}]
:env [{:name "MYSQL_ROOT_PASSWORD" :value 'mariadb-root-password}
{:name "MYSQL_DATABASE" :value "nextcloud"}
{:name "MYSQL_USER" :value 'username}
{:name "MYSQL_PASSWORD" :value 'mariadb-password}]
:volumeMounts [{:name "db" :mountPath "/var/lib/mysql"}]}]
:volumes
[{:name "db" :persistentVolumeClaim {:claimName "nextcloud-mariadb-disk"}}]}}}}
:k8s:service-opts
{:spec {:selector {:app 'app-name}
:ports [{:name 'app-name :port 3306 :targetPort 3306}]}}})

View File

@@ -1,17 +1,61 @@
(ns k8s.services.nextcloud.service)
(def config
{:stack [:vault-secrets :chart :ingress]
{:stack [:vault:prepare [:k8s :httproute :chart]]
:app-namespace "nextcloud"
:app-name "nextcloud"
:image-port 8080
:image-port 80
:vault-load-yaml true
:chart-opts {:repositoryOpts {:repo "https://nextcloud.github.io/helm/"}
:values {:nextcloud {:host 'host
:trustedDomains ['host 'app-name]}}
:transformations (fn [args _opts]
(let [kind (get-in args [:resource :kind])]
(if (some #{kind} ["StatefulSet" "PersistentVolumeClaim" "Ingress"])
(update-in args [:resource :metadata :annotations]
#(assoc (or % {}) "pulumi.com/skipAwait" "true"))
args)))}})
:k8s:chart-opts {:repositoryOpts {:repo "https://nextcloud.github.io/helm/"}
:values
{:podAnnotations {"backup.velero.io/backup-volumes" "data"}
:trustedDomains ['host 'app-name]
:nextcloud {:username 'username
:password 'password
:host 'host
:containerPort 80
:persistence {:enabled true
:storageClass "juicefs-sc"
:accessMode "ReadWriteMany"
:size "1Ti"}}
:service {:port 80}
:redis {:auth {:password 'redis-password}}
:externalDatabase {:enabled true
:type "mysql"
:host "nextcloud-db.nextcloud.svc.cluster.local"
:database "nextcloud"
:user 'username
:password 'mariadb-password}
:internalDatabase {:enabled false}
:mariadb {:enabled false
:auth {:username 'username
:password 'mariadb-password
:rootPassword 'mariadb-root-password}
:architecture "standalone"
:primary {:podAnnotations {"backup.velero.io/backup-volumes" "data"}
:persistence {:enabled true
:storageClass "hcloud-volumes"
:size "8Gi"}}
;; Obligatory what the fuck Broadcom, why are you like this. RIP Bitnami
:volumePermissions {:enabled true
:image {:registry "docker.io"
:repository "bitnami/os-shell"
:tag "latest"
:pullPolicy "Always"}}}
:transformations (fn [args _opts]
(let [kind (get-in args [:resource :kind])]
(if (some #{kind} ["StatefulSet" "PersistentVolumeClaim" "Ingress"])
(update-in args [:resource :metadata :annotations]
#(assoc (or % {}) "pulumi.com/skipAwait" "true"))
args)))}}
:k8s:httproute-opts {:spec {::hostnames ['host]
:rules [{:matches [{:path {:type "PathPrefix" :value "/"}}]
:filters [{:type "ResponseHeaderModifier"
:responseHeaderModifier
{:set [{:name "Content-Security-Policy"
:value "frame-src 'self' https://cinny.hampter.quest https://productive.chickensalad.quest https://gitea.chickensalad.quest;"}]
:remove ["X-Content-Security-Policy"]}}]
:backendRefs [{:name "nextcloud"
:port 80}]}]}}})

View File

@@ -1,12 +1,10 @@
(ns k8s.services.prometheus.service)
(def config
{:stack [:vault-secrets :chart]
{:stack [:vault:prepare :k8s:chart]
:app-namespace "prometheus"
:app-name "prometheus"
:image-port 8080
:vault-load-yaml true
:chart-opts {:chart "kube-prometheus-stack"
:k8s:chart-opts {:chart "kube-prometheus-stack"
:repositoryOpts {:repo "https://prometheus-community.github.io/helm-charts"}
:namespace "monitoring"
:values {:grafana {:adminPassword 'password

View File

@@ -0,0 +1,55 @@
(ns k8s.services.velero.service)
(def config
{:stack [:vault:prepare :k8s:secret :k8s:chart]
:app-namespace "velero"
:app-name "velero"
:k8s:secret-opts
{:metadata {:name "velero-s3-creds"}
:stringData {"cloud" '(str "[default]\n"
"aws_access_key_id = " s3-access-key "\n"
"aws_secret_access_key = " s3-secret-key)}}
:k8s:chart-opts
{:repositoryOpts {:repo 'repo}
:chart "velero"
:version "5.1.0"
:values
{:deployNodeAgent true
:configuration
{:backupStorageLocation
[{:name "default"
:provider "aws"
:bucket 's3-bucket-name
:config {:region 's3-region
:s3ForcePathStyle true
:s3Url 's3-url}}]
:volumeSnapshotLocation
[{:name "default"
:provider "aws"
:config {:region 's3-region}}]}
:credentials {:useSecret true
:existingSecret "velero-s3-creds"}
:initContainers
[{:name "velero-plugin-for-aws"
:image "velero/velero-plugin-for-aws:v1.8.0"
:volumeMounts [{:mountPath "/target" :name "plugins"}]}]
:defaultVolumesToFsBackup true
:nodeAgent {:resources {:requests {:cpu "50m" :memory "64Mi"}
:limits {:cpu "1000m" :memory "1Gi"}}}
:schedules
{:daily-backup
{:disabled false
:schedule "0 4 * * *"
:template {:ttl "720h"
:includedNamespaces ["matrix" "generic" "home" "nextcloud"]}}}}}})

View File

@@ -5,22 +5,37 @@
[k8s.add-ons.csi-driver.hetzner :as hetzner-csi]
[infra.dns :as dns]
[k8s.preparers.harbor :as harbor-prepare]
[k8s.add-ons.gateway.traefik :as traefik]
[k8s.add-ons.cert-manager :as cert-manager]
[k8s.add-ons.crd.cert-manager :as cert-manager-crd]
[k8s.add-ons.crd.gateway-api :as gateway-api-crd]
[k8s.add-ons.crd.traefik :as traefik-crds]
[k8s.add-ons.csi-driver.juicefs :as juicefs-csi]
[k8s.add-ons.csi-driver.wasabi :as wasabi-csi]
[k8s.add-ons.csi-driver.extra.redis :as redis-juicefs]
[k8s.add-ons.image-registry.harbor :as harbor]
[k8s.add-ons.secret-replicator :as secret-replicator]
[k8s.add-ons.proxy :as proxy]
[k8s.services.nextcloud.service :as nextcloud-service]
[k8s.services.nextcloud.database.service :as nextcloud-db-service]
[k8s.services.mesite.service :as mesite-service]
[k8s.services.gitea.service :as gitea-service]
[k8s.services.act-runner.service :as act-runner-service]
[k8s.services.foundryvtt.service :as foundryvtt-service]
[k8s.services.productive.service :as productive-service]))
[k8s.services.foundryvtt.service-2 :as girls-foundry-service]
[k8s.services.productive.service :as productive-service]
[k8s.services.velero.service :as velero-service]
[k8s.services.matrix.cinny.service :as cinny-service]
[k8s.services.matrix.element-call.service :as element-call-service]
[k8s.services.matrix.element.service :as element-service]
[k8s.services.matrix.element-call.livekit-server.service :as livekit-server-service]
[k8s.services.matrix.element-call.livekit-jwt.service :as livekit-jwt-service]
[k8s.services.matrix.mmr.service :as mmr-service]
[k8s.services.matrix.mmr.database.service :as mmr-db-service]
[k8s.services.matrix.mautrix-discord.database.service :as mautrix-discord-db-service]
[k8s.services.matrix.mautrix-discord.service :as mautrix-discord-service]
[k8s.services.matrix.home-server.well-known.service :as matrix-well-known-service]
[k8s.services.matrix.home-server.service :as homeserver-service]))
(defn general-provider-output-refs []
{:vault {:stack :init
@@ -51,13 +66,15 @@
(def shared-resources-definition
(create-resource-definition
[dns/config
cert-manager-crd/config
[cert-manager-crd/config
gateway-api-crd/config
traefik-crds/config
dns/config
wasabi-csi/config proxy/config secret-replicator/config
redis-juicefs/config
juicefs-csi/config
cert-manager/config
traefik/config
wasabi-csi/config proxy/config secret-replicator/config
harbor/config
]
["base" "init"]
@@ -72,9 +89,33 @@
(def deployment-resources-definition
(create-resource-definition
[#_nextcloud-service/config foundryvtt-service/config mesite-service/config productive-service/config gitea-service/config act-runner-service/config]
[girls-foundry-service/config foundryvtt-service/config
mesite-service/config productive-service/config
nextcloud-db-service/config
nextcloud-service/config
velero-service/config
gitea-service/config
;;act-runner-service/config
]
["base" "init" "shared"]
(general-provider-output-refs)))
(def deployment-matrix-service-registry [])
(def matrix-resources-definition
(create-resource-definition
[cinny-service/config
element-call-service/config
element-service/config
livekit-server-service/config
livekit-jwt-service/config
mmr-db-service/config
mmr-service/config
mautrix-discord-db-service/config
mautrix-discord-service/config
matrix-well-known-service/config
homeserver-service/config
]
["base" "init" "shared"]
(general-provider-output-refs)))