Compare commits

...

19 commits
3.0.0 ... main

18 changed files with 5407 additions and 85 deletions

2
.gitignore vendored
View file

@ -14,7 +14,7 @@ pom.*
# cljs # cljs
.shadow-cljs .shadow-cljs
.nrepl-* .nrepl-*
package-lock.json /package-lock.json
node_modules/ node_modules/
public/js/ public/js/

View file

@ -5,11 +5,19 @@
## Purpose ## Purpose
c4k-jitsi provides a k8s deployment for jitsi containing: c4k-jitsi provides a k8s deployment for jitsi containing [see also Jitsi Architecture](https://jitsi.github.io/handbook/docs/architecture/)
* jitsi * jitsi-web
* jvb
* jicofo
* prosody
* etherpad for shared documents
* excalidraw for shared whiteboards
* coturn as stun server
* moderator-election as tool for electing the next moderator
* ingress having a letsencrypt managed certificate * ingress having a letsencrypt managed certificate
* monitoring connected to grafana cloud
The package aims to a low load sceanrio. The package is intended for a low-load scenario.
## Status ## Status

View file

@ -17,10 +17,10 @@ resource "aws_s3_bucket" "backup" {
} }
} }
resource "hcloud_server" "jitsi_09_2021" { resource "hcloud_server" "jitsi_2025_02" {
name = "the name" name = "the name"
image = "ubuntu-20.04" image = "ubuntu-24.04"
server_type = "cx31" server_type = "cx32"
location = "fsn1" location = "fsn1"
ssh_keys = ... ssh_keys = ...
@ -29,31 +29,30 @@ resource "hcloud_server" "jitsi_09_2021" {
} }
} }
resource "aws_route53_record" "v4_neu" { resource "aws_route53_record" "v4" {
for_each ["jitsi", "stun.jitsi", "excalidraw.jitsi", "etherpad.jitsi"]
zone_id = the_dns_zone zone_id = the_dns_zone
name = "jitsi-neu" name = each.key
type = "A" type = "A"
ttl = "300" ttl = "300"
records = [hcloud_server.jitsi_09_2021.ipv4_address] records = [hcloud_server.jitsi_2025_01.ipv4_address]
} }
output "ipv4" { output "ipv4" {
value = hcloud_server.jitsi_09_2021.ipv4_address value = hcloud_server.jitsi_2025_01.ipv4_address
} }
``` ```
## k8s minicluster ## k8s minicluster
For k8s installation we use our [provs](https://repo.prod.meissa.de/meissa/provs) with the following configuation: For k8s installation we use our [provs](https://repo.prod.meissa.de/meissa/provs) with the following configuration:
``` ```
{:user :k8s {:fqdn "fqdn-from-above"
:k8s {:external-ip "ip-from-above"} :node {:ipv4 "ip-from-above"}
:cert-manager :letsencrypt-prod-issuer :certmanager {:email "admin-email" :letsencryptEndpoint "prod"}}
:persistent-dirs ["postgres"]
}
``` ```
## kubectl apply c4k-jitsi ## kubectl apply c4k-jitsi
@ -67,7 +66,6 @@ c4k-jitsi config.edn auth.edn | kubectl apply -f -
with the following config.edn: with the following config.edn:
``` ```
{:fqdn "the-fqdn-from aws_route53_record.v4_neu" {:fqdn "fqdn-from-above"
:postgres-data-volume-path "/var/postgres" ;; Volume was configured at dda-k8s-crate, results in a PersistentVolume definition.
:issuer "prod" } :issuer "prod" }
``` ```

Binary file not shown.

Before

(image error) Size: 83 KiB

After

(image error) Size: 84 KiB

View file

@ -6,7 +6,7 @@ from ddadevops import *
name = "c4k-jitsi" name = "c4k-jitsi"
MODULE = "excalidraw" MODULE = "excalidraw"
PROJECT_ROOT_PATH = "../.." PROJECT_ROOT_PATH = "../.."
version = "3.0.0" version = "3.0.3-dev"
@init @init

File diff suppressed because it is too large Load diff

View file

@ -2,7 +2,7 @@
"name": "c4k-jitsi", "name": "c4k-jitsi",
"description": "Generate c4k yaml for a jitsi deployment.", "description": "Generate c4k yaml for a jitsi deployment.",
"author": "meissa GmbH", "author": "meissa GmbH",
"version": "3.0.0", "version": "3.0.3-SNAPSHOT",
"homepage": "https://gitlab.com/domaindrivenarchitecture/c4k-jitsi#readme", "homepage": "https://gitlab.com/domaindrivenarchitecture/c4k-jitsi#readme",
"repository": "https://www.npmjs.com/package/c4k-jitsi", "repository": "https://www.npmjs.com/package/c4k-jitsi",
"license": "APACHE2", "license": "APACHE2",

View file

@ -1,10 +1,10 @@
(defproject org.domaindrivenarchitecture/c4k-jitsi "3.0.0" (defproject org.domaindrivenarchitecture/c4k-jitsi "3.0.3-SNAPSHOT"
:description "jitsi c4k-installation package" :description "jitsi c4k-installation package"
:url "https://domaindrivenarchitecture.org" :url "https://domaindrivenarchitecture.org"
:license {:name "Apache License, Version 2.0" :license {:name "Apache License, Version 2.0"
:url "https://www.apache.org/licenses/LICENSE-2.0.html"} :url "https://www.apache.org/licenses/LICENSE-2.0.html"}
:dependencies [[org.clojure/clojure "1.12.0"] :dependencies [[org.clojure/clojure "1.12.0"]
[org.clojure/tools.reader "1.5.0"] [org.clojure/tools.reader "1.5.1"]
[org.domaindrivenarchitecture/c4k-common-clj "9.0.1"] [org.domaindrivenarchitecture/c4k-common-clj "9.0.1"]
[hickory "0.7.1" :exclusions [viebel/codox-klipse-theme]]] [hickory "0.7.1" :exclusions [viebel/codox-klipse-theme]]]
:target-path "target/%s/" :target-path "target/%s/"
@ -24,9 +24,9 @@
:main dda.c4k-jitsi.uberjar :main dda.c4k-jitsi.uberjar
:uberjar-name "c4k-jitsi-standalone.jar" :uberjar-name "c4k-jitsi-standalone.jar"
:dependencies [[org.clojure/tools.cli "1.1.230"] :dependencies [[org.clojure/tools.cli "1.1.230"]
[ch.qos.logback/logback-classic "1.5.16" [ch.qos.logback/logback-classic "1.5.17"
:exclusions [com.sun.mail/javax.mail]] :exclusions [com.sun.mail/javax.mail]]
[org.slf4j/jcl-over-slf4j "2.0.16"] [org.slf4j/jcl-over-slf4j "2.0.17"]
[com.github.clj-easy/graal-build-time "1.0.5"]]}} [com.github.clj-easy/graal-build-time "1.0.5"]]}}
:release-tasks [["test"] :release-tasks [["test"]
["vcs" "assert-committed"] ["vcs" "assert-committed"]

View file

@ -39,6 +39,7 @@
(jitsi/jicofo-config resolved-config) (jitsi/jicofo-config resolved-config)
(jitsi/web-config resolved-config) (jitsi/web-config resolved-config)
(jitsi/jvb-config resolved-config) (jitsi/jvb-config resolved-config)
;not yet working, needs fix
;(jitsi/jibri-config resolved-config) ;(jitsi/jibri-config resolved-config)
(jitsi/restart-config resolved-config) (jitsi/restart-config resolved-config)
(jitsi/etherpad-config resolved-config) (jitsi/etherpad-config resolved-config)
@ -65,6 +66,11 @@
:service-port 80 :service-port 80
:fqdns [(str "moderator-elector." (:fqdn resolved-config))]} :fqdns [(str "moderator-elector." (:fqdn resolved-config))]}
resolved-config)) resolved-config))
(ing/generate-ingress-and-cert (merge
{:service-name "coturn-turn-tcp"
:service-port 3478
:fqdns [(str "stun." (:fqdn resolved-config))]}
resolved-config))
(when (:contains? resolved-config :mon-cfg) (when (:contains? resolved-config :mon-cfg)
(mon/generate-config))))))) (mon/generate-config)))))))

