From 1289daec33ec9174e1e5934018d08e4aaf1a9536 Mon Sep 17 00:00:00 2001 From: Kornel David Date: Fri, 20 Sep 2024 21:36:58 +0200 Subject: [PATCH 1/7] docs: Janus example init --- docs/examples/janus/janus-call-stunner.yaml | 51 +++++ docs/examples/janus/janus-server.yaml | 219 ++++++++++++++++++++ 2 files changed, 270 insertions(+) create mode 100644 docs/examples/janus/janus-call-stunner.yaml create mode 100644 docs/examples/janus/janus-server.yaml diff --git a/docs/examples/janus/janus-call-stunner.yaml b/docs/examples/janus/janus-call-stunner.yaml new file mode 100644 index 0000000..df5d4e0 --- /dev/null +++ b/docs/examples/janus/janus-call-stunner.yaml @@ -0,0 +1,51 @@ +apiVersion: gateway.networking.k8s.io/v1 +kind: GatewayClass +metadata: + name: stunner-gatewayclass +spec: + controllerName: "stunner.l7mp.io/gateway-operator" + parametersRef: + group: "stunner.l7mp.io" + kind: GatewayConfig + name: stunner-gatewayconfig + namespace: stunner + description: "STUNner is a WebRTC ingress gateway for Kubernetes" + +--- +apiVersion: stunner.l7mp.io/v1 +kind: GatewayConfig +metadata: + name: stunner-gatewayconfig + namespace: stunner +spec: + realm: stunner.l7mp.io + authType: static + userName: "user-1" + password: "pass-1" + +--- +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: udp-gateway + namespace: stunner +spec: + gatewayClassName: stunner-gatewayclass + listeners: + - name: udp-listener + port: 3478 + protocol: TURN-UDP +--- +apiVersion: stunner.l7mp.io/v1 +kind: UDPRoute +metadata: + name: janus + namespace: stunner +spec: + parentRefs: + - name: udp-gateway + rules: + - backendRefs: + - kind: Service + name: janus-gateway + namespace: default \ No newline at end of file diff --git a/docs/examples/janus/janus-server.yaml b/docs/examples/janus/janus-server.yaml new file mode 100644 index 0000000..76c13ac --- /dev/null +++ b/docs/examples/janus/janus-server.yaml @@ -0,0 +1,219 @@ +# Janus Gateway +apiVersion: v1 +kind: ConfigMap +metadata: + name: janus-gateway +data: + janus.jcfg: | + general: { + configs_folder = "@confdir@" + plugins_folder = "@plugindir@" + transports_folder = "@transportdir@" + events_folder = "@eventdir@" + loggers_folder = "@loggerdir@" + debug_level = 4 + admin_secret = "janusoverlord" + protected_folders = [ + "/bin", + "/boot", + "/dev", + "/etc", + "/initrd", + "/lib", + "/lib32", + "/lib64", + "/proc", + "/sbin", + "/sys", + "/usr", + "/var", + "/opt/janus/bin", + "/opt/janus/etc", + "/opt/janus/include", + "/opt/janus/lib", + "/opt/janus/lib32", + "/opt/janus/lib64", + "/opt/janus/sbin" + } + certificates: { + } + media: { + } + nat: { + nice_debug = false + ice_ignore_list = "vmnet" + plugins: { + + } + transports: { + + } + loggers: { + + } + events: { + } +--- +apiVersion: v1 +kind: Service +metadata: + name: janus-gateway + labels: + app.kubernetes.io/name: janus-gateway + app.kubernetes.io/instance: janus + app.kubernetes.io/version: "v1.2.4" +spec: + type: ClusterIP + ports: + - port: 8088 + targetPort: 8088 + protocol: TCP + name: http + - port: 8188 + targetPort: 8188 + protocol: TCP + name: websocket + selector: + app.kubernetes.io/name: janus-gateway + app.kubernetes.io/instance: janus +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: janus-gateway + labels: + app.kubernetes.io/name: janus-gateway + app.kubernetes.io/instance: janus + app.kubernetes.io/version: "v1.2.4" +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: janus-gateway + app.kubernetes.io/instance: janus + template: + metadata: + labels: + app.kubernetes.io/name: janus-gateway + app.kubernetes.io/instance: janus + spec: + terminationGracePeriodSeconds: 18000 # 5 hours + containers: + - name: janus-gateway + image: "l7mp/janus-gateway:v1.2.4" + imagePullPolicy: IfNotPresent + ports: + - name: http + containerPort: 8088 + protocol: TCP + - name: websocket + containerPort: 8188 + protocol: TCP +--- +# Janus Web Demos +apiVersion: v1 +kind: ConfigMap +metadata: + name: janus-web +data: + settings.js: | + var server = "wss://janus_gateway_ip" + var iceServers = [{urls: "turn:stunner_ip:3478?transport=udp", username: "user-1", credential: "pass-1"}] +--- +apiVersion: v1 +kind: Service +metadata: + name: janus-web + labels: + app.kubernetes.io/name: janus-web + app.kubernetes.io/instance: janus-web + app.kubernetes.io/version: "v1.2.4" +spec: + type: ClusterIP + ports: + - port: 80 + targetPort: 80 + protocol: TCP + name: http + selector: + app.kubernetes.io/name: janus-web + app.kubernetes.io/instance: janus-web +--- +apiVersion: apps/v1 +kind: Deployment +metadata: + name: janus-web + labels: + app.kubernetes.io/name: janus-web + app.kubernetes.io/instance: janus-web + app.kubernetes.io/version: "v1.2.4" +spec: + replicas: 1 + selector: + matchLabels: + app.kubernetes.io/name: janus-web + app.kubernetes.io/instance: janus-web + template: + metadata: + labels: + app.kubernetes.io/name: janus-web + app.kubernetes.io/instance: janus-web + spec: + containers: + - name: janus-web + image: "l7mp/janus-web:latest" + imagePullPolicy: IfNotPresent + ports: + - name: http + containerPort: 80 + protocol: TCP + volumeMounts: + - name: config + mountPath: /usr/share/nginx/html/demos/settings.js + subPath: settings.js + volumes: + - name: config + configMap: + name: janus-web + items: + - key: settings.js + path: settings.js +--- +# Ingress for both Janus Gateway and Janus Web Demos +apiVersion: networking.k8s.io/v1 +kind: Ingress +metadata: + name: janus-web-demos + annotations: + cert-manager.io/cluster-issuer: "letsencrypt-prod" + nginx.ingress.kubernetes.io/enable-cors: "true" + nginx.ingress.kubernetes.io/cors-allow-origin: "*" + nginx.ingress.kubernetes.io/ssl-redirect: "true" +spec: + ingressClassName: nginx + tls: + - hosts: + - janus.gcp-europe-central2.stunner.cc + - janus-gateway.gcp-europe-central2.stunner.cc + secretName: janus-web-secret-tls + rules: + - host: janus-gateway.gcp-europe-central2.stunner.cc + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: janus-gateway + port: + number: 8188 + - host: janus.gcp-europe-central2.stunner.cc + http: + paths: + - path: / + pathType: Prefix + backend: + service: + name: janus-web + port: + number: 80 \ No newline at end of file From e3c141f59233fa681ffce764b995e82238eebb77 Mon Sep 17 00:00:00 2001 From: Kornel David Date: Fri, 20 Sep 2024 21:47:49 +0200 Subject: [PATCH 2/7] docs(/example/janus): Add clusterissuer and host name templates --- docs/examples/janus/janus-server.yaml | 28 +++++++++++++++++++++------ 1 file changed, 22 insertions(+), 6 deletions(-) diff --git a/docs/examples/janus/janus-server.yaml b/docs/examples/janus/janus-server.yaml index 76c13ac..e8884d9 100644 --- a/docs/examples/janus/janus-server.yaml +++ b/docs/examples/janus/janus-server.yaml @@ -117,7 +117,7 @@ metadata: name: janus-web data: settings.js: | - var server = "wss://janus_gateway_ip" + var server = "wss://server-janus_gateway_host.nip.io" var iceServers = [{urls: "turn:stunner_ip:3478?transport=udp", username: "user-1", credential: "pass-1"}] --- apiVersion: v1 @@ -193,11 +193,11 @@ spec: ingressClassName: nginx tls: - hosts: - - janus.gcp-europe-central2.stunner.cc - - janus-gateway.gcp-europe-central2.stunner.cc + - client-janus_web_host.nip.io + - server-janus_gateway_host.nip.io secretName: janus-web-secret-tls rules: - - host: janus-gateway.gcp-europe-central2.stunner.cc + - host: server-janus_gateway_host.nip.io http: paths: - path: / @@ -207,7 +207,7 @@ spec: name: janus-gateway port: number: 8188 - - host: janus.gcp-europe-central2.stunner.cc + - host: client-janus_web_host.nip.io http: paths: - path: / @@ -216,4 +216,20 @@ spec: service: name: janus-web port: - number: 80 \ No newline at end of file + number: 80 +--- +apiVersion: cert-manager.io/v1 +kind: ClusterIssuer +metadata: + name: letsencrypt-prod +spec: + acme: + email: info@l7mp.io + server: https://acme-v02.api.letsencrypt.org/directory + privateKeySecretRef: + name: letsencrypt-secret-prod + solvers: + - http01: + ingress: + class: nginx +--- \ No newline at end of file From c949a77752e4c65c8a0453be1187f63e562958e6 Mon Sep 17 00:00:00 2001 From: Kornel David Date: Fri, 20 Sep 2024 21:57:25 +0200 Subject: [PATCH 3/7] docs(/examples/janus): Fix hostname templates --- docs/examples/janus/janus-server.yaml | 10 +++++----- 1 file changed, 5 insertions(+), 5 deletions(-) diff --git a/docs/examples/janus/janus-server.yaml b/docs/examples/janus/janus-server.yaml index e8884d9..1d6a699 100644 --- a/docs/examples/janus/janus-server.yaml +++ b/docs/examples/janus/janus-server.yaml @@ -117,7 +117,7 @@ metadata: name: janus-web data: settings.js: | - var server = "wss://server-janus_gateway_host.nip.io" + var server = "wss://server-ingressserviceip.nip.io" var iceServers = [{urls: "turn:stunner_ip:3478?transport=udp", username: "user-1", credential: "pass-1"}] --- apiVersion: v1 @@ -193,11 +193,11 @@ spec: ingressClassName: nginx tls: - hosts: - - client-janus_web_host.nip.io - - server-janus_gateway_host.nip.io + - client-ingressserviceip.nip.io + - server-ingressserviceip.nip.io secretName: janus-web-secret-tls rules: - - host: server-janus_gateway_host.nip.io + - host: server-ingressserviceip.nip.io http: paths: - path: / @@ -207,7 +207,7 @@ spec: name: janus-gateway port: number: 8188 - - host: client-janus_web_host.nip.io + - host: client-ingressserviceip.nip.io http: paths: - path: / From ef9b92914cf3a72ed92dd7c8e4043e1647fa9e4f Mon Sep 17 00:00:00 2001 From: Kornel David Date: Fri, 20 Sep 2024 22:23:57 +0200 Subject: [PATCH 4/7] docs(/example/livekit): Add Janus example README --- docs/examples/janus/README.md | 204 ++++++++++++++++++++++++++++++++++ 1 file changed, 204 insertions(+) create mode 100644 docs/examples/janus/README.md diff --git a/docs/examples/janus/README.md b/docs/examples/janus/README.md new file mode 100644 index 0000000..c014699 --- /dev/null +++ b/docs/examples/janus/README.md @@ -0,0 +1,204 @@ +# STUNner demo: Video-conferencing with Janus + +This document guides you through the installation of [Janus](https://janus.conf.meetecho.com/) by [Meetecho](https://www.meetecho.com/en/) into Kubernetes, when it is used together with the STUNner WebRTC media gateway. + +In this demo you will learn to: + +- integrate a typical WebRTC application with STUNner, +- obtain a valid TLS certificate to secure the signaling plane, +- deploy the Janus WebRTC server into Kubernetes, and +- configure STUNner to expose Janus to clients. + +## Prerequisites + +The below installation instructions require an operational cluster running a supported version of Kubernetes (>1.22). Most hosted or private Kubernetes cluster services will work, but make sure that the cluster comes with a functional load-balancer integration (all major hosted Kubernetes services should support this). Otherwise, STUNner will not be able to allocate a public IP address for clients to reach your WebRTC infra. As a regrettable exception, Minikube is unfortunately not supported for this demo. The reason is that [Let's Encrypt certificate issuance is not available with nip.io](https://medium.com/@EmiiKhaos/there-is-no-possibility-that-you-can-get-lets-encrypt-certificate-with-nip-io-7483663e0c1b); later on you will learn more about why this is crucial above. + +## Setup + +The recommended way (or at least the possible way, [link](https://janus.discourse.group/t/janus-with-kubernetes-demystifying-the-myths/938), [link](https://bugraoz93.medium.com/active-passive-highly-availability-janus-gateway-on-kubernetes-2189256e5525)) to install Janus into Kubernetes is deploying the media servers into the host-network namespace of the Kubernetes nodes (`hostNetwork: true`). This deployment model, however, comes with a set of uncanny [operational limitations and security concerns](../../WHY.md). Using STUNner, however, media servers can be deployed into ordinary Kubernetes pods and run over a private IP network, like any "normal" Kubernetes workload. + +![WARNING] TODO: figure + +The figure below shows Janus deployed into regular Kubernetes pods behind STUNner without the host-networking hack. Here, Janus is deployed behind STUNner in the [*media-plane deployment model*](../../DEPLOYMENT.md), so that STUNner acts as a "local" STUN/TURN server for Janus, saving the overhead of using public a 3rd party STUN/TURN server for NAT traversal. + +![STUNner Janus integration deployment architecture](../../img/stunner_janus.svg) + +In this tutorial we deploy [Janus Gateway](https://github.com/meetecho/janus-gateway/tree/master) with a set of [preimplemented and packaged server plugins](https://janus.conf.meetecho.com/docs/pluginslist.html) for media exchange, a [Janus Web Demo](https://github.com/meetecho/janus-gateway/tree/master/html), a Kubernetes Ingress gateway to secure signaling connections and handle TLS, and STUNner as a media gateway to expose the Janus server pool to clients. + +## Installation + +Let's start with a disclaimer. The Janus client-side application must work over a secure HTTPS connection, because [getUserMedia](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#browser_compatibility) is available only in secure contexts. This implies that the client-server signaling connection must be secure too. In this demo, we will aim to obtain a proper CA-signed certificate (self-signed certificates haven't been tested). Obtaining a valid TLS certificate is a challenge. Thus, the majority of the below installation guide will be about securing client connections to Janus over TLS; as it turns out, once HTTPS is correctly working integrating Janus with STUNner is very simple. + +In the below example, STUNner will be installed into the identically named namespace, while Janus and the Ingress gateway will live in the default namespace. + +### TLS certificates + +As mentioned above, the Janus WebRTC server will need a valid TLS cert, which means it must run behind an existing DNS domain name backed by a CA signed TLS certificate. This is simple if you have your own domain, but if you don't then [nip.io](https://nip.io) provides a dead simple wildcard DNS for any IP address. We will use this to "own a domain" and obtain a CA signed certificate for Janus. This will allow us to point the domain name `client-.nip.io` to an ingress HTTP gateway in our Kubernetes cluster, which will then use some automation (namely, cert-manager) to obtain a valid CA signed cert. + +Note that public wildcard DNS domains might run into [rate limiting](https://letsencrypt.org/docs/rate-limits/) issues. If this occurs you can try [alternative services](https://moss.sh/free-wildcard-dns-services/) instead of `nip.io`. + +### Ingress + +The first step of obtaining a valid cert is to install a Kubernetes Ingress: this will be used during the validation of our certificates and to terminate client TLS encrypted contexts. + +Install an ingress controller into your cluster. We used the official [nginx ingress](https://github.com/kubernetes/ingress-nginx), but this is not required. + +```console +helm repo add ingress-nginx https://kubernetes.github.io/ingress-nginx +helm repo update +helm install ingress-nginx ingress-nginx/ingress-nginx +``` + +Wait until Kubernetes assigns an external IP to the Ingress. + +```console +until [ -n "$(kubectl get service ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}')" ]; do sleep 1; done +``` + +Store the Ingress IP address Kubernetes assigned to our Ingress; this will be needed later when we configure the validation pipeline for our TLS certs. + +```console +kubectl get service ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}' +export INGRESSIP=$(kubectl get service ingress-nginx-controller -o jsonpath='{.status.loadBalancer.ingress[0].ip}') +export INGRESSIP=$(echo $INGRESSIP | sed 's/\./-/g') +``` + +### Cert manager + +We use the official [cert-manager](https://cert-manager.io) to automate TLS certificate management. + +Add the Helm repository, which contains the cert-manager Helm chart, and install the charts: + +```console +helm repo add cert-manager https://charts.jetstack.io +helm repo update +helm install cert-manager jetstack/cert-manager --namespace cert-manager \ + --create-namespace --set global.leaderElection.namespace=cert-manager \ + --set crds.enabled=true --timeout 600s +``` + +At this point we have all the necessary boilerplate set up to automate TLS issuance for Janus. + +### STUNner + +Now comes the fun part. The simplest way to run this demo is to clone the [STUNner git repository](https://github.com/l7mp/stunner) and deploy (after some minor modifications) the [manifest](janus-server.yaml) packaged with STUNner. + +Install the STUNner gateway operator and STUNner via [Helm](https://github.com/l7mp/stunner-helm): + +```console +helm repo add stunner https://l7mp.io/stunner +helm repo update +helm install stunner-gateway-operator stunner/stunner-gateway-operator --create-namespace --namespace=stunner +``` + +Configure STUNner to act as a STUN/TURN server to clients, and route all received media to the Janus Gateway pods. + +```console +git clone https://github.com/l7mp/stunner +cd stunner +kubectl apply -f docs/examples/janus/janus-call-stunner.yaml +``` + +The relevant parts here are the STUNner [Gateway definition](../../GATEWAY.md#gateway), which exposes the STUNner STUN/TURN server over UDP:3478 to the Internet, and the [UDPRoute definition](../../GATEWAY.md#udproute), which takes care of routing media to the pods running the Janus Gateway service. + +```yaml +apiVersion: gateway.networking.k8s.io/v1 +kind: Gateway +metadata: + name: udp-gateway + namespace: stunner +spec: + gatewayClassName: stunner-gatewayclass + listeners: + - name: udp-listener + port: 3478 + protocol: UDP +--- +apiVersion: stunner.l7mp.io/v1 +kind: UDPRoute +metadata: + name: janus + namespace: stunner +spec: + parentRefs: + - name: udp-gateway + rules: + - backendRefs: + - kind: Service + name: janus-gateway + namespace: default +``` + +Once the Gateway resource is installed into Kubernetes, STUNner will create a Kubernetes LoadBalancer for the Gateway to expose the TURN server on UDP:3478 to clients. It can take up to a minute for Kubernetes to allocate a public external IP for the service. + +Wait until Kubernetes assigns an external IP and store the external IP assigned by Kubernetes to +STUNner in an environment variable for later use. + +```console +until [ -n "$(kubectl get svc udp-gateway -n stunner -o jsonpath='{.status.loadBalancer.ingress[0].ip}')" ]; do sleep 1; done +export STUNNERIP=$(kubectl get service udp-gateway -n stunner -o jsonpath='{.status.loadBalancer.ingress[0].ip}') +``` + +### Janus + +The crucial step of integrating *any* WebRTC media server with STUNner is to ensure that the server instructs the clients to use STUNner as the STUN/TURN server. In order to achieve this, first we patch the public IP address of the STUNner STUN/TURN server we have learned above into our Janus Web and Gateway deployment manifests: + +```console +sed -i "s/stunner_ip/$STUNNERIP/g" docs/examples/janus/janus-server.yaml +``` + +Janus Web tells the connected clients where to look for the Janus Gateway server and which ICE servers should be used for ICE negotiation. Assuming that Kubernetes assigns the IP address 1.2.3.4 to STUNner (i.e., `STUNNERIP=1.2.3.4`), the relevant part of the Janus Web config would be something like the below: + +```yaml +... + settings.js: | + var server = "wss://server-$INGRESSIP.nip.io" + var iceServers = [{urls: "turn:1.2.3.4:3478?transport=udp", username: "user-1", credential: "pass-1"}] +``` + +This will make sure that Janus Web tells the clients to use STUNner as the STUN/TURN server. If unsure about the STUNner settings to use, you can always use the handy [`stunnerctl` CLI tool](/cmd/stunnerctl/README.md) to dump the running STUNner configuration. + +``` console +stunnerctl -n stunner config udp-gateway +Gateway: stunner/udp-gateway (loglevel: "all:INFO") +Authentication type: static, username/password: user-1/pass-1 +Listeners: + - Name: stunner/udp-gateway/udp-listener + Protocol: TURN-UDP + Public address:port: 34.118.88.91:3478 + Routes: [stunner/iperf-server] + Endpoints: [10.76.1.4, 10.80.4.47] +``` + +Note that Janus itself will not use STUNner (that would amount to a less efficient [symmetric ICE mode](../../DEPLOYMENT.md)); with the above configuration we are just telling Janus Web to instruct its clients to use STUNner to reach the Janus Gateway server. + +We also need the Ingress external IP address we have stored previously: this will make sure that the TLS certificate created by cert-manager will be bound to the proper `nip.io` domain and IP address. + +```console +sed -i "s/ingressserviceip/$INGRESSIP/g" docs/examples/janus/janus-server.yaml +``` + +Finally, fire up Janus. + +```console +kubectl apply -f docs/examples/janus/janus-server.yaml +``` + +The demo installation bundle includes a lot of resources to deploy Janus: + +- a Janus Gateway server, +- a web server serving the landing page using [Janus Web Demos](https://github.com/meetecho/janus-gateway/tree/master/html) +- a cluster issuer for the TLS certificates, +- an Ingress resource to terminate the secure connections between your browser and the Kubernetes cluster. + +Wait until all pods become operational and jump right into testing! + +## Test + +After installing everything, execute the following command to retrieve the URL of your fresh Janus demo app: + +```console +echo client-$INGRESSIP.nip.io +``` + +Copy the URL into your browser, and now you should be greeted with the About page. On the landing page navigate to the Video call plugin demo (`/demos/videocall.html`). Duplicate the tab and register two users in the system and make a call. If everything is set up correctly, you should be able to connect to a room. If you repeat the procedure in a separate browser tab you can enjoy a nice video-conferencing session with yourself, with the twist that all media between the browser tabs is flowing through STUNner and the Janus Gateway server deployed in you Kubernetes cluster. From c6820a60cc0f22d994268d2bf6391fcd05904177 Mon Sep 17 00:00:00 2001 From: Kornel David Date: Mon, 23 Sep 2024 21:53:35 +0200 Subject: [PATCH 5/7] docs(/example/janus): Small changes to the README --- docs/examples/janus/README.md | 14 ++++++++++---- 1 file changed, 10 insertions(+), 4 deletions(-) diff --git a/docs/examples/janus/README.md b/docs/examples/janus/README.md index c014699..fbb33c5 100644 --- a/docs/examples/janus/README.md +++ b/docs/examples/janus/README.md @@ -27,9 +27,11 @@ In this tutorial we deploy [Janus Gateway](https://github.com/meetecho/janus-gat ## Installation -Let's start with a disclaimer. The Janus client-side application must work over a secure HTTPS connection, because [getUserMedia](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#browser_compatibility) is available only in secure contexts. This implies that the client-server signaling connection must be secure too. In this demo, we will aim to obtain a proper CA-signed certificate (self-signed certificates haven't been tested). Obtaining a valid TLS certificate is a challenge. Thus, the majority of the below installation guide will be about securing client connections to Janus over TLS; as it turns out, once HTTPS is correctly working integrating Janus with STUNner is very simple. +> [!NOTE] +> +> Let's start with a disclaimer. The Janus client-side application must work over a secure HTTPS connection, because [getUserMedia](https://developer.mozilla.org/en-US/docs/Web/API/MediaDevices/getUserMedia#browser_compatibility) is available only in secure contexts. This implies that the client-server signaling connection must be secure too. In this demo, we will aim to obtain a proper CA-signed certificate (self-signed certificates haven't been tested). Obtaining a valid TLS certificate is a challenge. Thus, the majority of the below installation guide will be about securing client connections to Janus over TLS; as it turns out, once HTTPS is correctly working integrating Janus with STUNner is very simple. -In the below example, STUNner will be installed into the identically named namespace, while Janus and the Ingress gateway will live in the default namespace. +In the below example, STUNner will be installed into the identically named namespace (`stunner`), while Janus and the Ingress gateway will live in the `default` namespace. ### TLS certificates @@ -170,7 +172,7 @@ Listeners: Endpoints: [10.76.1.4, 10.80.4.47] ``` -Note that Janus itself will not use STUNner (that would amount to a less efficient [symmetric ICE mode](../../DEPLOYMENT.md)); with the above configuration we are just telling Janus Web to instruct its clients to use STUNner to reach the Janus Gateway server. +Note that Janus itself will not use STUNner as a TURN server (that would amount to a less efficient [symmetric ICE mode](../../DEPLOYMENT.md)); with the above configuration we are just telling Janus Web to instruct its clients to use STUNner to reach the Janus Gateway server. We also need the Ingress external IP address we have stored previously: this will make sure that the TLS certificate created by cert-manager will be bound to the proper `nip.io` domain and IP address. @@ -195,10 +197,14 @@ Wait until all pods become operational and jump right into testing! ## Test -After installing everything, execute the following command to retrieve the URL of your fresh Janus demo app: +After installing everything, execute the following command to retrieve the URL of your freshly deployed Janus demo app: ```console echo client-$INGRESSIP.nip.io ``` Copy the URL into your browser, and now you should be greeted with the About page. On the landing page navigate to the Video call plugin demo (`/demos/videocall.html`). Duplicate the tab and register two users in the system and make a call. If everything is set up correctly, you should be able to connect to a room. If you repeat the procedure in a separate browser tab you can enjoy a nice video-conferencing session with yourself, with the twist that all media between the browser tabs is flowing through STUNner and the Janus Gateway server deployed in you Kubernetes cluster. + +# Help + +STUNner development is coordinated in Discord, feel free to [join](https://discord.gg/DyPgEsbwzc). \ No newline at end of file From 060eaf827ec7849f6a15031395c5d80d94b21207 Mon Sep 17 00:00:00 2001 From: Kornel David Date: Mon, 23 Sep 2024 22:13:34 +0200 Subject: [PATCH 6/7] docs(/example/janus): Add Dockerfiles and Docker images section to README --- docs/examples/janus/DOCKERFILE-janus-gateway | 123 +++++++++++++++++++ docs/examples/janus/DOCKERFILE-janus-web | 2 + docs/examples/janus/README.md | 5 + 3 files changed, 130 insertions(+) create mode 100644 docs/examples/janus/DOCKERFILE-janus-gateway create mode 100644 docs/examples/janus/DOCKERFILE-janus-web diff --git a/docs/examples/janus/DOCKERFILE-janus-gateway b/docs/examples/janus/DOCKERFILE-janus-gateway new file mode 100644 index 0000000..08b214b --- /dev/null +++ b/docs/examples/janus/DOCKERFILE-janus-gateway @@ -0,0 +1,123 @@ +FROM debian:bullseye-slim + +RUN apt-get -y update && \ + apt-get install -y \ + libavutil-dev \ + libavformat-dev \ + libavcodec-dev \ + libmicrohttpd-dev \ + libjansson-dev \ + libssl-dev \ + libsofia-sip-ua-dev \ + libglib2.0-dev \ + libopus-dev \ + libogg-dev \ + libcurl4-openssl-dev \ + liblua5.3-dev \ + libconfig-dev \ + libusrsctp-dev \ + libwebsockets-dev \ + libnanomsg-dev \ + librabbitmq-dev \ + pkg-config \ + gengetopt \ + libtool \ + automake \ + build-essential \ + wget \ + git \ + gtk-doc-tools && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + + +RUN cd /tmp && \ + wget https://github.com/cisco/libsrtp/archive/v2.3.0.tar.gz && \ + tar xfv v2.3.0.tar.gz && \ + cd libsrtp-2.3.0 && \ + ./configure --prefix=/usr --enable-openssl && \ + make shared_library && \ + make install + +RUN cd /tmp && \ + git clone https://gitlab.freedesktop.org/libnice/libnice && \ + cd libnice && \ + git checkout 0.1.17 && \ + ./autogen.sh && \ + ./configure --prefix=/usr && \ + make && \ + make install + +COPY . /usr/local/src/janus-gateway + +RUN cd /usr/local/src/janus-gateway && \ + sh autogen.sh && \ + ./configure --enable-post-processing --prefix=/usr/local && \ + make && \ + make install && \ + make configs + +FROM debian:bullseye-slim + +ARG BUILD_DATE="undefined" +ARG GIT_BRANCH="undefined" +ARG GIT_COMMIT="undefined" +ARG VERSION="undefined" + +LABEL build_date=${BUILD_DATE} +LABEL git_branch=${GIT_BRANCH} +LABEL git_commit=${GIT_COMMIT} +LABEL version=${VERSION} + +RUN apt-get -y update && \ + apt-get install -y \ + libmicrohttpd12 \ + libavutil-dev \ + libavformat-dev \ + libavcodec-dev \ + libjansson4 \ + libssl1.1 \ + libsofia-sip-ua0 \ + libglib2.0-0 \ + libopus0 \ + libogg0 \ + libcurl4 \ + liblua5.3-0 \ + libconfig9 \ + libusrsctp1 \ + libwebsockets16 \ + libnanomsg5 \ + librabbitmq4 && \ + apt-get clean && \ + rm -rf /var/lib/apt/lists/* + +COPY --from=0 /usr/lib/libsrtp2.so.1 /usr/lib/libsrtp2.so.1 +RUN ln -s /usr/lib/libsrtp2.so.1 /usr/lib/libsrtp2.so + +COPY --from=0 /usr/lib/libnice.la /usr/lib/libnice.la +COPY --from=0 /usr/lib/libnice.so.10.10.0 /usr/lib/libnice.so.10.10.0 +RUN ln -s /usr/lib/libnice.so.10.10.0 /usr/lib/libnice.so.10 +RUN ln -s /usr/lib/libnice.so.10.10.0 /usr/lib/libnice.so + +COPY --from=0 /usr/local/bin/janus /usr/local/bin/janus +COPY --from=0 /usr/local/bin/janus-pp-rec /usr/local/bin/janus-pp-rec +COPY --from=0 /usr/local/bin/janus-cfgconv /usr/local/bin/janus-cfgconv +COPY --from=0 /usr/local/etc/janus /usr/local/etc/janus +COPY --from=0 /usr/local/lib/janus /usr/local/lib/janus +COPY --from=0 /usr/local/share/janus /usr/local/share/janus + +ENV BUILD_DATE=${BUILD_DATE} +ENV GIT_BRANCH=${GIT_BRANCH} +ENV GIT_COMMIT=${GIT_COMMIT} +ENV VERSION=${VERSION} + +EXPOSE 10000-10200/udp +EXPOSE 8188 +EXPOSE 8088 +EXPOSE 8089 +EXPOSE 8889 +EXPOSE 8000 +EXPOSE 7088 +EXPOSE 7089 + +CMD ["/usr/local/bin/janus"] \ No newline at end of file diff --git a/docs/examples/janus/DOCKERFILE-janus-web b/docs/examples/janus/DOCKERFILE-janus-web new file mode 100644 index 0000000..7aa5364 --- /dev/null +++ b/docs/examples/janus/DOCKERFILE-janus-web @@ -0,0 +1,2 @@ +FROM nginx:1.27.1 +COPY . /usr/share/nginx/html \ No newline at end of file diff --git a/docs/examples/janus/README.md b/docs/examples/janus/README.md index fbb33c5..7a60ff1 100644 --- a/docs/examples/janus/README.md +++ b/docs/examples/janus/README.md @@ -33,6 +33,11 @@ In this tutorial we deploy [Janus Gateway](https://github.com/meetecho/janus-gat In the below example, STUNner will be installed into the identically named namespace (`stunner`), while Janus and the Ingress gateway will live in the `default` namespace. +### Docker images + +Janus does not come with an official Docker image; thus, we built one using a self-made Dockerfile based on the available documents in the official [Janus repository](https://github.com/meetecho/janus-gateway). Actually, we've made two Dockerfiles. One for the Janus Gateway server and one for the Janus Web Demos. The [Janus Gateway server Dockerfile](./DOCKERFILE-janus-gateway) should be ran in the root directory of the [Janus repository](https://github.com/meetecho/janus-gateway). The Janus Web Demos Dockerfile should be used in the `/html` directory of the [same repository](https://github.com/meetecho/janus-gateway/tree/master/html). The images (`l7mp/janus-gateway:v1.2.4` and `l7mp/janus-web:latest`) used in the following demo are hosted on Docker Hub under the L7MP organization. + + ### TLS certificates As mentioned above, the Janus WebRTC server will need a valid TLS cert, which means it must run behind an existing DNS domain name backed by a CA signed TLS certificate. This is simple if you have your own domain, but if you don't then [nip.io](https://nip.io) provides a dead simple wildcard DNS for any IP address. We will use this to "own a domain" and obtain a CA signed certificate for Janus. This will allow us to point the domain name `client-.nip.io` to an ingress HTTP gateway in our Kubernetes cluster, which will then use some automation (namely, cert-manager) to obtain a valid CA signed cert. From 3cfd63afd6c53f790d8682c847dde0c11dabc380 Mon Sep 17 00:00:00 2001 From: Kornel David Date: Mon, 23 Sep 2024 23:02:59 +0200 Subject: [PATCH 7/7] docs(/example/janus): Add janus arch fig --- docs/examples/janus/README.md | 4 +--- docs/img/stunner_janus_arch.svg | 4 ++++ 2 files changed, 5 insertions(+), 3 deletions(-) create mode 100644 docs/img/stunner_janus_arch.svg diff --git a/docs/examples/janus/README.md b/docs/examples/janus/README.md index 7a60ff1..d7e87c5 100644 --- a/docs/examples/janus/README.md +++ b/docs/examples/janus/README.md @@ -17,11 +17,9 @@ The below installation instructions require an operational cluster running a sup The recommended way (or at least the possible way, [link](https://janus.discourse.group/t/janus-with-kubernetes-demystifying-the-myths/938), [link](https://bugraoz93.medium.com/active-passive-highly-availability-janus-gateway-on-kubernetes-2189256e5525)) to install Janus into Kubernetes is deploying the media servers into the host-network namespace of the Kubernetes nodes (`hostNetwork: true`). This deployment model, however, comes with a set of uncanny [operational limitations and security concerns](../../WHY.md). Using STUNner, however, media servers can be deployed into ordinary Kubernetes pods and run over a private IP network, like any "normal" Kubernetes workload. -![WARNING] TODO: figure - The figure below shows Janus deployed into regular Kubernetes pods behind STUNner without the host-networking hack. Here, Janus is deployed behind STUNner in the [*media-plane deployment model*](../../DEPLOYMENT.md), so that STUNner acts as a "local" STUN/TURN server for Janus, saving the overhead of using public a 3rd party STUN/TURN server for NAT traversal. -![STUNner Janus integration deployment architecture](../../img/stunner_janus.svg) +![STUNner Janus integration deployment architecture](../../img/stunner_janus_arch.svg) In this tutorial we deploy [Janus Gateway](https://github.com/meetecho/janus-gateway/tree/master) with a set of [preimplemented and packaged server plugins](https://janus.conf.meetecho.com/docs/pluginslist.html) for media exchange, a [Janus Web Demo](https://github.com/meetecho/janus-gateway/tree/master/html), a Kubernetes Ingress gateway to secure signaling connections and handle TLS, and STUNner as a media gateway to expose the Janus server pool to clients. diff --git a/docs/img/stunner_janus_arch.svg b/docs/img/stunner_janus_arch.svg new file mode 100644 index 0000000..a11d242 --- /dev/null +++ b/docs/img/stunner_janus_arch.svg @@ -0,0 +1,4 @@ + + + +
Kubernetes  cluster
HTTPS
Ingress
UDP/RTP
Secure WebSocket
(wss)
STUN/TURN
Janus Web Demo
\ No newline at end of file