kadet-hub logokadet-hub

Jitsi Meet on Kubernetes without Docker Compose, with Kapitan

Jitsi Meet, video meetings in the browser, as its four services web, prosody, jicofo and the video bridge jvb, rendered by the kadet-hub kubernetes generator 1.14.0 from docker-compose.yml of docker-jitsi-meet stable-11248-3.

What it deploys

Required parameters

applications.jitsi-meet.jicofo_auth_password is JICOFO_AUTH_PASSWORD, with which jicofo logs in to prosody as focus@auth.meet.jitsi. applications.jitsi-meet.jvb_auth_password is JVB_AUTH_PASSWORD, with which jvb logs in as jvb@auth.meet.jitsi. The compose setup has gen-passwords.sh write random values, such as openssl rand -hex 16 prints, and any such string works. applications.jitsi-meet.moderator_password is the password of moderator@meet.jitsi, the first user who may open a meeting. Set all three as refs with the backend of your choice. Without one of them the compile stops with Interpolation key '<key>' not found.

Include

A target includes the recipe and its options as classes and can override anything the recipe sets:

classes:
  - recipes.jitsi-meet
parameters:
  namespace: jitsi-meet
  kapitan:
    vars:
      target: jitsi-meet
  applications:
    jitsi-meet:
      jicofo_auth_password: <ref>
      jvb_auth_password: <ref>
      moderator_password: <ref>

Fetching it

The quickstart goes through these steps on a kind cluster with the uptime-kuma recipe, from installing Kapitan to the running app.

A separate fetch inventory pins the recipe by version and digest. This is fetch/targets/recipes.yml for version 1.0.0:

parameters:
  kapitan:
    dependencies:
      - type: oci
        source: ghcr.io/kadet-hub/recipes/jitsi-meet:1.0.0@sha256:8c268b78db723657e9310c4c5fee873917b1a5c4d6729b0a74f44e707104f8f7
        output_path: inventory/classes/recipes/jitsi-meet

The first command fetches the recipe into inventory/classes/recipes/jitsi-meet, the second the generators and compiles:

kapitan compile --inventory-path fetch --fetch --output-path .
kapitan compile --fetch

The first command exits with status 1 because the fetch target compiles nothing. Kapitan's --fetch checks neither the digest nor the attestation. This verifies the attestation of the recipe:

gh attestation verify \
  oci://ghcr.io/kadet-hub/recipes/jitsi-meet@sha256:8c268b78db723657e9310c4c5fee873917b1a5c4d6729b0a74f44e707104f8f7 \
  --owner kadet-hub \
  --cert-identity https://github.com/kadet-hub/registry/.github/workflows/release.yml@refs/heads/main

The attested index must also list each digest under its recipe with the pinned version, and not as yanked. Verifying by hand shows how to read it.

Settings

<c> stands for each of the components jitsi-meet, jitsi-meet-prosody, jitsi-meet-jicofo and jitsi-meet-jvb.

Setting Inventory
Jitsi release, stable-11248-3 components.<c>.image, tag and digest, the same release for all four
time zone, UTC from env.example components.<c>.env.TZ
public URL, unset components.jitsi-meet.env.PUBLIC_URL
media address, unset components.jitsi-meet-jvb.env.JVB_ADVERTISE_IPS
user name of the first moderator, moderator components.jitsi-meet-prosody.env.MODERATOR_USER
cluster domain, cluster.local applications.jitsi-meet.cluster_domain
other variables of env.example, such as ENABLE_LOBBY components.<c>.env.<variable> of each component whose compose service lists it
exposure components.jitsi-meet.service.type, components.jitsi-meet-jvb.service.type
size of the claims storage, 1Gi components.jitsi-meet.volume_claims.storage.spec.resources.requests.storage, the same below jitsi-meet-prosody
resources components.<c>.resources

Values of env are strings, so quote "1". web resolves prosody by the Service’s full name, jitsi-meet-prosody.<namespace>.svc.<cluster domain>, so set applications.jitsi-meet.cluster_domain on a cluster whose domain is not cluster.local.

The images render their configuration at each start from the environment. The directories /config of each image and /prosody-plugins-custom of prosody take files that extend it, such as custom-config.js for web. A target mounts a ConfigMap there through config_maps of the component.