View file

@ -40,7 +40,8 @@
[(load-and-adjust-namespace "jitsi/prosody-config-serviceaccount.yaml" namespace) [(load-and-adjust-namespace "jitsi/prosody-config-serviceaccount.yaml" namespace)
(-> (->
(load-and-adjust-namespace "jitsi/prosody-config-common-cm.yaml" namespace) (load-and-adjust-namespace "jitsi/prosody-config-common-cm.yaml" namespace)
(cm/replace-all-matching "JITSI_FQDN" fqdn)) (cm/replace-all-matching "JITSI_FQDN" fqdn)
(cm/replace-key-value :STUN_HOST (str "stun." fqdn)))
(load-and-adjust-namespace "jitsi/prosody-config-default-cm.yaml" namespace) (load-and-adjust-namespace "jitsi/prosody-config-default-cm.yaml" namespace)
(load-and-adjust-namespace "jitsi/prosody-config-envs-cm.yaml" namespace) (load-and-adjust-namespace "jitsi/prosody-config-envs-cm.yaml" namespace)
(load-and-adjust-namespace "jitsi/prosody-config-init-cm.yaml" namespace) (load-and-adjust-namespace "jitsi/prosody-config-init-cm.yaml" namespace)
@ -87,6 +88,7 @@
(-> (->
(load-and-adjust-namespace "jitsi/web-config-envs-cm.yaml" namespace) (load-and-adjust-namespace "jitsi/web-config-envs-cm.yaml" namespace)
(cm/replace-key-value :XMPP_BOSH_URL_BASE (str "http://prosody." namespace ".svc.cluster.local:5280")) (cm/replace-key-value :XMPP_BOSH_URL_BASE (str "http://prosody." namespace ".svc.cluster.local:5280"))
(cm/replace-key-value :P2P_STUN_SERVERS (str "stun." fqdn ":443"))
(cm/replace-key-value :ETHERPAD_PUBLIC_URL (str "https://etherpad." fqdn "/p/")) (cm/replace-key-value :ETHERPAD_PUBLIC_URL (str "https://etherpad." fqdn "/p/"))
(cm/replace-key-value :WHITEBOARD_COLLAB_SERVER_PUBLIC_URL (str "https://excalidraw." fqdn)) (cm/replace-key-value :WHITEBOARD_COLLAB_SERVER_PUBLIC_URL (str "https://excalidraw." fqdn))
) )

View file

@ -1,11 +1,9 @@
(ns dda.c4k-jitsi.browser (ns dda.c4k-jitsi.browser
(:require (:require
[clojure.tools.reader.edn :as edn] [clojure.tools.reader.edn :as edn]
[dda.c4k-common.monitoring :as mon]
[dda.c4k-common.common :as cm] [dda.c4k-common.common :as cm]
[dda.c4k-common.browser :as br] [dda.c4k-common.browser :as br]
[dda.c4k-jitsi.core :as core] [dda.c4k-jitsi.core :as core]))
[dda.c4k-jitsi.jitsi :as jitsi]))
(defn generate-content [] (defn generate-content []
(cm/concat-vec (cm/concat-vec
@ -13,22 +11,22 @@
(br/generate-needs-validation) :content (br/generate-needs-validation) :content
(cm/concat-vec (cm/concat-vec
(br/generate-group (br/generate-group
"domain" "config"
(cm/concat-vec (br/generate-text-area
(br/generate-input-field "fqdn" "Your fqdn:" "jitsi.prod.meissa-gmbh.de") "config" "Your config.edn:"
(br/generate-input-field "issuer" "(Optional) Your issuer prod/staging:" "") "{:fqdn \"jitsi.your.domain\"
(br/generate-input-field "mon-cluster-name" "(Optional) monitoring cluster name:" "jitsi") :mon-cfg {:cluster-name \"jitsi\"
(br/generate-input-field "mon-cluster-stage" "(Optional) monitoring cluster stage:" "test") :cluster-stage \"test\"
(br/generate-input-field "mon-cloud-url" "(Optional) grafana cloud url:" "https://prometheus-prod-01-eu-west-0.grafana.net/api/prom/push") :grafana-cloud-url \"https://prometheus-prod-01-eu-west-0.grafana.net/api/prom/push\"}}"
)) "5"))
(br/generate-group (br/generate-group
"credentials" "auth"
(br/generate-text-area "auth" "Your auth.edn:" "{:jvb-auth-password \"jitsi\" (br/generate-text-area "auth" "Your auth.edn:" "{:jvb-auth-password \"jitsi\"
:jicofo-auth-password \"jicofo-password\" :jicofo-auth-password \"jicofo-password\"
:jicofo-component-secret \"jicofo-component-secrect\" :jicofo-component-secret \"jicofo-component-secrect\"
:mon-auth {:grafana-cloud-user \"your-user-id\" :mon-auth {:grafana-cloud-user \"your-user-id\"
:grafana-cloud-password \"your-cloud-password\"}}}" :grafana-cloud-password \"your-cloud-password\"}}}"
"5")) "6"))
[(br/generate-br)] [(br/generate-br)]
(br/generate-button "generate-button" "Generate c4k yaml")))] (br/generate-button "generate-button" "Generate c4k yaml")))]
(br/generate-output "c4k-jitsi-output" "Your c4k deployment.yaml:" "25"))) (br/generate-output "c4k-jitsi-output" "Your c4k deployment.yaml:" "25")))
@ -40,27 +38,8 @@
:content :content
(generate-content)}) (generate-content)})
(defn config-from-document []
(let [issuer (br/get-content-from-element "issuer" :optional true)
mon-cluster-name (br/get-content-from-element "mon-cluster-name" :optional true)
mon-cluster-stage (br/get-content-from-element "mon-cluster-stage" :optional true)
mon-cloud-url (br/get-content-from-element "mon-cloud-url" :optional true)]
(merge
{:fqdn (br/get-content-from-element "fqdn")}
(when (some? issuer)
{:issuer issuer})
(when (some? mon-cluster-name)
{:mon-cfg {:cluster-name mon-cluster-name
:cluster-stage (keyword mon-cluster-stage)
:grafana-cloud-url mon-cloud-url}})
)))
(defn validate-all! [] (defn validate-all! []
(br/validate! "fqdn" ::jitsi/fqdn) (br/validate! "config" core/config? :deserializer edn/read-string)
(br/validate! "issuer" ::jitsi/issuer :optional true)
(br/validate! "mon-cluster-name" ::mon/cluster-name :optional true)
(br/validate! "mon-cluster-stage" ::mon/cluster-stage :optional true)
(br/validate! "mon-cloud-url" ::mon/grafana-cloud-url :optional true)
(br/validate! "auth" core/auth? :deserializer edn/read-string) (br/validate! "auth" core/auth? :deserializer edn/read-string)
(br/set-form-validated!)) (br/set-form-validated!))
@ -68,22 +47,22 @@
(-> (br/get-element-by-id name) (-> (br/get-element-by-id name)
(.addEventListener "blur" #(do (validate-all!))))) (.addEventListener "blur" #(do (validate-all!)))))
(defn init [] (defn init []
(br/append-hickory (generate-content-div)) (br/append-hickory (generate-content-div))
(-> js/document (let [config-only false
(.getElementById "generate-button") auth-only false]
(.addEventListener "click" (-> js/document
#(do (validate-all!) (.getElementById "generate-button")
(-> (cm/generate-common (.addEventListener "click"
(config-from-document) #(do (validate-all!)
(br/get-content-from-element "auth" :deserializer edn/read-string) (-> (cm/generate-cm
{} (br/get-content-from-element "config" :deserializer edn/read-string)
core/k8s-objects) (br/get-content-from-element "auth" :deserializer edn/read-string)
(br/set-output!))))) core/config-defaults
(add-validate-listener "fqdn") core/config-objects
(add-validate-listener "issuer") core/auth-objects
(add-validate-listener "mon-cluster-name") config-only
(add-validate-listener "mon-cluster-stage") auth-only)
(add-validate-listener "mon-cloud-url") (br/set-output!)))))
(add-validate-listener "auth")) (add-validate-listener "config")
(add-validate-listener "auth")))

View file

@ -9,7 +9,6 @@ metadata:
metallb.universe.tf/allow-shared-ip: "shared-ip-service-group" metallb.universe.tf/allow-shared-ip: "shared-ip-service-group"
metallb.universe.tf/address-pool: public metallb.universe.tf/address-pool: public
spec: spec:
type: LoadBalancer
ports: ports:
- name: turn-tcp - name: turn-tcp
port: 3478 port: 3478

View file

@ -9,7 +9,6 @@ metadata:
metallb.universe.tf/allow-shared-ip: "shared-ip-service-group" metallb.universe.tf/allow-shared-ip: "shared-ip-service-group"
metallb.universe.tf/address-pool: public metallb.universe.tf/address-pool: public
spec: spec:
type: LoadBalancer
ports: ports:
- name: turn-udp - name: turn-udp
port: 3478 port: 3478

View file

@ -21,6 +21,11 @@ spec:
serviceAccountName: jitsi-meet serviceAccountName: jitsi-meet
securityContext: securityContext:
{} {}
initContainers:
- name: wait-for-prosody
image: curlimages/curl:latest
command: ["/bin/sh","-c"]
args: ["while [ $(curl -sw '%{http_code}' http://prosody:5280 -o /dev/null) -ne 200 ]; do sleep 5; echo 'Waiting for the prosody...'; done"]
containers: containers:
- name: jitsi-meet - name: jitsi-meet
securityContext: securityContext:

View file

@ -22,4 +22,6 @@ data:
ENABLE_XMPP_WEBSOCKET: 'true' ENABLE_XMPP_WEBSOCKET: 'true'
ENABLE_RECORDING: "true" ENABLE_RECORDING: "true"
ENABLE_FILE_RECORDING_SERVICE_SHARING: "true" ENABLE_FILE_RECORDING_SERVICE_SHARING: "true"
TZ: 'Europe/Berlin' TZ: 'Europe/Berlin'
STUN_HOST: STUN_FQDN
STUN_PORT: "443"

View file

@ -12,9 +12,6 @@ data:
JICOFO_AUTH_USER: focus JICOFO_AUTH_USER: focus
XMPP_BOSH_URL_BASE: REPLACE_ME XMPP_BOSH_URL_BASE: REPLACE_ME
DEFAULT_LANGUAGE: de DEFAULT_LANGUAGE: de
RESOLUTION: "480" P2P_STUN_SERVERS: REPLACE_ME
RESOLUTION_MIN: "240"
RESOLUTION_WIDTH: "853"
RESOLUTION_WIDTH_MIN: "427"
ETHERPAD_PUBLIC_URL: REPLACE_ME ETHERPAD_PUBLIC_URL: REPLACE_ME
WHITEBOARD_COLLAB_SERVER_PUBLIC_URL: REPLACE_ME WHITEBOARD_COLLAB_SERVER_PUBLIC_URL: REPLACE_ME

View file

@ -17,7 +17,7 @@
(is (s/valid? cut/auth? (yaml/load-as-edn "jitsi-test/valid-auth.yaml")))) (is (s/valid? cut/auth? (yaml/load-as-edn "jitsi-test/valid-auth.yaml"))))
(deftest test-whole-generation (deftest test-whole-generation
(is (= 63 (is (= 65
(count (count
(cut/config-objects (cut/config-objects
(yaml/load-as-edn "jitsi-test/valid-config.yaml"))))) (yaml/load-as-edn "jitsi-test/valid-config.yaml")))))

View file

@ -47,7 +47,9 @@
:ENABLE_XMPP_WEBSOCKET "true", :ENABLE_XMPP_WEBSOCKET "true",
:ENABLE_RECORDING "true", :ENABLE_RECORDING "true",
:ENABLE_FILE_RECORDING_SERVICE_SHARING "true", :ENABLE_FILE_RECORDING_SERVICE_SHARING "true",
:TZ "Europe/Berlin"}} :TZ "Europe/Berlin"
:STUN_HOST "stun.xy.xy.xy",
:STUN_PORT "443"}}
(second (cut/prosody-config (second (cut/prosody-config
{:fqdn "xy.xy.xy" {:fqdn "xy.xy.xy"
:namespace "jitsi"})))) :namespace "jitsi"}))))