Compare commits

...

72 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
d573843361 Add secondary foundry instance 2025-11-29 03:59:19 -06:00
3848712b0e Update SHA for lib 2025-11-26 19:02:48 -06:00
efeb5d928a Swap to v4 impl 2025-11-26 18:59:41 -06:00
02ba585356 Fix Traefik deployment 2025-11-26 18:59:22 -06:00
73c23feefb Add CRDs 2025-11-26 18:57:36 -06:00
7813e9de91 Add CRDs 2025-11-26 18:57:27 -06:00
cbb1dc5c6b Swap to v4 impl 2025-11-26 18:57:02 -06:00
e5c958d565 Swap to v4 impl 2025-11-26 18:56:10 -06:00
7eb3a89d6c Swap to v4 impl 2025-11-26 18:56:02 -06:00
63e8f1b9ee Swap to v4 impl 2025-11-26 18:55:56 -06:00
2320ed477f Swap to v4 impl 2025-11-26 18:55:50 -06:00
49b1c689b4 Swap to v4 impl 2025-11-26 18:55:44 -06:00
a228662447 Swap to v4 impl 2025-11-26 18:55:38 -06:00
aa12880d49 Swap to v4 impl 2025-11-26 18:55:20 -06:00
29c2910631 Swap to v4 impl 2025-11-26 18:55:13 -06:00
bdddf88a0b Add CRDs 2025-11-26 18:54:53 -06:00
c9d305264d Swap to using local for a bit 2025-11-26 18:54:26 -06:00
4360b43e12 Add note 2025-11-26 18:53:10 -06:00
82f874e834 Update README to move future changes into the library repo README 2025-11-26 18:52:24 -06:00
45 changed files with 1130 additions and 294 deletions

138
README.md
View File