Mapping

The service web becomes the component jitsi-meet, prosody jitsi-meet-prosody, jicofo jitsi-meet-jicofo and jvb jitsi-meet-jvb. The compose file sets no variable of its own beyond SENTRY_DSN. Its services pass variables from .env, which the documentation copies from env.example at the same commit, SHA-256 b38560d14b7f25be441f8ae116f13fcb626d8a3bd248c86f03ef25060d2330d9 (DEC-306). A variable that env.example leaves unset is not rendered.

Compose Recipe
service web StatefulSet jitsi-meet, Service jitsi-meet
service prosody StatefulSet jitsi-meet-prosody, Service jitsi-meet-prosody
service jicofo Deployment jitsi-meet-jicofo, Service jitsi-meet-jicofo
service jvb Deployment jitsi-meet-jvb, Service jitsi-meet-jvb
images ${JITSI_IMAGE_REPO:-ghcr.io/jitsi}/<service>:stable-11248-3 ghcr.io/jitsi/<service>:stable-11248-3 with the digest of its index
ports ${HTTP_PORT}:8000 and ${HTTPS_PORT}:8443 of web, 8000 and 8443 in env.example Service ports http 8000 and https 8443
expose 5222, 5269, 5347 and 5280 of prosody Service ports c2s, s2s, component and http
port 127.0.0.1:8888:8888 of jicofo Service port http 8888
ports 10000:10000/udp and 127.0.0.1:8080:8080 of jvb Service ports media 10000/UDP and http 8080
TZ and the passwords in env.example TZ: UTC in each env, JICOFO_AUTH_PASSWORD and JVB_AUTH_PASSWORD from the Secret jitsi-meet
JIGASI_XMPP_PASSWORD, JIGASI_TRANSCRIBER_PASSWORD, JIBRI_RECORDER_PASSWORD, JIBRI_XMPP_PASSWORD not rendered. They serve jigasi and jibri, which docker-compose.yml does not run (DEC-306).
SENTRY_DSN="${JICOFO_SENTRY_DSN:-0}" and its jvb counterpart SENTRY_DSN: '"0"', the quoted value compose passes
prosody’s network alias ${XMPP_SERVER:-xmpp.meet.jitsi} XMPP_SERVER: jitsi-meet-prosody for jicofo and jvb, and web’s XMPP_BOSH_URL_BASE with the Service’s full name (DEC-308)
bind mounts ${CONFIG}/storage/web and ${CONFIG}/storage/prosody claim templates storage, ReadWriteOnce, 1Gi, at /storage and /var/lib/prosody, with fsGroup: 1000 (DEC-307)
the other bind mounts below ${CONFIG} not rendered. The containers only read them, and the images have the directory empty or read it only for a feature that is off (DEC-307).
read_only: true readOnlyRootFilesystem: true (DEC-309)
tmpfs at /run and /tmp emptyDir volumes of medium: Memory with the compose sizes as sizeLimit (DEC-309)
labels service: jitsi-<service> pod annotations
restart, depends_on, the network meet.jitsi not rendered
not in the compose file ENABLE_AUTH and ENABLE_GUESTS (DEC-310), the postStart hook and MODERATOR_* of prosody (DEC-311)

Not every Service port answers with these settings, as with the compose file. jicofo serves its REST API on 8888 at its loopback address unless JICOFO_ENABLE_REST is set. prosody listens on 5269 only with PROSODY_ENABLE_S2S and on 5347 only for an external component that its configuration names.

Proof

check jitsi-meet --level deploys with tests/target.yml, on kind for each Kubernetes minor CI tests, with check 0.16.0. A compose file has no Kubernetes objects to compare with, so the recipe is proven by deploying it (RCP-38). tests/target.yml sets low-entropy test passwords.

tests/smoke starts a pod of prosody’s image, which carries bash and curl. From there, through the Services, it

Not tested: audio and video, whether a client reaches UDP port 10000, ICE through STUN, TURN, the web app in a browser, and the ports that answer only with other settings.

Versions

The recipe's files are in kadet-hub/recipes. All recipes