├── .github └── workflows │ └── test.yaml ├── .gitignore ├── LICENSE ├── NOTICE ├── README.md ├── deploy-egress.sh ├── deploy-ingress.sh ├── deploy.sh ├── egress-sample.yaml ├── egress ├── .helmignore ├── Chart.yaml ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── configmap.yaml │ ├── deployment.yaml │ ├── hpa.yaml │ └── serviceaccount.yaml └── values.yaml ├── examples ├── egress.yaml ├── server-do.yaml ├── server-eks.yaml ├── server-gke-vpc-native.yaml └── server-gke.yaml ├── gclb-sample.yaml ├── ingress-sample.yaml ├── ingress ├── .helmignore ├── Chart.yaml ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── configmap.yaml │ ├── deployment.yaml │ ├── hpa.yaml │ ├── service.yaml │ └── serviceaccount.yaml └── values.yaml ├── livekit-server ├── .helmignore ├── Chart.yaml ├── templates │ ├── NOTES.txt │ ├── _helpers.tpl │ ├── backendconfig.yaml │ ├── configmap.yaml │ ├── deployment.yaml │ ├── hpa.yaml │ ├── ingress.yaml │ ├── secret.yaml │ ├── service.yaml │ ├── serviceaccount.yaml │ ├── servicemonitor.yaml │ ├── tests │ │ └── test-connection.yaml │ └── turnloadbalancer.yaml └── values.yaml └── server-sample.yaml /.github/workflows/test.yaml: -------------------------------------------------------------------------------- 1 | # based on: https://github.com/nats-io/k8s/blob/main/.github/workflows/test.yaml and https://github.com/helm/charts-repo-actions-demo/blob/main/.github/workflows/lint-test.yaml 2 | name: Lint, Install, and Test Charts 3 | 4 | on: 5 | workflow_dispatch: 6 | pull_request: 7 | paths: 8 | - 'ingress/**' 9 | - 'egress/**' 10 | - 'livekit-server/**' 11 | - '.github/workflows/test.yaml' 12 | 13 | jobs: 14 | lint-test: 15 | runs-on: ubuntu-latest 16 | strategy: 17 | fail-fast: false 18 | matrix: 19 | k8s: 20 | - "1.26" 21 | - "1.25" 22 | - "1.24" 23 | steps: 24 | - name: Checkout 25 | uses: actions/checkout@v4 26 | with: 27 | fetch-depth: 0 28 | 29 | - name: Set up Helm 30 | uses: azure/setup-helm@v3 31 | with: 32 | version: v3.11.2 33 | 34 | # Python is required because `ct lint` runs Yamale (https://github.com/23andMe/Yamale) and 35 | # yamllint (https://github.com/adrienverge/yamllint) which require Python 36 | - name: Set up Python 37 | uses: actions/setup-python@v5 38 | with: 39 | python-version: 3.9 40 | 41 | - name: Set up chart-testing 42 | uses: helm/chart-testing-action@v2.6.1 43 | 44 | - name: Run chart-testing (lint) 45 | run: |- 46 | ct lint \ 47 | --all \ 48 | --chart-dirs egress ingress livekit-server \ 49 | --validate-maintainers=false 50 | 51 | - name: Create k8s cluster 52 | run: |- 53 | sudo snap install microk8s --channel="${{ matrix.k8s }}/stable" --classic 54 | sudo microk8s.enable dns hostpath-storage 55 | sudo microk8s.kubectl wait --for=condition=ready --timeout=60s node --all 56 | sudo microk8s.kubectl wait --for=condition=ready --timeout=120s --namespace=kube-system pod --all 57 | mkdir -p ~/.kube 58 | sudo microk8s.config > ~/.kube/config 59 | chmod 600 ~/.kube/config 60 | 61 | - name: Run chart-testing (install) 62 | run: |- 63 | ct install \ 64 | --all \ 65 | --chart-dirs egress ingress livekit-server 66 | -------------------------------------------------------------------------------- /.gitignore: -------------------------------------------------------------------------------- 1 | build/ 2 | values 3 | .idea/ 4 | -------------------------------------------------------------------------------- /LICENSE: -------------------------------------------------------------------------------- 1 | 2 | Apache License 3 | Version 2.0, January 2004 4 | http://www.apache.org/licenses/ 5 | 6 | TERMS AND CONDITIONS FOR USE, REPRODUCTION, AND DISTRIBUTION 7 | 8 | 1. Definitions. 9 | 10 | "License" shall mean the terms and conditions for use, reproduction, 11 | and distribution as defined by Sections 1 through 9 of this document. 12 | 13 | "Licensor" shall mean the copyright owner or entity authorized by 14 | the copyright owner that is granting the License. 15 | 16 | "Legal Entity" shall mean the union of the acting entity and all 17 | other entities that control, are controlled by, or are under common 18 | control with that entity. For the purposes of this definition, 19 | "control" means (i) the power, direct or indirect, to cause the 20 | direction or management of such entity, whether by contract or 21 | otherwise, or (ii) ownership of fifty percent (50%) or more of the 22 | outstanding shares, or (iii) beneficial ownership of such entity. 23 | 24 | "You" (or "Your") shall mean an individual or Legal Entity 25 | exercising permissions granted by this License. 26 | 27 | "Source" form shall mean the preferred form for making modifications, 28 | including but not limited to software source code, documentation 29 | source, and configuration files. 30 | 31 | "Object" form shall mean any form resulting from mechanical 32 | transformation or translation of a Source form, including but 33 | not limited to compiled object code, generated documentation, 34 | and conversions to other media types. 35 | 36 | "Work" shall mean the work of authorship, whether in Source or 37 | Object form, made available under the License, as indicated by a 38 | copyright notice that is included in or attached to the work 39 | (an example is provided in the Appendix below). 40 | 41 | "Derivative Works" shall mean any work, whether in Source or Object 42 | form, that is based on (or derived from) the Work and for which the 43 | editorial revisions, annotations, elaborations, or other modifications 44 | represent, as a whole, an original work of authorship. For the purposes 45 | of this License, Derivative Works shall not include works that remain 46 | separable from, or merely link (or bind by name) to the interfaces of, 47 | the Work and Derivative Works thereof. 48 | 49 | "Contribution" shall mean any work of authorship, including 50 | the original version of the Work and any modifications or additions 51 | to that Work or Derivative Works thereof, that is intentionally 52 | submitted to Licensor for inclusion in the Work by the copyright owner 53 | or by an individual or Legal Entity authorized to submit on behalf of 54 | the copyright owner. For the purposes of this definition, "submitted" 55 | means any form of electronic, verbal, or written communication sent 56 | to the Licensor or its representatives, including but not limited to 57 | communication on electronic mailing lists, source code control systems, 58 | and issue tracking systems that are managed by, or on behalf of, the 59 | Licensor for the purpose of discussing and improving the Work, but 60 | excluding communication that is conspicuously marked or otherwise 61 | designated in writing by the copyright owner as "Not a Contribution." 62 | 63 | "Contributor" shall mean Licensor and any individual or Legal Entity 64 | on behalf of whom a Contribution has been received by Licensor and 65 | subsequently incorporated within the Work. 66 | 67 | 2. Grant of Copyright License. Subject to the terms and conditions of 68 | this License, each Contributor hereby grants to You a perpetual, 69 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 70 | copyright license to reproduce, prepare Derivative Works of, 71 | publicly display, publicly perform, sublicense, and distribute the 72 | Work and such Derivative Works in Source or Object form. 73 | 74 | 3. Grant of Patent License. Subject to the terms and conditions of 75 | this License, each Contributor hereby grants to You a perpetual, 76 | worldwide, non-exclusive, no-charge, royalty-free, irrevocable 77 | (except as stated in this section) patent license to make, have made, 78 | use, offer to sell, sell, import, and otherwise transfer the Work, 79 | where such license applies only to those patent claims licensable 80 | by such Contributor that are necessarily infringed by their 81 | Contribution(s) alone or by combination of their Contribution(s) 82 | with the Work to which such Contribution(s) was submitted. If You 83 | institute patent litigation against any entity (including a 84 | cross-claim or counterclaim in a lawsuit) alleging that the Work 85 | or a Contribution incorporated within the Work constitutes direct 86 | or contributory patent infringement, then any patent licenses 87 | granted to You under this License for that Work shall terminate 88 | as of the date such litigation is filed. 89 | 90 | 4. Redistribution. You may reproduce and distribute copies of the 91 | Work or Derivative Works thereof in any medium, with or without 92 | modifications, and in Source or Object form, provided that You 93 | meet the following conditions: 94 | 95 | (a) You must give any other recipients of the Work or 96 | Derivative Works a copy of this License; and 97 | 98 | (b) You must cause any modified files to carry prominent notices 99 | stating that You changed the files; and 100 | 101 | (c) You must retain, in the Source form of any Derivative Works 102 | that You distribute, all copyright, patent, trademark, and 103 | attribution notices from the Source form of the Work, 104 | excluding those notices that do not pertain to any part of 105 | the Derivative Works; and 106 | 107 | (d) If the Work includes a "NOTICE" text file as part of its 108 | distribution, then any Derivative Works that You distribute must 109 | include a readable copy of the attribution notices contained 110 | within such NOTICE file, excluding those notices that do not 111 | pertain to any part of the Derivative Works, in at least one 112 | of the following places: within a NOTICE text file distributed 113 | as part of the Derivative Works; within the Source form or 114 | documentation, if provided along with the Derivative Works; or, 115 | within a display generated by the Derivative Works, if and 116 | wherever such third-party notices normally appear. The contents 117 | of the NOTICE file are for informational purposes only and 118 | do not modify the License. You may add Your own attribution 119 | notices within Derivative Works that You distribute, alongside 120 | or as an addendum to the NOTICE text from the Work, provided 121 | that such additional attribution notices cannot be construed 122 | as modifying the License. 123 | 124 | You may add Your own copyright statement to Your modifications and 125 | may provide additional or different license terms and conditions 126 | for use, reproduction, or distribution of Your modifications, or 127 | for any such Derivative Works as a whole, provided Your use, 128 | reproduction, and distribution of the Work otherwise complies with 129 | the conditions stated in this License. 130 | 131 | 5. Submission of Contributions. Unless You explicitly state otherwise, 132 | any Contribution intentionally submitted for inclusion in the Work 133 | by You to the Licensor shall be under the terms and conditions of 134 | this License, without any additional terms or conditions. 135 | Notwithstanding the above, nothing herein shall supersede or modify 136 | the terms of any separate license agreement you may have executed 137 | with Licensor regarding such Contributions. 138 | 139 | 6. Trademarks. This License does not grant permission to use the trade 140 | names, trademarks, service marks, or product names of the Licensor, 141 | except as required for reasonable and customary use in describing the 142 | origin of the Work and reproducing the content of the NOTICE file. 143 | 144 | 7. Disclaimer of Warranty. Unless required by applicable law or 145 | agreed to in writing, Licensor provides the Work (and each 146 | Contributor provides its Contributions) on an "AS IS" BASIS, 147 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or 148 | implied, including, without limitation, any warranties or conditions 149 | of TITLE, NON-INFRINGEMENT, MERCHANTABILITY, or FITNESS FOR A 150 | PARTICULAR PURPOSE. You are solely responsible for determining the 151 | appropriateness of using or redistributing the Work and assume any 152 | risks associated with Your exercise of permissions under this License. 153 | 154 | 8. Limitation of Liability. In no event and under no legal theory, 155 | whether in tort (including negligence), contract, or otherwise, 156 | unless required by applicable law (such as deliberate and grossly 157 | negligent acts) or agreed to in writing, shall any Contributor be 158 | liable to You for damages, including any direct, indirect, special, 159 | incidental, or consequential damages of any character arising as a 160 | result of this License or out of the use or inability to use the 161 | Work (including but not limited to damages for loss of goodwill, 162 | work stoppage, computer failure or malfunction, or any and all 163 | other commercial damages or losses), even if such Contributor 164 | has been advised of the possibility of such damages. 165 | 166 | 9. Accepting Warranty or Additional Liability. While redistributing 167 | the Work or Derivative Works thereof, You may choose to offer, 168 | and charge a fee for, acceptance of support, warranty, indemnity, 169 | or other liability obligations and/or rights consistent with this 170 | License. However, in accepting such obligations, You may act only 171 | on Your own behalf and on Your sole responsibility, not on behalf 172 | of any other Contributor, and only if You agree to indemnify, 173 | defend, and hold each Contributor harmless for any liability 174 | incurred by, or claims asserted against, such Contributor by reason 175 | of your accepting any such warranty or additional liability. 176 | 177 | END OF TERMS AND CONDITIONS 178 | 179 | APPENDIX: How to apply the Apache License to your work. 180 | 181 | To apply the Apache License to your work, attach the following 182 | boilerplate notice, with the fields enclosed by brackets "[]" 183 | replaced with your own identifying information. (Don't include 184 | the brackets!) The text should be enclosed in the appropriate 185 | comment syntax for the file format. We also recommend that a 186 | file or class name and description of purpose be included on the 187 | same "printed page" as the copyright notice for easier 188 | identification within third-party archives. 189 | 190 | Copyright [yyyy] [name of copyright owner] 191 | 192 | Licensed under the Apache License, Version 2.0 (the "License"); 193 | you may not use this file except in compliance with the License. 194 | You may obtain a copy of the License at 195 | 196 | http://www.apache.org/licenses/LICENSE-2.0 197 | 198 | Unless required by applicable law or agreed to in writing, software 199 | distributed under the License is distributed on an "AS IS" BASIS, 200 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 201 | See the License for the specific language governing permissions and 202 | limitations under the License. 203 | -------------------------------------------------------------------------------- /NOTICE: -------------------------------------------------------------------------------- 1 | Copyright 2021 LiveKit, Inc. 2 | 3 | Licensed under the Apache License, Version 2.0 (the "License"); 4 | you may not use this file except in compliance with the License. 5 | You may obtain a copy of the License at 6 | 7 | http://www.apache.org/licenses/LICENSE-2.0 8 | 9 | Unless required by applicable law or agreed to in writing, software 10 | distributed under the License is distributed on an "AS IS" BASIS, 11 | WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. 12 | See the License for the specific language governing permissions and 13 | limitations under the License. 14 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | 2 | LiveKit's helm charts are published on S3. 3 | 4 | ## Installing helm 5 | 6 | Add it to your helm repo with: 7 | 8 | ```shell 9 | helm repo add livekit https://helm.livekit.io 10 | ``` 11 | 12 | Customize values in values-sample.yaml 13 | 14 | Then install the chart 15 | 16 | ```shell 17 | helm install livekit/livekit-server --namespace --values values.yaml 18 | ``` 19 | 20 | ## For LiveKit Helm developers 21 | 22 | Publishing requires helm-s3 plugin 23 | 24 | ```shell 25 | helm plugin install https://github.com/hypnoglow/helm-s3.git 26 | AWS_REGION=us-east-1 helm repo add livekit s3://livekit-helm 27 | 28 | ./deploy.sh 29 | ``` 30 | -------------------------------------------------------------------------------- /deploy-egress.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -euxo pipefail 4 | 5 | rm -rf build 6 | mkdir -p build 7 | helm package egress --destination build 8 | cd build 9 | AWS_REGION=us-east-1 helm s3 push --relative ./egress*.tgz livekit 10 | 11 | aws cloudfront create-invalidation --distribution-id E2MJ94T12TAUZU --paths "/*" 12 | -------------------------------------------------------------------------------- /deploy-ingress.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -euxo pipefail 4 | 5 | rm -rf build 6 | mkdir -p build 7 | helm package ingress --destination build 8 | cd build 9 | AWS_REGION=us-east-1 helm s3 push --relative ./ingress*.tgz livekit 10 | 11 | aws cloudfront create-invalidation --distribution-id E2MJ94T12TAUZU --paths "/*" 12 | -------------------------------------------------------------------------------- /deploy.sh: -------------------------------------------------------------------------------- 1 | #!/bin/sh 2 | 3 | set -euxo pipefail 4 | 5 | rm -rf build 6 | mkdir -p build 7 | helm package livekit-server --destination build 8 | cd build 9 | AWS_REGION=us-east-1 helm s3 push --relative ./livekit-server*.tgz livekit 10 | 11 | aws cloudfront create-invalidation --distribution-id E2MJ94T12TAUZU --paths "/*" 12 | -------------------------------------------------------------------------------- /egress-sample.yaml: -------------------------------------------------------------------------------- 1 | replicaCount: 1 2 | 3 | # Suggested value for gracefully terminate the pod: 1 hour 4 | terminationGracePeriodSeconds: 3600 5 | 6 | egress: 7 | api_key: "server-api-key" 8 | api_secret: "server-api-secret" 9 | ws_url: "ws://livekit-host:" 10 | log_level: info 11 | health_port: 8080 12 | prometheus_port: 9090 13 | enable_chrome_sandbox: true 14 | # template_base: "https://your-custom-template.com" 15 | redis: 16 | address: 17 | # db: 0 18 | # username: 19 | # password: 20 | # use_tls: false 21 | s3: 22 | access_key: "access_key" 23 | secret: "secret" 24 | region: "us-west-2" 25 | # endpoint: 26 | bucket: "my-egress" 27 | # azure: 28 | # account_name: 29 | # account_key: 30 | # container_name: 31 | # gcp: 32 | # credentials_json: 33 | # bucket: 34 | # cpu_cost: 35 | # room_composite_cpu_cost: 3 36 | # track_composite_cpu_cost: 2 37 | # track_cpu_cost: 1 38 | 39 | # autoscaling requires resources to be defined 40 | autoscaling: 41 | # set to true to enable autoscaling. when set, ignores replicaCount 42 | enabled: false 43 | minReplicas: 1 44 | maxReplicas: 5 45 | targetCPUUtilizationPercentage: 60 46 | # targetMemoryUtilizationPercentage: 60 47 | # for use with prometheus adapter - the egress service outputs a prometheus metric called livekit_egress_available 48 | # this can be used to ensure a certain number or percentage of instances are available 49 | # custom: 50 | # metricName: my_metric_name 51 | # targetAverageValue: 70 52 | 53 | # if egress should run only on specific nodes 54 | # this can be used to isolate designated nodes 55 | nodeSelector: {} 56 | # node.kubernetes.io/instance-type: c5.2xlarge 57 | 58 | resources: {} 59 | # requests: 60 | # cpu: 5000m 61 | # memory: 1024Mi 62 | # limits: 63 | # cpu: 8000m 64 | # memory: 2048Mi 65 | 66 | serviceAccount: 67 | # Specifies whether a service account should be created 68 | create: false 69 | # Annotations to add to the service account 70 | annotations: {} 71 | # The name of the service account to use. 72 | # If not set and create is true, a name is generated using the fullname template 73 | name: "" 74 | 75 | podAnnotations: 76 | sidecar.istio.io/inject: "false" 77 | linkerd.io/inject: disabled 78 | 79 | podSecurityContext: {} 80 | # fsGroup: 2000 81 | 82 | securityContext: {} 83 | # capabilities: 84 | # drop: 85 | # - ALL 86 | # readOnlyRootFilesystem: true 87 | # runAsNonRoot: true 88 | # runAsUser: 1000 89 | 90 | tolerations: [] 91 | 92 | affinity: {} 93 | -------------------------------------------------------------------------------- /egress/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /egress/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: egress 3 | description: Egress is used by LiveKit to stream and record rooms. 4 | type: application 5 | version: 1.9.0 6 | appVersion: "v1.9.0" 7 | 8 | sources: 9 | - https://github.com/livekit/egress 10 | -------------------------------------------------------------------------------- /egress/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | 3 | LiveKit Egress {{ .Values.image.tag | default .Chart.AppVersion }} has been deployed! 4 | 5 | ------------------------------------------------------------------------------- 6 | -------------------------------------------------------------------------------- /egress/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "egress.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "egress.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "egress.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "egress.labels" -}} 37 | helm.sh/chart: {{ include "egress.chart" . }} 38 | {{ include "egress.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "egress.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "egress.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | {{/* 54 | Create the name of the service account to use 55 | */}} 56 | {{- define "egress.serviceAccountName" -}} 57 | {{- if .Values.serviceAccount.create }} 58 | {{- default (include "egress.fullname" .) .Values.serviceAccount.name }} 59 | {{- else }} 60 | {{- default "default" .Values.serviceAccount.name }} 61 | {{- end }} 62 | {{- end }} 63 | -------------------------------------------------------------------------------- /egress/templates/configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: {{ include "egress.fullname" . }} 5 | data: 6 | config.yaml: | 7 | {{ toYaml .Values.egress | indent 4 }} 8 | -------------------------------------------------------------------------------- /egress/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "egress.fullname" . }} 5 | labels: 6 | {{- include "egress.labels" . | nindent 4 }} 7 | spec: 8 | {{- if not .Values.autoscaling.enabled }} 9 | replicas: {{ .Values.replicaCount }} 10 | {{- end }} 11 | selector: 12 | matchLabels: 13 | {{- include "egress.selectorLabels" . | nindent 6 }} 14 | template: 15 | metadata: 16 | {{- with .Values.podAnnotations }} 17 | annotations: 18 | {{- toYaml . | nindent 8 }} 19 | {{- end }} 20 | checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} 21 | labels: 22 | {{- include "egress.selectorLabels" . | nindent 8 }} 23 | spec: 24 | serviceAccountName: {{ include "egress.serviceAccountName" . }} 25 | securityContext: 26 | {{- toYaml .Values.podSecurityContext | nindent 8 }} 27 | terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} 28 | containers: 29 | - name: {{ .Chart.Name }} 30 | securityContext: 31 | {{- toYaml .Values.securityContext | nindent 12 }} 32 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" 33 | imagePullPolicy: {{ .Values.image.pullPolicy }} 34 | env: 35 | - name: EGRESS_CONFIG_BODY 36 | valueFrom: 37 | configMapKeyRef: 38 | name: {{ include "egress.fullname" . }} 39 | key: config.yaml 40 | ports: 41 | {{- if .Values.egress.health_port }} 42 | - name: health 43 | containerPort: {{ .Values.egress.health_port }} 44 | protocol: TCP 45 | {{- end }} 46 | {{- if .Values.egress.prometheus_port }} 47 | - name: metrics 48 | containerPort: {{ .Values.egress.prometheus_port }} 49 | protocol: TCP 50 | {{- end }} 51 | livenessProbe: 52 | httpGet: 53 | path: / 54 | port: health 55 | readinessProbe: 56 | httpGet: 57 | path: / 58 | port: health 59 | resources: 60 | {{- toYaml .Values.resources | nindent 12 }} 61 | {{- with .Values.nodeSelector }} 62 | nodeSelector: 63 | {{- toYaml . | nindent 8 }} 64 | {{- end }} 65 | {{- with .Values.affinity }} 66 | affinity: 67 | {{- toYaml . | nindent 8 }} 68 | {{- end }} 69 | {{- with .Values.tolerations }} 70 | tolerations: 71 | {{- toYaml . | nindent 8 }} 72 | {{- end }} 73 | -------------------------------------------------------------------------------- /egress/templates/hpa.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.autoscaling.enabled }} 2 | {{- if semverCompare ">=1.23-0" .Capabilities.KubeVersion.GitVersion }} 3 | apiVersion: autoscaling/v2 4 | {{- else }} 5 | apiVersion: autoscaling/v2beta1 6 | {{- end }} 7 | kind: HorizontalPodAutoscaler 8 | metadata: 9 | name: {{ include "egress.fullname" . }} 10 | labels: 11 | {{- include "egress.labels" . | nindent 4 }} 12 | spec: 13 | scaleTargetRef: 14 | apiVersion: apps/v1 15 | kind: Deployment 16 | name: {{ include "egress.fullname" . }} 17 | minReplicas: {{ .Values.autoscaling.minReplicas }} 18 | maxReplicas: {{ .Values.autoscaling.maxReplicas }} 19 | metrics: 20 | {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} 21 | - type: Resource 22 | resource: 23 | name: cpu 24 | {{- if semverCompare ">=1.23-0" .Capabilities.KubeVersion.GitVersion }} 25 | target: 26 | type: Utilization 27 | averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} 28 | {{- else }} 29 | targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} 30 | {{- end }} 31 | {{- end }} 32 | {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} 33 | - type: Resource 34 | resource: 35 | name: memory 36 | {{- if semverCompare ">=1.23-0" .Capabilities.KubeVersion.GitVersion }} 37 | target: 38 | type: Utilization 39 | averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} 40 | {{- else }} 41 | targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} 42 | {{- end }} 43 | {{- end }} 44 | {{- if .Values.autoscaling.custom }} 45 | - type: Pods 46 | pods: 47 | {{- if semverCompare ">=1.23-0" .Capabilities.KubeVersion.GitVersion }} 48 | metric: 49 | name: {{ .Values.autoscaling.custom.metricName }} 50 | target: 51 | type: AverageValue 52 | averageValue: {{ .Values.autoscaling.custom.targetAverageValue }} 53 | {{- else }} 54 | metricName: {{ .Values.autoscaling.custom.metricName }} 55 | targetAverageValue: {{ .Values.autoscaling.custom.targetAverageValue }} 56 | {{- end }} 57 | {{- end }} 58 | {{- end }} 59 | -------------------------------------------------------------------------------- /egress/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "egress.serviceAccountName" . }} 6 | labels: 7 | {{- include "egress.labels" . | nindent 4 }} 8 | {{- with .Values.serviceAccount.annotations }} 9 | annotations: 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /egress/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for egress. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | 5 | replicaCount: 1 6 | 7 | image: 8 | repository: livekit/egress 9 | pullPolicy: IfNotPresent 10 | 11 | egress: 12 | log_level: info 13 | health_port: 8080 14 | prometheus_port: 9090 15 | 16 | terminationGracePeriodSeconds: 3600 17 | 18 | nameOverride: "" 19 | fullnameOverride: "" 20 | 21 | autoscaling: 22 | enabled: false 23 | 24 | nodeSelector: {} 25 | 26 | resources: {} 27 | 28 | serviceAccount: 29 | create: false 30 | annotations: {} 31 | name: "" 32 | 33 | podAnnotations: 34 | sidecar.istio.io/inject: "false" 35 | linkerd.io/inject: disabled 36 | 37 | podSecurityContext: {} 38 | 39 | securityContext: {} 40 | 41 | tolerations: [] 42 | 43 | affinity: {} 44 | -------------------------------------------------------------------------------- /examples/egress.yaml: -------------------------------------------------------------------------------- 1 | replicaCount: 2 2 | 3 | egress: 4 | ws_url: 5 | api_key: 6 | api_secret: 7 | log_level: info 8 | health_port: 8080 9 | prometheus_port: 9090 10 | redis: 11 | address: 12 | s3: 13 | access_key: 14 | secret: 15 | region: "us-west-2" 16 | bucket: "my-egress" 17 | -------------------------------------------------------------------------------- /examples/server-do.yaml: -------------------------------------------------------------------------------- 1 | replicaCount: 2 2 | 3 | # Refer to https://docs.livekit.io/deploy/kubernetes/ for instructions 4 | 5 | livekit: 6 | rtc: 7 | use_external_ip: true 8 | redis: 9 | address: :6379 10 | keys: 11 | : 12 | turn: 13 | enabled: true 14 | domain: 15 | tls_port: 3478 16 | secretName: 17 | 18 | loadBalancer: 19 | type: do 20 | # TLS certificate generated automatically with certmanager / letsencrypt 21 | # secretName is still required. certmanager will place the provisioned 22 | # certificate in that secret 23 | clusterIssuer: letsencrypt-prod 24 | tls: 25 | - hosts: 26 | - 27 | secretName: 28 | 29 | autoscaling: 30 | enabled: true 31 | minReplicas: 1 32 | maxReplicas: 5 33 | targetCPUUtilizationPercentage: 60 34 | 35 | # resources are set assuming a 8 core instance 36 | resources: 37 | limits: 38 | cpu: 7500m 39 | memory: 2048Mi 40 | requests: 41 | cpu: 7000m 42 | memory: 1024Mi 43 | -------------------------------------------------------------------------------- /examples/server-eks.yaml: -------------------------------------------------------------------------------- 1 | replicaCount: 2 2 | 3 | # Refer to https://docs.livekit.io/deploy/kubernetes/ for instructions 4 | 5 | livekit: 6 | rtc: 7 | use_external_ip: true 8 | redis: 9 | address: :6379 10 | keys: 11 | : 12 | turn: 13 | enabled: true 14 | domain: 15 | tls_port: 3478 16 | secretName: 17 | 18 | loadBalancer: 19 | # With ALB, TLS certificates are managed by ACM 20 | # Ensure you have issued a certificate for your domain in ACM 21 | type: alb 22 | tls: 23 | - hosts: 24 | - 25 | 26 | autoscaling: 27 | enabled: true 28 | minReplicas: 1 29 | maxReplicas: 5 30 | targetCPUUtilizationPercentage: 60 31 | 32 | # resources are set assuming a 8 core instance 33 | resources: 34 | limits: 35 | cpu: 7500m 36 | memory: 2048Mi 37 | requests: 38 | cpu: 7000m 39 | memory: 1024Mi 40 | -------------------------------------------------------------------------------- /examples/server-gke-vpc-native.yaml: -------------------------------------------------------------------------------- 1 | # Deploy LiveKit into a VPC-native GKE cluster 2 | # see https://cloud.google.com/kubernetes-engine/docs/concepts/alias-ips 3 | 4 | replicaCount: 2 5 | 6 | # Refer to https://docs.livekit.io/deploy/kubernetes/ for instructions 7 | 8 | livekit: 9 | rtc: 10 | use_external_ip: true 11 | redis: 12 | address: :6379 13 | keys: 14 | : 15 | turn: 16 | enabled: true 17 | domain: 18 | tls_port: 3478 19 | secretName: 20 | 21 | loadBalancer: 22 | type: gke-vpc-native 23 | tls: 24 | - hosts: 25 | - 26 | secretName: 27 | 28 | autoscaling: 29 | enabled: true 30 | minReplicas: 1 31 | maxReplicas: 5 32 | targetCPUUtilizationPercentage: 60 33 | 34 | # resources are set assuming a 8 core instance 35 | resources: 36 | limits: 37 | cpu: 7500m 38 | memory: 2048Mi 39 | requests: 40 | cpu: 7000m 41 | memory: 1024Mi 42 | -------------------------------------------------------------------------------- /examples/server-gke.yaml: -------------------------------------------------------------------------------- 1 | replicaCount: 2 2 | 3 | # Refer to https://docs.livekit.io/deploy/kubernetes/ for instructions 4 | 5 | livekit: 6 | rtc: 7 | use_external_ip: true 8 | redis: 9 | address: :6379 10 | keys: 11 | : 12 | turn: 13 | enabled: true 14 | domain: 15 | tls_port: 3478 16 | secretName: 17 | 18 | loadBalancer: 19 | type: gke 20 | tls: 21 | - hosts: 22 | - 23 | secretName: 24 | 25 | autoscaling: 26 | enabled: true 27 | minReplicas: 1 28 | maxReplicas: 5 29 | targetCPUUtilizationPercentage: 60 30 | 31 | # resources are set assuming a 8 core instance 32 | resources: 33 | limits: 34 | cpu: 7500m 35 | memory: 2048Mi 36 | requests: 37 | cpu: 7000m 38 | memory: 1024Mi 39 | -------------------------------------------------------------------------------- /gclb-sample.yaml: -------------------------------------------------------------------------------- 1 | # LiveKit Helm chart will set up a Deployment, Service, HPA, and Ingress as either 2 | # a single or multi-node LiveKit deployment. 3 | # After installing this chart, you would still need to 4 | # * Open ports on the firewall to the hosts (see https://docs.livekit.io/deploy/ports-firewall) 5 | # * Update DNS of hostnames to the ingress/service that were created 6 | 7 | replicaCount: 1 8 | 9 | # Suggested value for gracefully terminate the pod: 5 hours 10 | terminationGracePeriodSeconds: 18000 11 | 12 | livekit: 13 | # port: 7880 14 | # Uncomment to enable prometheus metrics 15 | # prometheus_port: 6789 16 | log_level: info 17 | rtc: 18 | use_external_ip: true 19 | # default ports used 20 | port_range_start: 50000 21 | port_range_end: 60000 22 | tcp_port: 7881 23 | redis: 24 | address: 25 | # db: 0 26 | # username: 27 | # password: 28 | # use_tls: true 29 | # one or more API key/secret pairs 30 | # see https://docs.livekit.io/guides/getting-started/#generate-api-key-and-secret 31 | keys: 32 | myapikey: "myapisecret" 33 | turn: 34 | enabled: true 35 | # must match domain of your TLS cert 36 | domain: turn.myhost.com 37 | # tls_port must be 443 if turn load balancer is disabled 38 | tls_port: 3478 39 | # udp_port should be 443 for best connectivity through firewalls 40 | udp_port: 443 41 | # uncomment if you will manage TLS termination for TURN, secretName is not used 42 | # when external_tls is set 43 | # external_tls: true 44 | # Kubernetes Secret containing TLS cert for 45 | # See https://docs.livekit.io/deploy/kubernetes/#importing-ssl-certificates 46 | secretName: 47 | # set the Kubernetes serviceType for the TURN service. By default it sets it to "LoadBalancer" 48 | # See kubernetes serviceTypes on official documentation: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types 49 | serviceType: "LoadBalancer" 50 | 51 | loadBalancer: 52 | # valid values: disable, alb, aws, gke, gke-managed-cert, gke-native-vpc, do 53 | # on AWS, we recommend using alb load balancer, which supports TLS termination 54 | # * in order to use alb, aws-ingress-controller must be installed 55 | # https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html 56 | # * for gke-managed-cert type follow https://cloud.google.com/kubernetes-engine/docs/how-to/managed-certs 57 | # and set staticIpName to your reserved static IP, and certificateName to be 58 | # name of the managed cert 59 | # * for do uncomment clusterIssuer with your cert manager issuer 60 | type: gclb 61 | # staticIpName: 62 | # certificateName: 63 | # clusterIssuer: letsencrypt-prod 64 | tls: 65 | # - hosts: 66 | # - livekit.myhost.com 67 | # with alb, certificates needs to reside in ACM for self-discovery 68 | # with do, use cert-manager and create certificate for turn. Load balancer is autoamtic 69 | # with gke, specify one or more secrets to use for the certificate 70 | # see: https://cloud.google.com/kubernetes-engine/docs/how-to/ingress-multi-ssl#specifying_certificates_for_your_ingress 71 | # secretName: 72 | 73 | # autoscaling requires resources to be defined 74 | autoscaling: 75 | # set to true to enable autoscaling. when set, ignores replicaCount 76 | enabled: false 77 | minReplicas: 1 78 | maxReplicas: 5 79 | targetCPUUtilizationPercentage: 60 80 | 81 | # if LiveKit should run only on specific nodes 82 | # this can be used to isolate designated nodes 83 | nodeSelector: 84 | {} 85 | # node.kubernetes.io/instance-type: c5.2xlarge 86 | 87 | resources: 88 | {} 89 | # Due to port restrictions, you can run only one instance of LiveKit per physical 90 | # node. Because of that, we recommend giving it plenty of resources to work with 91 | # limits: 92 | # cpu: 6000m 93 | # memory: 2048Mi 94 | # requests: 95 | # cpu: 4000m 96 | # memory: 1024Mi 97 | -------------------------------------------------------------------------------- /ingress-sample.yaml: -------------------------------------------------------------------------------- 1 | replicaCount: 1 2 | 3 | # Suggested value for gracefully terminate the pod: 3 hours 4 | terminationGracePeriodSeconds: 10800 5 | 6 | ingress: 7 | api_key: "server-api-key" 8 | api_secret: "server-api-secret" 9 | ws_url: "ws://livekit-host:" 10 | logging: 11 | level: info 12 | health_port: 7888 13 | prometheus_port: 7889 14 | http_relay_port: 9090 15 | rtmp_port: 1935 16 | whip_port: 8080 17 | rtc_config: 18 | use_external_ip: true 19 | udp_port: 7885 20 | 21 | redis: 22 | address: 23 | # db: 0 24 | # username: 25 | # password: 26 | # use_tls: false 27 | 28 | cpu_cost: 29 | rtmp_cpu_cost: 2.0 30 | whip_cpu_cost: 2.0 31 | whip_bypass_transcoding_cpu_cost: 0.1 32 | # set the Kubernetes serviceType for the ingress service. By default it sets it to "LoadBalancer" 33 | # See kubernetes serviceTypes on official documentation: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types 34 | serviceType: "LoadBalancer" 35 | 36 | # autoscaling requires resources to be defined 37 | autoscaling: 38 | # set to true to enable autoscaling. when set, ignores replicaCount 39 | enabled: false 40 | minReplicas: 1 41 | maxReplicas: 5 42 | targetCPUUtilizationPercentage: 60 43 | # targetMemoryUtilizationPercentage: 60 44 | # for use with prometheus adapter - the ingress service outputs a prometheus metric called livekit_ingress_available 45 | # this can be used to ensure a certain number or percentage of instances are available 46 | # custom: 47 | # metricName: my_metric_name 48 | # targetAverageValue: 70 49 | 50 | # if ingress should run only on specific nodes 51 | # this can be used to isolate designated nodes 52 | nodeSelector: {} 53 | # node.kubernetes.io/instance-type: c5.2xlarge 54 | 55 | resources: {} 56 | # requests: 57 | # cpu: 5000m 58 | # memory: 1024Mi 59 | # limits: 60 | # cpu: 8000m 61 | # memory: 2048Mi 62 | 63 | serviceAccount: 64 | # Specifies whether a service account should be created 65 | create: false 66 | # Annotations to add to the service account 67 | annotations: {} 68 | # The name of the service account to use. 69 | # If not set and create is true, a name is generated using the fullname template 70 | name: "" 71 | 72 | podAnnotations: 73 | sidecar.istio.io/inject: "false" 74 | linkerd.io/inject: disabled 75 | 76 | podSecurityContext: {} 77 | # fsGroup: 2000 78 | 79 | securityContext: 80 | {} 81 | # capabilities: 82 | # drop: 83 | # - ALL 84 | # readOnlyRootFilesystem: true 85 | # runAsNonRoot: true 86 | # runAsUser: 1000 87 | 88 | tolerations: [] 89 | 90 | affinity: {} 91 | -------------------------------------------------------------------------------- /ingress/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /ingress/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: ingress 3 | description: Ingress is used by LiveKit to ingest streams produced by external workflows 4 | type: application 5 | version: 1.4.3 6 | appVersion: "v1.4.3" 7 | 8 | sources: 9 | - https://github.com/livekit/ingress 10 | -------------------------------------------------------------------------------- /ingress/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | 3 | LiveKit Ingress {{ .Values.image.tag | default .Chart.AppVersion }} has been deployed! 4 | 5 | To get LoadBalancer details: 6 | NOTE: It may take a few minutes for the LoadBalancer IP to be available. 7 | Watch the status with: 'kubectl get svc --namespace {{ .Release.Namespace }} -w {{ template "ingress.fullname" . }}' 8 | 9 | kubectl get svc --namespace {{ .Release.Namespace }} {{ template "ingress.fullname" . }} -o jsonpath='{.status.loadBalancer.ingress[0].ip}' 10 | kubectl get svc --namespace {{ .Release.Namespace }} {{ template "ingress.fullname" . }} -o jsonpath='{.spec.ports}' 11 | 12 | ------------------------------------------------------------------------------- 13 | -------------------------------------------------------------------------------- /ingress/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "ingress.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "ingress.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "ingress.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "ingress.labels" -}} 37 | helm.sh/chart: {{ include "ingress.chart" . }} 38 | {{ include "ingress.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "ingress.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "ingress.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | {{/* 54 | Create the name of the service account to use 55 | */}} 56 | {{- define "ingress.serviceAccountName" -}} 57 | {{- if .Values.serviceAccount.create }} 58 | {{- default (include "ingress.fullname" .) .Values.serviceAccount.name }} 59 | {{- else }} 60 | {{- default "default" .Values.serviceAccount.name }} 61 | {{- end }} 62 | {{- end }} 63 | -------------------------------------------------------------------------------- /ingress/templates/configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: {{ include "ingress.fullname" . }} 5 | data: 6 | config.yaml: | 7 | {{ toYaml .Values.ingress | indent 4 }} 8 | -------------------------------------------------------------------------------- /ingress/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "ingress.fullname" . }} 5 | labels: 6 | {{- include "ingress.labels" . | nindent 4 }} 7 | spec: 8 | {{- if not .Values.autoscaling.enabled }} 9 | replicas: {{ .Values.replicaCount }} 10 | {{- end }} 11 | selector: 12 | matchLabels: 13 | {{- include "ingress.selectorLabels" . | nindent 6 }} 14 | template: 15 | metadata: 16 | {{- with .Values.podAnnotations }} 17 | annotations: 18 | {{- toYaml . | nindent 8 }} 19 | {{- end }} 20 | checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} 21 | labels: 22 | {{- include "ingress.selectorLabels" . | nindent 8 }} 23 | spec: 24 | serviceAccountName: {{ include "ingress.serviceAccountName" . }} 25 | securityContext: 26 | {{- toYaml .Values.podSecurityContext | nindent 8 }} 27 | {{- if .Values.podHostNetwork }} 28 | dnsPolicy: ClusterFirstWithHostNet 29 | hostNetwork: true 30 | {{- end }} 31 | terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} 32 | containers: 33 | - name: {{ .Chart.Name }} 34 | securityContext: 35 | {{- toYaml .Values.securityContext | nindent 12 }} 36 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" 37 | imagePullPolicy: {{ .Values.image.pullPolicy }} 38 | env: 39 | - name: INGRESS_CONFIG_BODY 40 | valueFrom: 41 | configMapKeyRef: 42 | name: {{ include "ingress.fullname" . }} 43 | key: config.yaml 44 | ports: 45 | {{- if .Values.ingress.health_port }} 46 | - name: health 47 | containerPort: {{ .Values.ingress.health_port }} 48 | protocol: TCP 49 | {{- end }} 50 | {{- if .Values.ingress.http_relay_port }} 51 | - name: http-relay 52 | containerPort: {{ .Values.ingress.http_relay_port }} 53 | protocol: TCP 54 | {{- end }} 55 | {{- if .Values.ingress.rtmp_port }} 56 | - name: rtmp-port 57 | containerPort: {{ .Values.ingress.rtmp_port }} 58 | protocol: TCP 59 | {{- end }} 60 | {{- if .Values.ingress.whip_port }} 61 | - name: whip-port 62 | containerPort: {{ .Values.ingress.whip_port }} 63 | protocol: TCP 64 | {{- end }} 65 | {{- if .Values.ingress.prometheus_port }} 66 | - name: metrics 67 | containerPort: {{ .Values.ingress.prometheus_port }} 68 | protocol: TCP 69 | {{- end }} 70 | livenessProbe: 71 | httpGet: 72 | path: / 73 | port: health 74 | readinessProbe: 75 | httpGet: 76 | path: / 77 | port: health 78 | resources: 79 | {{- toYaml .Values.resources | nindent 12 }} 80 | {{- with .Values.nodeSelector }} 81 | nodeSelector: 82 | {{- toYaml . | nindent 8 }} 83 | {{- end }} 84 | {{- with .Values.affinity }} 85 | affinity: 86 | {{- toYaml . | nindent 8 }} 87 | {{- end }} 88 | {{- with .Values.tolerations }} 89 | tolerations: 90 | {{- toYaml . | nindent 8 }} 91 | {{- end }} 92 | -------------------------------------------------------------------------------- /ingress/templates/hpa.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.autoscaling.enabled }} 2 | {{- if semverCompare ">=1.23-0" .Capabilities.KubeVersion.GitVersion }} 3 | apiVersion: autoscaling/v2 4 | {{- else }} 5 | apiVersion: autoscaling/v2beta1 6 | {{- end }} 7 | kind: HorizontalPodAutoscaler 8 | metadata: 9 | name: {{ include "ingress.fullname" . }} 10 | labels: 11 | {{- include "ingress.labels" . | nindent 4 }} 12 | spec: 13 | scaleTargetRef: 14 | apiVersion: apps/v1 15 | kind: Deployment 16 | name: {{ include "ingress.fullname" . }} 17 | minReplicas: {{ .Values.autoscaling.minReplicas }} 18 | maxReplicas: {{ .Values.autoscaling.maxReplicas }} 19 | metrics: 20 | {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} 21 | - type: Resource 22 | resource: 23 | name: cpu 24 | {{- if semverCompare ">=1.23-0" .Capabilities.KubeVersion.GitVersion }} 25 | target: 26 | type: Utilization 27 | averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} 28 | {{- else }} 29 | targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} 30 | {{- end }} 31 | {{- end }} 32 | {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} 33 | - type: Resource 34 | resource: 35 | name: memory 36 | {{- if semverCompare ">=1.23-0" .Capabilities.KubeVersion.GitVersion }} 37 | target: 38 | type: Utilization 39 | averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} 40 | {{- else }} 41 | targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} 42 | {{- end }} 43 | {{- end }} 44 | {{- if .Values.autoscaling.custom }} 45 | - type: Pods 46 | pods: 47 | {{- if semverCompare ">=1.23-0" .Capabilities.KubeVersion.GitVersion }} 48 | metric: 49 | name: {{ .Values.autoscaling.custom.metricName }} 50 | target: 51 | type: AverageValue 52 | averageValue: {{ .Values.autoscaling.custom.targetAverageValue }} 53 | {{- else }} 54 | metricName: {{ .Values.autoscaling.custom.metricName }} 55 | targetAverageValue: {{ .Values.autoscaling.custom.targetAverageValue }} 56 | {{- end }} 57 | {{- end }} 58 | {{- end }} 59 | -------------------------------------------------------------------------------- /ingress/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "ingress.fullname" . }} 5 | labels: {{- include "ingress.labels" . | nindent 4 }} 6 | spec: 7 | type: {{ default "LoadBalancer" .Values.ingress.serviceType }} 8 | ports: 9 | {{- if .Values.loadBalancer.servicePort }} 10 | - port: {{ .Values.loadBalancer.servicePort }} 11 | protocol: TCP 12 | name: ws 13 | {{- end }} 14 | - port: {{ .Values.ingress.rtmp_port }} 15 | protocol: TCP 16 | name: rtmp 17 | - port: {{ .Values.ingress.whip_port }} 18 | protocol: TCP 19 | name: whip 20 | 21 | selector: 22 | {{- include "ingress.selectorLabels" . | nindent 4 }} 23 | -------------------------------------------------------------------------------- /ingress/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "ingress.serviceAccountName" . }} 6 | labels: 7 | {{- include "ingress.labels" . | nindent 4 }} 8 | {{- with .Values.serviceAccount.annotations }} 9 | annotations: 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /ingress/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for ingress. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | 5 | replicaCount: 1 6 | 7 | image: 8 | repository: livekit/ingress 9 | pullPolicy: IfNotPresent 10 | 11 | ingress: 12 | logging: 13 | level: info 14 | health_port: 7888 15 | prometheus_port: 7889 16 | http_relay_port: 9090 17 | rtmp_port: 1935 18 | whip_port: 8080 19 | rtc_config: 20 | use_external_ip: true 21 | udp_port: 7885 22 | redis: {} 23 | 24 | cpu_cost: 25 | rtmp_cpu_cost: 2 26 | whip_cpu_cost: 2 27 | whip_bypass_transcoding_cpu_cost: 0.1 28 | 29 | loadBalancer: 30 | servicePort: 7888 31 | annotations: {} 32 | 33 | terminationGracePeriodSeconds: 3600 34 | 35 | nameOverride: "" 36 | fullnameOverride: "" 37 | 38 | autoscaling: 39 | enabled: false 40 | 41 | nodeSelector: {} 42 | 43 | resources: {} 44 | 45 | serviceAccount: 46 | create: false 47 | annotations: {} 48 | name: "" 49 | 50 | podHostNetwork: true 51 | 52 | podAnnotations: 53 | sidecar.istio.io/inject: "false" 54 | linkerd.io/inject: disabled 55 | 56 | podSecurityContext: {} 57 | 58 | securityContext: {} 59 | 60 | tolerations: [] 61 | 62 | affinity: {} 63 | -------------------------------------------------------------------------------- /livekit-server/.helmignore: -------------------------------------------------------------------------------- 1 | # Patterns to ignore when building packages. 2 | # This supports shell glob matching, relative path matching, and 3 | # negation (prefixed with !). Only one pattern per line. 4 | .DS_Store 5 | # Common VCS dirs 6 | .git/ 7 | .gitignore 8 | .bzr/ 9 | .bzrignore 10 | .hg/ 11 | .hgignore 12 | .svn/ 13 | # Common backup files 14 | *.swp 15 | *.bak 16 | *.tmp 17 | *.orig 18 | *~ 19 | # Various IDEs 20 | .project 21 | .idea/ 22 | *.tmproj 23 | .vscode/ 24 | -------------------------------------------------------------------------------- /livekit-server/Chart.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v2 2 | name: livekit-server 3 | description: Real-time infrastructure for developers. LiveKit is the open source stack for streaming audio, video, and data. 4 | type: application 5 | version: 1.8.3 6 | appVersion: "v1.8.3" 7 | 8 | sources: 9 | - https://github.com/livekit/livekit 10 | -------------------------------------------------------------------------------- /livekit-server/templates/NOTES.txt: -------------------------------------------------------------------------------- 1 | ------------------------------------------------------------------------------- 2 | 3 | LiveKit {{ .Values.image.tag | default .Chart.AppVersion }} has been deployed! 4 | 5 | Please ensure that the following ports on the nodes are open on your firewall. 6 | 7 | {{- if .Values.livekit.rtc.udp_port }} 8 | * WebRTC UDP {{ .Values.livekit.rtc.udp_port }} 9 | {{- else }} 10 | * WebRTC UDP {{ .Values.livekit.rtc.port_range_start}} - {{ .Values.livekit.rtc.port_range_end}} 11 | {{- end }} 12 | * WebRTC TCP {{ .Values.livekit.rtc.tcp_port }} 13 | {{- if .Values.livekit.turn.enabled }} 14 | {{- if .Values.livekit.turn.udp_port }} 15 | * TURN/UDP {{ .Values.livekit.turn.udp_port }} 16 | {{- end }} 17 | {{- if .Values.livekit.turn.tls_port }} 18 | * TURN/TLS {{ .Values.livekit.turn.tls_port }} 19 | {{- end }} 20 | {{- end }} 21 | 22 | {{- if ne .Values.loadBalancer.type "disable" }} 23 | 24 | Primary load balancer has been set up for the primary API endpoint. The 25 | following hosts should now be pointed at the load balancer. 26 | {{- range .Values.loadBalancer.tls }} 27 | {{- range .hosts }} 28 | - {{ . }} 29 | {{- end }} 30 | {{- end }} 31 | 32 | To determine the load balancer address, run: 33 | {{- if eq .Values.loadBalancer.type "aws" }} 34 | $ kubectl get --namespace {{ .Release.Namespace }} service {{ include "livekit-server.fullname" . }} 35 | {{- else }} 36 | $ kubectl get --namespace {{ .Release.Namespace }} ingress {{ include "livekit-server.fullname" . }} 37 | {{- end }} 38 | {{- else }} 39 | Load balancer has been disabled 40 | {{- end }} 41 | 42 | {{- if and .Values.livekit.turn.enabled .Values.livekit.turn.tls_port (not .Values.livekit.turn.external_tls) }} 43 | 44 | TURN/TLS has been deployed behind a load balancer, to determine its address, run: 45 | $ kubectl get --namespace {{ .Release.Namespace }} service {{ include "livekit-server.fullname" . }}-turn 46 | You may now map the TURN/TLS domain {{ .Values.livekit.turn.domain }} to this address 47 | 48 | {{- end }} 49 | 50 | ------------------------------------------------------------------------------- 51 | -------------------------------------------------------------------------------- /livekit-server/templates/_helpers.tpl: -------------------------------------------------------------------------------- 1 | {{/* 2 | Expand the name of the chart. 3 | */}} 4 | {{- define "livekit-server.name" -}} 5 | {{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }} 6 | {{- end }} 7 | 8 | {{/* 9 | Create a default fully qualified app name. 10 | We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec). 11 | If release name contains chart name it will be used as a full name. 12 | */}} 13 | {{- define "livekit-server.fullname" -}} 14 | {{- if .Values.fullnameOverride }} 15 | {{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }} 16 | {{- else }} 17 | {{- $name := default .Chart.Name .Values.nameOverride }} 18 | {{- if contains $name .Release.Name }} 19 | {{- .Release.Name | trunc 63 | trimSuffix "-" }} 20 | {{- else }} 21 | {{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }} 22 | {{- end }} 23 | {{- end }} 24 | {{- end }} 25 | 26 | {{/* 27 | Create chart name and version as used by the chart label. 28 | */}} 29 | {{- define "livekit-server.chart" -}} 30 | {{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }} 31 | {{- end }} 32 | 33 | {{/* 34 | Common labels 35 | */}} 36 | {{- define "livekit-server.labels" -}} 37 | helm.sh/chart: {{ include "livekit-server.chart" . }} 38 | {{ include "livekit-server.selectorLabels" . }} 39 | {{- if .Chart.AppVersion }} 40 | app.kubernetes.io/version: {{ .Chart.AppVersion | quote }} 41 | {{- end }} 42 | app.kubernetes.io/managed-by: {{ .Release.Service }} 43 | {{- end }} 44 | 45 | {{/* 46 | Selector labels 47 | */}} 48 | {{- define "livekit-server.selectorLabels" -}} 49 | app.kubernetes.io/name: {{ include "livekit-server.name" . }} 50 | app.kubernetes.io/instance: {{ .Release.Name }} 51 | {{- end }} 52 | 53 | {{/* 54 | Create the name of the service account to use 55 | */}} 56 | {{- define "livekit-server.serviceAccountName" -}} 57 | {{- if .Values.serviceAccount.create }} 58 | {{- default (include "livekit-server.fullname" .) .Values.serviceAccount.name }} 59 | {{- else }} 60 | {{- default "default" .Values.serviceAccount.name }} 61 | {{- end }} 62 | {{- end }} 63 | 64 | {{/* 65 | Create the name of the service monitor to use 66 | */}} 67 | {{- define "livekit-server.serviceMonitorName" -}} 68 | {{- if .Values.serviceMonitor.create }} 69 | {{- default (include "livekit-server.fullname" .) .Values.serviceMonitor.name }} 70 | {{- else }} 71 | {{- default "default" .Values.serviceMonitor.name }} 72 | {{- end }} 73 | {{- end }} 74 | -------------------------------------------------------------------------------- /livekit-server/templates/backendconfig.yaml: -------------------------------------------------------------------------------- 1 | {{- if or (eq .Values.loadBalancer.type "gke") (eq .Values.loadBalancer.type "gke-managed-cert") (eq .Values.loadBalancer.type "gke-vpc-native") (eq .Values.loadBalancer.type "gclb") -}} 2 | apiVersion: cloud.google.com/v1 3 | kind: BackendConfig 4 | metadata: 5 | name: {{ include "livekit-server.fullname" . }} 6 | spec: 7 | {{ .Values.gcp.backendConfig | toPrettyJson }} 8 | {{ end }} -------------------------------------------------------------------------------- /livekit-server/templates/configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: {{ include "livekit-server.fullname" . }} 5 | data: 6 | config.yaml: | 7 | {{ toYaml .Values.livekit | indent 4 }} 8 | -------------------------------------------------------------------------------- /livekit-server/templates/deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: {{ include "livekit-server.fullname" . }} 5 | labels: 6 | {{- include "livekit-server.labels" . | nindent 4 }} 7 | {{- if .Values.deploymentAnnotations }} 8 | annotations: 9 | {{- toYaml .Values.deploymentAnnotations | nindent 4 }} 10 | {{- end }} 11 | spec: 12 | {{- if not .Values.autoscaling.enabled }} 13 | replicas: {{ .Values.replicaCount }} 14 | {{- end }} 15 | selector: 16 | matchLabels: 17 | {{- include "livekit-server.selectorLabels" . | nindent 6 }} 18 | {{- if .Values.deploymentStrategy }} 19 | strategy: 20 | {{- toYaml .Values.deploymentStrategy | nindent 4 }} 21 | {{- end }} 22 | template: 23 | metadata: 24 | {{- with .Values.podAnnotations }} 25 | annotations: 26 | {{- toYaml . | nindent 8 }} 27 | {{- end }} 28 | checksum/config: {{ include (print $.Template.BasePath "/configmap.yaml") . | sha256sum }} 29 | labels: 30 | {{- include "livekit-server.selectorLabels" . | nindent 8 }} 31 | spec: 32 | {{- with .Values.imagePullSecrets }} 33 | imagePullSecrets: 34 | {{- toYaml . | nindent 8 }} 35 | {{- end }} 36 | serviceAccountName: {{ include "livekit-server.serviceAccountName" . }} 37 | securityContext: 38 | {{- toYaml .Values.podSecurityContext | nindent 8 }} 39 | {{- if .Values.podHostNetwork }} 40 | dnsPolicy: ClusterFirstWithHostNet 41 | hostNetwork: true 42 | {{- end }} 43 | terminationGracePeriodSeconds: {{ .Values.terminationGracePeriodSeconds }} 44 | containers: 45 | - name: {{ .Chart.Name }} 46 | securityContext: 47 | {{- toYaml .Values.securityContext | nindent 12 }} 48 | image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}" 49 | imagePullPolicy: {{ .Values.image.pullPolicy }} 50 | args: ["--disable-strict-config"] 51 | env: 52 | - name: LIVEKIT_CONFIG 53 | valueFrom: 54 | configMapKeyRef: 55 | name: {{ include "livekit-server.fullname" . }} 56 | key: config.yaml 57 | {{- if and .Values.livekit.turn.enabled .Values.livekit.turn.tls_port (not .Values.livekit.turn.external_tls) }} 58 | - name: LIVEKIT_TURN_CERT 59 | value: /etc/lkcert/tls.crt 60 | - name: LIVEKIT_TURN_KEY 61 | value: /etc/lkcert/tls.key 62 | {{- end }} 63 | ports: 64 | - name: http 65 | containerPort: {{ .Values.livekit.port }} 66 | protocol: TCP 67 | {{- if .Values.livekit.rtc.udp_port }} 68 | - name: rtc-udp 69 | containerPort: {{ .Values.livekit.rtc.udp_port }} 70 | hostPort: {{ .Values.livekit.rtc.udp_port }} 71 | protocol: UDP 72 | {{- end }} 73 | {{- if .Values.livekit.rtc.tcp_port }} 74 | - name: rtc-tcp 75 | containerPort: {{ .Values.livekit.rtc.tcp_port }} 76 | hostPort: {{ .Values.livekit.rtc.tcp_port }} 77 | protocol: TCP 78 | {{- end }} 79 | {{- if .Values.livekit.prometheus_port }} 80 | - name: metrics 81 | containerPort: {{ .Values.livekit.prometheus_port }} 82 | hostPort: {{ .Values.livekit.prometheus_port }} 83 | protocol: TCP 84 | {{- end }} 85 | {{- if .Values.livekit.turn.enabled }} 86 | {{- if .Values.livekit.turn.tls_port }} 87 | - name: turn-tls 88 | containerPort: {{ .Values.livekit.turn.tls_port }} 89 | hostPort: {{ .Values.livekit.turn.tls_port }} 90 | protocol: TCP 91 | {{- end }} 92 | {{- if .Values.livekit.turn.udp_port }} 93 | - name: turn-udp 94 | containerPort: {{ .Values.livekit.turn.udp_port }} 95 | hostPort: {{ .Values.livekit.turn.udp_port }} 96 | protocol: UDP 97 | {{- end }} 98 | {{- end }} 99 | livenessProbe: 100 | httpGet: 101 | path: / 102 | port: http 103 | readinessProbe: 104 | httpGet: 105 | path: / 106 | port: http 107 | resources: 108 | {{- toYaml .Values.resources | nindent 12 }} 109 | {{- if or .Values.storeKeysInSecret.enabled (and .Values.livekit.turn.enabled .Values.livekit.turn.tls_port (not .Values.livekit.turn.external_tls)) }} 110 | volumeMounts: 111 | {{- if .Values.storeKeysInSecret.enabled }} 112 | - name: keys-volume 113 | mountPath: {{ .Values.livekit.key_file }} 114 | subPath: {{ .Values.livekit.key_file }} 115 | {{- end }} 116 | {{- if and .Values.livekit.turn.enabled .Values.livekit.turn.tls_port (not .Values.livekit.turn.external_tls) }} 117 | - name: lkturncert 118 | mountPath: /etc/lkcert 119 | readOnly: true 120 | {{- end }} 121 | {{- end }} 122 | {{- if or .Values.storeKeysInSecret.enabled (and .Values.livekit.turn.enabled .Values.livekit.turn.tls_port (not .Values.livekit.turn.external_tls)) }} 123 | volumes: 124 | {{- if .Values.storeKeysInSecret.enabled }} 125 | - name: keys-volume 126 | secret: 127 | secretName: {{ (tpl .Values.storeKeysInSecret.existingSecret .) | default (include "livekit-server.fullname" .) }} 128 | defaultMode: 0600 129 | {{- end }} 130 | {{- if and .Values.livekit.turn.enabled .Values.livekit.turn.tls_port (not .Values.livekit.turn.external_tls) }} 131 | - name: lkturncert 132 | secret: 133 | secretName: {{ required "tls secret required if turn enabled" .Values.livekit.turn.secretName }} 134 | {{- end }} 135 | {{- end }} 136 | {{- with .Values.nodeSelector }} 137 | nodeSelector: 138 | {{- toYaml . | nindent 8 }} 139 | {{- end }} 140 | {{- with .Values.affinity }} 141 | affinity: 142 | {{- toYaml . | nindent 8 }} 143 | {{- end }} 144 | {{- with .Values.tolerations }} 145 | tolerations: 146 | {{- toYaml . | nindent 8 }} 147 | {{- end }} 148 | -------------------------------------------------------------------------------- /livekit-server/templates/hpa.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.autoscaling.enabled }} 2 | {{- if semverCompare ">=1.23-0" .Capabilities.KubeVersion.GitVersion }} 3 | apiVersion: autoscaling/v2 4 | {{- else }} 5 | apiVersion: autoscaling/v2beta1 6 | {{- end }} 7 | kind: HorizontalPodAutoscaler 8 | metadata: 9 | name: {{ include "livekit-server.fullname" . }} 10 | labels: 11 | {{- include "livekit-server.labels" . | nindent 4 }} 12 | spec: 13 | scaleTargetRef: 14 | apiVersion: apps/v1 15 | kind: Deployment 16 | name: {{ include "livekit-server.fullname" . }} 17 | minReplicas: {{ .Values.autoscaling.minReplicas }} 18 | maxReplicas: {{ .Values.autoscaling.maxReplicas }} 19 | metrics: 20 | {{- if .Values.autoscaling.targetCPUUtilizationPercentage }} 21 | - type: Resource 22 | resource: 23 | name: cpu 24 | {{- if semverCompare ">=1.23-0" .Capabilities.KubeVersion.GitVersion }} 25 | target: 26 | type: Utilization 27 | averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} 28 | {{- else }} 29 | targetAverageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }} 30 | {{- end }} 31 | {{- end }} 32 | {{- if .Values.autoscaling.targetMemoryUtilizationPercentage }} 33 | - type: Resource 34 | resource: 35 | name: memory 36 | {{- if semverCompare ">=1.23-0" .Capabilities.KubeVersion.GitVersion }} 37 | target: 38 | type: Utilization 39 | averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} 40 | {{- else }} 41 | targetAverageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }} 42 | {{- end }} 43 | {{- end }} 44 | {{- end }} 45 | -------------------------------------------------------------------------------- /livekit-server/templates/ingress.yaml: -------------------------------------------------------------------------------- 1 | {{- if and (ne .Values.loadBalancer.type "disable") (ne .Values.loadBalancer.type "gclb") -}} 2 | {{- $fullName := include "livekit-server.fullname" . -}} 3 | {{- $svcPort := .Values.loadBalancer.servicePort -}} 4 | kind: Ingress 5 | metadata: 6 | name: {{ $fullName }} 7 | labels: 8 | {{- include "livekit-server.labels" . | nindent 4 }} 9 | annotations: 10 | # custom annotations 11 | {{- with .Values.loadBalancer.annotations }} 12 | {{- toYaml . | nindent 4 }} 13 | {{- end }} 14 | # AWS ALB 15 | {{- if eq .Values.loadBalancer.type "alb" }} 16 | kubernetes.io/ingress.class: alb 17 | alb.ingress.kubernetes.io/scheme: internet-facing 18 | {{- if .Values.loadBalancer.tls }} 19 | alb.ingress.kubernetes.io/listen-ports: '[{"HTTPS":443}]' 20 | {{- end }} 21 | {{- end }} 22 | # GKE with managed certs 23 | {{- if eq .Values.loadBalancer.type "gke-managed-cert" }} 24 | kubernetes.io/ingress.global-static-ip-name: {{ .Values.loadBalancer.staticIpName }} 25 | networking.gke.io/managed-certificates: {{ or .Values.loadBalancer.certificateName "managed-cert" }} 26 | kubernetes.io/ingress.class: "gce" 27 | {{- end }} 28 | # DO with cert manager 29 | {{- if eq .Values.loadBalancer.type "do" }} 30 | cert-manager.io/cluster-issuer: {{ .Values.loadBalancer.clusterIssuer }} 31 | {{- end }} 32 | {{- if semverCompare ">=1.19-0" .Capabilities.KubeVersion.GitVersion }} 33 | apiVersion: networking.k8s.io/v1 34 | {{- else }} 35 | apiVersion: extensions/v1beta1 36 | {{- end }} 37 | spec: 38 | {{- if eq .Values.loadBalancer.type "do" }} 39 | ingressClassName: nginx 40 | {{- end }} 41 | rules: 42 | # In order to work with cert manager on DO, we cannot set us as a default backend 43 | {{- range .Values.loadBalancer.tls }} 44 | {{- range .hosts }} 45 | - host: {{ . | quote }} 46 | http: 47 | paths: 48 | - pathType: Prefix 49 | path: / 50 | backend: 51 | service: 52 | name: {{ $fullName }} 53 | port: 54 | number: {{ $svcPort }} 55 | {{- end }} 56 | {{- end }} 57 | {{- if ne .Values.loadBalancer.type "gke-vpc-native" }} 58 | {{- with .Values.loadBalancer }} 59 | {{- if .tls }} 60 | tls: 61 | {{- range .tls }} 62 | {{- if .hosts }} 63 | - hosts: 64 | {{- range .hosts }} 65 | - {{ . | quote }} 66 | {{- end }} 67 | {{- if .secretName }} 68 | secretName: {{ .secretName | quote }} 69 | {{- end }} 70 | {{- end }} 71 | {{- end }} 72 | {{- end }} 73 | {{- end }} 74 | {{- end }} 75 | {{- end }} 76 | -------------------------------------------------------------------------------- /livekit-server/templates/secret.yaml: -------------------------------------------------------------------------------- 1 | {{- if and (not .Values.storeKeysInSecret.existingSecret) .Values.storeKeysInSecret.enabled }} 2 | apiVersion: v1 3 | kind: Secret 4 | metadata: 5 | name: {{ include "livekit-server.fullname" . }} 6 | labels: 7 | {{- include "livekit-server.labels" . | nindent 4 }} 8 | data: 9 | {{ .Values.livekit.key_file }}: {{ toYaml .Values.storeKeysInSecret.keys | b64enc }} 10 | {{- end }} 11 | -------------------------------------------------------------------------------- /livekit-server/templates/service.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: {{ include "livekit-server.fullname" . }} 5 | labels: 6 | {{- include "livekit-server.labels" . | nindent 4 }} 7 | annotations: 8 | {{- if eq .Values.loadBalancer.type "aws" }} 9 | service.beta.kubernetes.io/aws-load-balancer-backend-protocol: http 10 | service.beta.kubernetes.io/aws-load-balancer-type: nlb 11 | {{- else if or (eq .Values.loadBalancer.type "gke") (eq .Values.loadBalancer.type "gke-managed-cert") (eq .Values.loadBalancer.type "gke-vpc-native") }} 12 | cloud.google.com/backend-config: '{"ports": {"{{ .Values.loadBalancer.servicePort }}":"{{ include "livekit-server.fullname" . }}"}}' 13 | {{- else if eq .Values.loadBalancer.type "gclb" }} 14 | cloud.google.com/backend-config: '{"ports": {"{{ .Values.loadBalancer.servicePort }}":"{{ include "livekit-server.fullname" . }}"}}' 15 | cloud.google.com/neg: '{"exposed_ports": {"{{ .Values.loadBalancer.servicePort }}":{}}}' 16 | {{- end }} 17 | {{- if eq .Values.loadBalancer.type "gke-vpc-native" }} 18 | cloud.google.com/neg: '{"ingress": true}' 19 | {{- end }} 20 | spec: 21 | {{- if or (eq .Values.loadBalancer.type "alb") (eq .Values.loadBalancer.type "gke") (eq .Values.loadBalancer.type "gke-managed-cert") (eq .Values.loadBalancer.type "do") (eq .Values.loadBalancer.type "gclb")}} 22 | type: NodePort 23 | {{- else if eq .Values.loadBalancer.type "aws" }} 24 | type: LoadBalancer 25 | {{- end }} 26 | ports: 27 | - port: {{ .Values.loadBalancer.servicePort }} 28 | targetPort: http 29 | protocol: TCP 30 | name: http 31 | {{- if and (or (eq .Values.loadBalancer.type "disable") (eq .Values.loadBalancer.type "gclb")) .Values.livekit.rtc.tcp_port }} 32 | - name: rtc-tcp 33 | port: {{ .Values.livekit.rtc.tcp_port }} 34 | protocol: TCP 35 | targetPort: rtc-tcp 36 | {{- end }} 37 | {{- if and (or (eq .Values.loadBalancer.type "disable") (eq .Values.loadBalancer.type "gclb")) .Values.livekit.rtc.udp_port }} 38 | - name: rtc-udp 39 | port: {{ .Values.livekit.rtc.udp_port }} 40 | protocol: UDP 41 | targetPort: rtc-udp 42 | {{- end }} 43 | {{- if .Values.livekit.prometheus_port }} 44 | - port: {{ .Values.livekit.prometheus_port }} 45 | targetPort: metrics 46 | protocol: TCP 47 | name: metrics 48 | {{- end }} 49 | selector: 50 | {{- include "livekit-server.selectorLabels" . | nindent 4 }} 51 | -------------------------------------------------------------------------------- /livekit-server/templates/serviceaccount.yaml: -------------------------------------------------------------------------------- 1 | {{- if .Values.serviceAccount.create -}} 2 | apiVersion: v1 3 | kind: ServiceAccount 4 | metadata: 5 | name: {{ include "livekit-server.serviceAccountName" . }} 6 | labels: 7 | {{- include "livekit-server.labels" . | nindent 4 }} 8 | {{- with .Values.serviceAccount.annotations }} 9 | annotations: 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | {{- end }} 13 | -------------------------------------------------------------------------------- /livekit-server/templates/servicemonitor.yaml: -------------------------------------------------------------------------------- 1 | {{- if and .Values.serviceMonitor.create .Values.livekit.prometheus_port -}} 2 | apiVersion: monitoring.coreos.com/v1 3 | kind: ServiceMonitor 4 | metadata: 5 | name: {{ include "livekit-server.serviceMonitorName" . }} 6 | labels: 7 | {{- include "livekit-server.labels" . | nindent 4 }} 8 | {{- with .Values.serviceMonitor.annotations }} 9 | annotations: 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | spec: 13 | endpoints: 14 | - port: metrics 15 | path: / 16 | interval: {{ .Values.serviceMonitor.interval }} 17 | selector: 18 | matchLabels: 19 | {{- include "livekit-server.selectorLabels" . | nindent 6 }} 20 | {{- end }} 21 | -------------------------------------------------------------------------------- /livekit-server/templates/tests/test-connection.yaml: -------------------------------------------------------------------------------- 1 | {{- if ne .Values.loadBalancer.type "disable" }} 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: "{{ include "livekit-server.fullname" . }}-test-connection" 6 | labels: 7 | {{- include "livekit-server.labels" . | nindent 4 }} 8 | annotations: 9 | "helm.sh/hook": test 10 | spec: 11 | {{- with .Values.imagePullSecrets }} 12 | imagePullSecrets: 13 | {{- toYaml . | nindent 4 }} 14 | {{- end }} 15 | containers: 16 | - name: wget 17 | image: busybox 18 | command: ['wget'] 19 | args: ['{{ include "livekit-server.fullname" . }}:{{ .Values.loadBalancer.servicePort }}'] 20 | restartPolicy: Never 21 | {{- end }} 22 | -------------------------------------------------------------------------------- /livekit-server/templates/turnloadbalancer.yaml: -------------------------------------------------------------------------------- 1 | {{- if and (and .Values.livekit.turn.enabled .Values.livekit.turn.tls_port) .Values.turnLoadbalancer.enable }} 2 | apiVersion: v1 3 | kind: Service 4 | metadata: 5 | name: '{{ include "livekit-server.fullname" . }}-turn' 6 | labels: 7 | {{- include "livekit-server.labels" . | nindent 4 }} 8 | {{- with .Values.livekit.turn.loadBalancerAnnotations }} 9 | annotations: 10 | {{- toYaml . | nindent 4 }} 11 | {{- end }} 12 | spec: 13 | type: {{ default "LoadBalancer" .Values.livekit.turn.serviceType }} 14 | ports: 15 | - port: 443 16 | targetPort: {{ .Values.livekit.turn.tls_port }} 17 | protocol: TCP 18 | selector: 19 | {{- include "livekit-server.selectorLabels" . | nindent 4 }} 20 | {{- end }} 21 | -------------------------------------------------------------------------------- /livekit-server/values.yaml: -------------------------------------------------------------------------------- 1 | # Default values for livekit-server. 2 | # This is a YAML-formatted file. 3 | # Declare variables to be passed into your templates. 4 | 5 | replicaCount: 1 6 | 7 | image: 8 | repository: livekit/livekit-server 9 | pullPolicy: IfNotPresent 10 | 11 | imagePullSecrets: [] 12 | 13 | terminationGracePeriodSeconds: 18000 14 | 15 | # configuration for livekit 16 | # you may specify any config settings that are valid in livekit-server's 17 | # config.yaml: https://github.com/livekit/livekit/blob/master/config-sample.yaml 18 | livekit: 19 | port: 7880 20 | log_level: info 21 | rtc: 22 | tcp_port: 7881 23 | port_range_start: 50000 24 | port_range_end: 60000 25 | use_external_ip: true 26 | redis: 27 | {} 28 | # supports sentinels and cluster, see above 29 | # address: 30 | # db: 0 31 | # username: 32 | # password: 33 | # key value pairs (: >api_secret>) 34 | keys: 35 | {} 36 | # Api keys can be loaded from a file 37 | # https://github.com/livekit/livekit/blob/6eaa300949cdfe8fbf6e2ded926c9f8c1a01bc61/pkg/config/config.go#L61 38 | # In order to set the api keys when using the key_file parameter configure the storeKeysInSecret block below 39 | # key_file: keys.yaml 40 | turn: 41 | enabled: false 42 | # Must match domain of your tls cert 43 | # domain: turn.myhost.com 44 | # secretName: 45 | loadBalancerAnnotations: {} 46 | # webhook: 47 | # room: 48 | # region: 49 | 50 | # Set this option to true if you want to store your API keys in a secret instead of the config file 51 | storeKeysInSecret: 52 | enabled: false 53 | # Use a pre existing secret, useful to combine with external secret managers 54 | # as GCP External Secrets or Hashicorp Vault 55 | existingSecret: "" 56 | # Define your API keys and secrets as key-value pairs here. These will be stored in the secret. 57 | # Example: keys: 58 | # my_api_key: my_api_secret 59 | keys: 60 | {} 61 | # key value pairs (: >api_secret>) 62 | 63 | nameOverride: "" 64 | fullnameOverride: "" 65 | 66 | loadBalancer: 67 | type: disable 68 | servicePort: 80 69 | annotations: {} 70 | 71 | turnLoadbalancer: 72 | enable: true 73 | 74 | autoscaling: 75 | enabled: false 76 | minReplicas: 1 77 | maxReplicas: 5 78 | targetCPUUtilizationPercentage: 60 79 | # targetMemoryUtilizationPercentage: 80 80 | 81 | # if LiveKit should run only on specific nodes 82 | # this can be used to isolate designated nodes 83 | nodeSelector: 84 | {} 85 | # node.kubernetes.io/instance-type: c5.2xlarge 86 | 87 | resources: 88 | {} 89 | # Due to port restrictions, you can run only one instance of LiveKit per physical 90 | # node. Because of that, we recommend giving it plenty of resources to work with 91 | # limits: 92 | # cpu: 6000m 93 | # memory: 2048Mi 94 | # requests: 95 | # cpu: 4000m 96 | # memory: 1024Mi 97 | 98 | serviceAccount: 99 | # Specifies whether a service account should be created 100 | create: false 101 | # Annotations to add to the service account 102 | annotations: {} 103 | # The name of the service account to use. 104 | # If not set and create is true, a name is generated using the fullname template 105 | name: "" 106 | 107 | podHostNetwork: true 108 | 109 | podAnnotations: 110 | sidecar.istio.io/inject: "false" 111 | linkerd.io/inject: disabled 112 | 113 | podSecurityContext: 114 | {} 115 | # fsGroup: 2000 116 | 117 | securityContext: 118 | {} 119 | # capabilities: 120 | # drop: 121 | # - ALL 122 | # readOnlyRootFilesystem: true 123 | # runAsNonRoot: true 124 | # runAsUser: 1000 125 | 126 | tolerations: [] 127 | 128 | affinity: {} 129 | 130 | # https://kubernetes.io/docs/reference/generated/kubernetes-api/v1.27/#deploymentstrategy-v1-apps 131 | deploymentStrategy: {} 132 | 133 | deploymentAnnotations: {} 134 | 135 | # Specifies configuration gke backendconfig 136 | gcp: 137 | backendConfig: 138 | # 10h timeout for websocket 139 | timeoutSec: 36000 140 | connectionDraining: 141 | drainingTimeoutSec: 60 142 | 143 | serviceMonitor: 144 | # Specifies whether a service monitor should be created 145 | create: false 146 | # Annotations to add to the service monitor 147 | annotations: {} 148 | # The name of the service monitor to use. 149 | # If not set and create is true, a name is generated using the fullname template 150 | name: "" 151 | # The scrape interval 152 | interval: 30s 153 | -------------------------------------------------------------------------------- /server-sample.yaml: -------------------------------------------------------------------------------- 1 | # LiveKit Helm chart will set up a Deployment, Service, HPA, and Ingress as either 2 | # a single or multi-node LiveKit deployment. 3 | # After installing this chart, you would still need to 4 | # * Open ports on the firewall to the hosts (see https://docs.livekit.io/deploy/ports-firewall) 5 | # * Update DNS of hostnames to the ingress/service that were created 6 | 7 | replicaCount: 1 8 | 9 | # Suggested value for gracefully terminate the pod: 5 hours 10 | terminationGracePeriodSeconds: 18000 11 | 12 | livekit: 13 | # port: 7880 14 | # Uncomment to enable prometheus metrics 15 | # prometheus_port: 6789 16 | log_level: info 17 | rtc: 18 | use_external_ip: true 19 | # default ports used 20 | port_range_start: 50000 21 | port_range_end: 60000 22 | tcp_port: 7881 23 | redis: 24 | address: 25 | # db: 0 26 | # username: 27 | # password: 28 | # use_tls: true 29 | # one or more API key/secret pairs 30 | # see https://docs.livekit.io/guides/getting-started/#generate-api-key-and-secret 31 | keys: 32 | myapikey: "myapisecret" 33 | turn: 34 | enabled: true 35 | # must match domain of your TLS cert 36 | domain: turn.myhost.com 37 | # TURN/TLS port over TCP. It must be 443 if TURN load balancer is disabled 38 | tls_port: 3478 39 | # TURN/UDP port, must be exposed on the firewall 40 | udp_port: 3478 41 | # uncomment if you will manage TLS termination for TURN, secretName is not used 42 | # when external_tls is set 43 | # external_tls: true 44 | # Kubernetes Secret containing TLS cert for 45 | # See https://docs.livekit.io/deploy/kubernetes/#importing-ssl-certificates 46 | secretName: 47 | # set the Kubernetes serviceType for the TURN service. By default it sets it to "LoadBalancer" 48 | # See kubernetes serviceTypes on official documentation: https://kubernetes.io/docs/concepts/services-networking/service/#publishing-services-service-types 49 | serviceType: "LoadBalancer" 50 | 51 | loadBalancer: 52 | # valid values: disable, alb, aws, gke, gke-managed-cert, gke-native-vpc, do 53 | # on AWS, we recommend using alb load balancer, which supports TLS termination 54 | # * in order to use alb, aws-ingress-controller must be installed 55 | # https://docs.aws.amazon.com/eks/latest/userguide/alb-ingress.html 56 | # * for gke-managed-cert type follow https://cloud.google.com/kubernetes-engine/docs/how-to/managed-certs 57 | # and set staticIpName to your reserved static IP, and certificateName to be 58 | # name of the managed cert 59 | # * for do uncomment clusterIssuer with your cert manager issuer 60 | type: disable 61 | # staticIpName: 62 | # certificateName: 63 | # clusterIssuer: letsencrypt-prod 64 | tls: 65 | # - hosts: 66 | # - livekit.myhost.com 67 | # with alb, certificates needs to reside in ACM for self-discovery 68 | # with do, use cert-manager and create certificate for turn. Load balancer is autoamtic 69 | # with gke, specify one or more secrets to use for the certificate 70 | # see: https://cloud.google.com/kubernetes-engine/docs/how-to/ingress-multi-ssl#specifying_certificates_for_your_ingress 71 | # secretName: 72 | 73 | # autoscaling requires resources to be defined 74 | autoscaling: 75 | # set to true to enable autoscaling. when set, ignores replicaCount 76 | enabled: false 77 | minReplicas: 1 78 | maxReplicas: 5 79 | targetCPUUtilizationPercentage: 60 80 | 81 | # if LiveKit should run only on specific nodes 82 | # this can be used to isolate designated nodes 83 | nodeSelector: 84 | {} 85 | # node.kubernetes.io/instance-type: c5.2xlarge 86 | 87 | resources: 88 | {} 89 | # Due to port restrictions, you can run only one instance of LiveKit per physical 90 | # node. Because of that, we recommend giving it plenty of resources to work with 91 | # limits: 92 | # cpu: 6000m 93 | # memory: 2048Mi 94 | # requests: 95 | # cpu: 4000m 96 | # memory: 1024Mi 97 | --------------------------------------------------------------------------------