@@ -3,119 +3,21 @@ My cluster configuration that serves to automate the deployment and handling of
I'll try to include any pertinent documentation here in the tooling I use or the setup.
#### This uses a very much alpha build of my pulumi-cljs library
#### Upcoming
Break this into three repos. IaC, the Pulumi CLJS library, and my dot files. We'll also be moving data from our old instances to the new IaC managed cluster. c:
Current roadmap for that is breaking apart the Vault provider into its actual core components as it is currently an anti-pattern in the way it combines multiple provider functionalities through it. It relying on the config file even is a bit of an issue.
Furthermore, we are unable to effectively destructure secrets in the execute function in the current design. However, since we'd want to change to remove the anti-pattern mentioned above, we'd ideally actually just reference secrets through the vault resource output from the given resource config's stack execution.
Currently only want to expand on making the final service declarations functional.
I'll be revising the library to better incorporate changes I'd like to see and I'd like to make the core cleaned up further.
In the more immediate that'd be:
- Simplifying the declarations
- Pulling out the library functions
- Cleaning up how re-used configs are appended to
get-provider-outputs-config inside utils.providers.cljs currently runs under the expectation that shared stack already exists... which inherently is flawed on an initial run. Will need to revise a little. Similarly get-stack-refs works on the same flawed principle.
Maybe we can move them to stack definitions (which currently exist in base.cljs). I think in an ideal design we could actually inherently scope the entire thing out. I'm inspired by how Guix allows system definitions to be written, and there isn't anything stopping a large block for a stack being like:
```
(def some-stack
{:stack-registry
[{:stack [:k8s:secret :k8s:chart]
:app-namespace "kube-system"
:app-name "hcloud-csi"
:vault-load-yaml false
:k8s:secret-opts {:metadata {:name "hcloud"
:namespace "kube-system"}
:stringData {:token (-> cfg :hcloudToken)}}
:k8s:chart-opts {:fetchOpts {:repo "https://charts.hetzner.cloud"}
:values {:controller {:enabled false
:existingSecret {:name "hcloud-csi-secret"}
:node {:existingSecret {:name "hcloud-csi-secret"}}}}}}
{:stack [:vault:prepare :docker:image :k8s:secret :k8s:chart]
:app-namespace "caddy-system"
:app-name "caddy-ingress-controller"
:k8s:image-port 8080
:k8s:vault-load-yaml false
:k8s:image-opts {:imageName '(str repo "/" app-name ":latest")}
:docker:image-opts {:registry {:server (-> cfg :public-image-registry-url)
:username (-> cfg :public-image-registry-username)
:password (-> cfg :public-image-registry-password)}
:tags [(str (-> cfg :public-image-registry-url) "/" (-> cfg :public-image-registry-username) "/" "caddy")]
:push true}
:k8s:chart-opts {:fetchOpts {:repo "https://caddyserver.github.io/ingress"}
:values
{:ingressController
{:deployment {:kind "DaemonSet"}
:daemonSet {:useHostPort true}
:ports {:web {:hostPort 80}
:websecure {:hostPort 443}}
:service {:type "NodePort"
:externalTrafficPolicy "Local"}
:image {:repository 'repo
:tag "latest"}
:config {:email 'email}}}}}
]
:stack-references { :init (new pulumi/StackReference "init")
:shared (new pulumi/StackReference "shared")}
:provider-configs {:harbor {:stack :shared
:outputs ["username" "password" "url"]}}
})
```
and that effectively defines an entire stack and is executable on (with the option to scope out to files to reduce the sheer verbosity in a single)
In that regard, I think we've made decent headway in achieving a similar design and behavior where a config should provide reproducible results.
Due to the nature of npm packages, it is a bit hard to *lock* to certain package versions as easily.
Eventually the user will have more programmatic choice of execution too so as to have a program that ingests the library first and applies their stack defaults to it.
The only limitation there would be that it does limit multi-cloud designs perhaps. Though for those, the unconsumed library would still be very much a practical option.
DNS should be swapped with a Cloudflare provider instead and more appropriately allow EACH service to plainly define a DNS entry.
To be more clear eventually rewriting the specs for defaults to match whatever stack configs given is likely the most optimal choice. Basically utilizing the homoiconic nature of Clojure and consuming the first program to generate the final one. Stubbing in the replacements as we walk through it.
Local config loading or something should also be a provider, as obviously we would want to be able to pass through virtually anything to a service. That way they can be accessed later (this would replace the weird load-yaml that is a leftover from prior iterations)
pulumi2crd should perhaps include some install instructions and some insight into usage
Currently the script builds correctly, but since they are version dependant we might want to have some sort of version management for each of these components. That way they can be updated in a similar mechanism to a normal npm package. We can make CICD pipelines for them for this with some sort of cron scheduling. Emulating Renovate behavior (or we can see if Renovate can be useful here even).
Those generated CRDs should not be baked into the provider utils but instead be treated as an expansion. This way it is neatly organized into official and extended functionality.
Default values (like in K8) are opinionated. They do need to outline how to use a structure for example, but it should also be convenient to use any other resource like Nginx instead of Traefik or Azure instead of Cloudflare. A macro could be applied to them (preferably after their declaration, so their default state remains opinionated) to swap out which provider an individual chooses to use. It can be an added field in the core declarations for processing. Obvious goal for this is expansiveness. There should be clean, reusable defaults and everything should be easily modifiable and expandable.
Resource declarations might benefit from being *able* to splinter when needed. Currently they are VERY MUCH locked to a singleton pattern. While we can "loop" over stuff inside a declaration it still only ever makes *one* resource.
Currently, certificates relies upon a prior step existing and that in itself is a bit of an anti-pattern... So in the future our options NEED some way of informing the resolver and deployer that it has custom execution.
```
:k8s:certificates
{:constructor (.. cert-manager -v1 -Certificate)
:provider-key :k8s
:defaults-fn (fn [env]
(p-> env :options :vault:prepare "stringData" .-domains
#(vec
(for [domain (js/JSON.parse %)]
(let [clean-name (clojure.string/replace domain #"\." "-")]
{:_suffix clean-name
:spec {:dnsNames [domain (str "*." domain)]
:secretName (str clean-name "-tls")}})))))}
```
The above is unideal. I think the best path forward for that is an override? Considering that some might not use Vault.
It might, instead, benefit from a high level user declaration of intent regarding the location of their secrets/settings. I mentioned above to have it resolve based on what providers utilized (within reason for support). That removes the inherent reliance, but it still does leave resolution in the default-fn in an unideal manner. It doesn't work to make top-level functions resolve on the outer layer as the Vault entry wouldn't exist yet.
If we do the user intent, we can at least change it to be a standard such as
```
(p-> env :options :secrets .-domains #(function here))
```
I should add that this function would be in a more *plugin* since it isn't inherently a built-in for K8s. Same for Gateway.
It wouldn't hurt to add some extension for developing these too. Increasing clarity on manner of declaration can not hurt.
Should also revise default-fn to recursively call certificate and just allow the default-fn to unwind the values.
---
It may be helpful to redesign the stack mechanism entirely so that resources and such are declared like:
(def config
{:stack [
{:item-name
{:options-in-here}}
{:item-name-2
{:options-in-here}}
]})
Where this provides much clearer association and each resource has its options readily available. As such you could declare duplicate keys in the same config. It would make resource associations much more explicit and cleaner written.
It would require a decent amount of revision, so no rush on this.
Mentioned above a bit, but eventually rewriting the specs for defaults to match whatever stack configs given is likely the most optimal choice. Basically utilizing the homoiconic nature of Clojure and consuming the first program to generate the final one. Stubbing in the replacements as we walk through it.
Component spec really needs to be moved out of stack_processor as it is just such a large block of data that so better belongs w/ the providers themselves.
---
@@ -125,7 +27,6 @@ The long term goal is for this to be a mostly uninteractive, to completion set u
More immediately, as we've closed in on a functional end-to-end alpha build and learned several choices we could've made to better design a next build, we'll actually use this to move our services off a single VPS w/ a docker compose and into a cluster fully generated by this with no setup or involvement on our part.
### Initial requirements
#### Need to Revise as we swapped to using Pulumi Automation API so the entire process is automated
@@ -300,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,9 +1,10 @@
{:paths ["src/main"]
;;:deps {gigiaj/pulumicljs {:local/root "../pulumi-clojurescript"}}
:deps {gigiaj/pulumicljs
:deps {
;;gigiaj/pulumicljs {:local/root "../pulumi-clojurescript"}
gigiaj/pulumicljs
{:git/url "https://github.com/GigiaJ/pulumi-clojurescript.git"
:git/sha "01133c6b412db9d6541bc8566dd0e6fe3ffd514c"
: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,7 +50,8 @@
#(execute
shared-resources-definition
(fn [output] (let [secrets (p-> output .-harbor "vault:prepare" "stringData")]
#js {:url (p-> secrets .-host (fn [x] (str "https://" x)))
#js {
:url (p-> secrets .-host (fn [x] (str "https://" x)))
:username (p-> secrets .-username)
:password (p-> secrets .-password)})))))
@@ -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]
@@ -112,6 +121,7 @@
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,9 +272,10 @@
{: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 {:fetchOpts {:repo "https://openbao.github.io/openbao-helm"}
:k8s:chart-opts {:repositoryOpts {:repo "https://openbao.github.io/openbao-helm"}
:transformations [(fn [props opts]
(let [kind (:kind props)]
(if (= kind "StatefulSet")

View File

@@ -5,11 +5,10 @@
:app-namespace "cert-manager"
:app-name "cert-manager"
:is-prod? true
:k8s:chart-opts {:fetchOpts {:repo "https://charts.jetstack.io"}
: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

@@ -0,0 +1,7 @@
(ns k8s.add-ons.crd.cert-manager)
(def config
{:stack [:k8s:config-file]
:app-name "cert-manager"
: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,7 @@
(ns k8s.add-ons.crd.gateway-api)
(def config
{:stack [:k8s:config-file]
:app-name "gateway-api"
:version "v1.4.0"
:k8s:config-file-opts {:file '(str "https://github.com/kubernetes-sigs/gateway-api/releases/download/" version "/experimental-install.yaml")}})

View File

@@ -0,0 +1,10 @@
(ns k8s.add-ons.crd.traefik)
(def config
{:stack [:k8s:chart]
:app-name "traefik-crds"
:k8s:chart-opts {:repositoryOpts {:repo "https://traefik.github.io/charts"}
:chart "traefik-crds"
:version "v1.12.0"
:namespace "traefik"
:values {:deleteOnUninstall true}}})

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,12 +5,13 @@
(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"
:namespace "kube-system"}
:stringData {:token (-> cfg :hcloudToken)}}
:k8s:chart-opts {:fetchOpts {:repo "https://charts.hetzner.cloud"}
:k8s:chart-opts {:repositoryOpts {:repo "https://charts.hetzner.cloud"}
:values {:controller {:enabled false
:existingSecret {:name "hcloud-csi-secret"}
:node {:existingSecret {:name "hcloud-csi-secret"}}}}}})

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

@@ -7,20 +7,10 @@
:no-namespace true
:app-name "wasabi-csi"
:k8s:chart-opts {:chart "csi-s3"
:fetchOpts {:repo "https://yandex-cloud.github.io/k8s-csi-s3/charts"}
: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

@@ -1,20 +1,42 @@
(ns k8s.add-ons.gateway.traefik)
(def config
{:stack [:vault:prepare [:k8s :secret :chart :gateway :certificates]]
{:stack [:vault:prepare [:k8s :secret :chart :gateway-class :gateway :certificates]]
:app-namespace "traefik"
:app-name "traefik"
:is-prod? true
:vault-load-yaml false
:k8s:chart-opts {:fetchOpts {:repo 'repo}
:k8s:chart-opts {:skipCrds true
:repositoryOpts {:repo 'repo}
:chart 'chart
:transformations [(fn [args _opts] (let [kind (get-in args [:resource :kind])]
(if (= kind "CustomResourceDefinition")
nil
args)))]
:version "37.3.0"
:namespace "traefik"
:values {:providers {:kubernetesGateway {:enabled true}}
:gatewayClass {:enabled true
:name "traefik"}}}
:gatewayClass {:enabled false}
:gateway {:enabled false}
:ports {:web {:port 8000
:expose {:default true}
:exposedPort 80
:protocol "TCP"}
:websecure {:port 8443
:expose {:default true}
:exposedPort 443
:protocol "TCP"
:transport {:respondingTimeouts
{:readTimeout "600s"
:writeTimeout "600s"
:idleTimeout "600s"}}}}}}
:k8s:gateway-opts
{:metadata {:name "main-gateway"
:namespace "traefik"}
:spec {:gatewayClassName "traefik"
:listeners '(make-listeners domains)}}})
:listeners '(make-listeners domains)}}
:k8s:gateway-class-opts
{:spec {:controllerName "traefik.io/gateway-controller"}}
})

View File

@@ -6,7 +6,7 @@
:app-name "harbor"
:image-port 80
:vault-load-yaml false
:k8s:chart-opts {:fetchOpts {:repo "https://helm.goharbor.io"}
:k8s:chart-opts {:repositoryOpts {:repo "https://helm.goharbor.io"}
:values {:externalURL '(str "https://" host)
:expose {:type "route"
:tls {:enabled false}

View File

@@ -13,7 +13,7 @@
:password (-> cfg :public-image-registry-password)}
:tags [(str (-> cfg :public-image-registry-url) "/" (-> cfg :public-image-registry-username) "/" "caddy")]
:push true}
:k8s:chart-opts {:fetchOpts {:repo "https://caddyserver.github.io/ingress"}
:k8s:chart-opts {:repositoryOpts {:repo "https://caddyserver.github.io/ingress"}
:values
{:ingressController
{:deployment {:kind "DaemonSet"}

View File

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

View File

@@ -6,4 +6,4 @@
:no-namespace true
:app-namespace "kube-system"
:app-name "kubernetes-replicator"
:k8s:chart-opts {:fetchOpts {:repo "https://helm.mittwald.de"}}})
:k8s:chart-opts {:repositoryOpts {:repo "https://helm.mittwald.de"}}})

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

@@ -0,0 +1,21 @@
(ns k8s.services.foundryvtt.service-2)
(def config
{:stack [:vault:prepare [:k8s :pvc :deployment :service :httproute]]
:image-port 30000
:app-namespace "generic"
:app-name "girls-foundry"
:k8s:deployment-opts {:spec {:template {:spec {:imagePullSecrets [{:name "harbor-creds-secrets"}]
:volumes [{:name "data-vol"
:persistentVolumeClaim {:claimName "girls-vtt-assets"}}]
:containers [{:name 'app-name :image '(str registry-base "/" registry-namespace "/" "foundry" ":latest")
:volumeMounts [{:name "data-vol"
:mountPath "/root/.local/share"
:mountPropagation "HostToContainer"}]}]}}}}
:k8s:pvc-opts
{:metadata {:name "girls-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]
{: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
(ns k8s.services.matrix.home-server.service)
(def config
{:stack [:vault-secrets :docker-image :deployment :service :ingress]
:image-port 80
(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 {:fetchOpts {:repo "https://nextcloud.github.io/helm/"}
:values {:nextcloud {:host 'host
:trustedDomains ['host 'app-name]}}
: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)))}})
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,13 +1,11 @@
(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"
:fetchOpts {:repo "https://prometheus-community.github.io/helm-charts"}
:k8s:chart-opts {:chart "kube-prometheus-stack"
:repositoryOpts {:repo "https://prometheus-community.github.io/helm-charts"}
:namespace "monitoring"
:values {:grafana {:adminPassword 'password
:ingress {:enabled true

View File

@@ -8,7 +8,7 @@
:image-port 8080
:vault-load-yaml true
:chart-opts
{:fetchOpts {:repo "https://docs.renovatebot.com/helm-charts"}
{:repositoryOpts {:repo "https://docs.renovatebot.com/helm-charts"}
:values
{:renovate
{:config {:platform "github"

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.ingress-controller.caddy :as caddy]
[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.minio :as minio]
[k8s.add-ons.s3proxy :as s3proxy]
[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,8 +66,15 @@
(def shared-resources-definition
(create-resource-definition
[traefik/config cert-manager/config
dns/config wasabi-csi/config proxy/config secret-replicator/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
harbor/config
]
["base" "init"]
@@ -67,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)))