Helm Installation¶
Add the chart repository¶
helm repo add droidfarm https://christopherime.github.io/droidfarm/
helm repo update
helm search repo droidfarm
Install¶
helm install droidfarm droidfarm/droidfarm \
--namespace droidfarm-system \
--create-namespace \
--set turn.credentials.username=<user> \
--set turn.credentials.password=<pass>
Upgrade¶
helm upgrade droidfarm droidfarm/droidfarm \
--namespace droidfarm-system \
--reuse-values \
--set operator.image.tag=v0.2.0
Install from source¶
git clone https://github.com/christopherime/droidfarm.git
cd droidfarm
helm install droidfarm charts/droidfarm/ \
--namespace droidfarm-system \
--create-namespace \
--set turn.credentials.username=myuser \
--set turn.credentials.password=mypass
Key values¶
| Key | Default | Description |
|---|---|---|
operator.image.repository | ghcr.io/christopherime/droidfarm-operator | Operator image |
operator.image.tag | latest | Operator image tag |
dashboard.image.repository | ghcr.io/christopherime/droidfarm-dashboard | Dashboard image |
dashboard.image.tag | latest | Dashboard image tag |
dashboard.gateway.enabled | false | Opt-in: render an HTTPRoute that attaches the dashboard Service to the cluster's shared Gateway |
dashboard.gateway.hostname | droidfarm.example.com | Hostname the dashboard responds to (must be covered by the parent Gateway's listener cert) |
dashboard.gateway.parentRef.name | cilium-gateway | Parent Gateway name |
dashboard.gateway.parentRef.namespace | kube-system | Parent Gateway namespace |
dashboard.gateway.parentRef.sectionName | https | Listener section on the parent Gateway |
streaming.gateway.enabled | false | Opt-in: render a dedicated streaming Gateway (most installs leave this off and attach to the cluster's shared Cilium Gateway) |
streaming.gateway.name | droidfarm-stream | Name used for the dedicated Gateway when enabled: true |
streaming.gateway.gatewayClassName | cilium | gatewayClassName for the dedicated Gateway |
streaming.gateway.domain | streaming.example.com | Base domain; dedicated listener hostname becomes *.<domain> |
streaming.gateway.tlsSecretName | droidfarm-stream-tls | Secret backing the wildcard TLS cert on the dedicated Gateway |
streaming.gateway.certManager.enabled | false | Create a cert-manager Certificate for *.<domain> on the dedicated Gateway |
streaming.gateway.certManager.clusterIssuer | "" | cert-manager ClusterIssuer (e.g. the same one the dashboard uses) |
turn.credentials.username | "" | Required — TURN server username |
turn.credentials.password | "" | Required — TURN server password |
turn.port | 3478 | TURN/STUN UDP port |
keda.enabled | false | Enable KEDA ScaledObject |
monitoring.serviceMonitor.enabled | false | Enable Prometheus ServiceMonitor |
monitoring.serviceMonitor.namespace | monitoring | Namespace for ServiceMonitor |
Cilium prerequisites¶
Whether you use the shared Cilium Gateway or a dedicated one, two flags must be set in kube-system/cilium-config:
enable-gateway-api-alpn: true— so the TLS listener advertises ALPNh2. Without this the browser drops to HTTP/1.1 and Cilium strips the gRPC-Web trailer frame.enable-gateway-api-app-protocol: true— so Cilium honours the per-device Service'sappProtocol: kubernetes.io/h2cand speaks HTTP/2 to the in-pod envoy sidecar.
Both default to false, and a Cilium Helm upgrade at the cluster level resets them back to false. Apply (and re-apply) them with the helper script:
The script is idempotent: it patches kube-system/cilium-config, rolls cilium-operator and the cilium DaemonSet, and skips when both flags are already true. Re-run it after every Cilium upgrade — or bake the same two values into your Cilium Helm values overlay so they survive upgrades automatically.
Never commit TURN credentials
Always pass credentials via --set or a sealed values overlay. Do not store them in values.yaml or commit them to git.
Per-Device Streaming Gateway (opt-in)¶
By default the chart does not render a Gateway. Per-device HTTPRoute objects attach directly to the cluster's shared Cilium Gateway — kube-system/cilium-gateway, listener section https — which is the Cilium 1.18+ cluster-wide Gateway pattern. Every DevicePool.spec.streaming block already targets that Gateway by default; pools only need a domain value to start serving per-device URLs.
Enable streaming.gateway only when you want a dedicated Gateway for streaming traffic. Typical reasons:
- Isolation — separate LoadBalancer IP, separate listener config, separate observability scope from the cluster's general-purpose Gateway.
- Dedicated certificate — a wildcard cert that should not live on the shared Gateway.
- A different
gatewayClassNameor annotation set than the shared Gateway provides.
When enabled, the chart renders a Gateway named streaming.gateway.name (default droidfarm-stream) with an HTTPS listener for *.<streaming.gateway.domain>, plus the wildcard cert via cert-manager. Point each DevicePool at this Gateway with:
spec:
streaming:
domain: streaming.example.com
gatewayName: droidfarm-stream # the name set under streaming.gateway.name
gatewayNamespace: droidfarm-system
gatewaySectionName: https
Minimal production values¶
The defaults assume the cluster already exposes a shared Cilium Gateway at kube-system/cilium-gateway with an https listener whose wildcard cert covers the streaming domain. Most installs only need to set credentials and turn on optional subsystems:
# values-prod.yaml
operator:
image:
tag: v0.1.0
dashboard:
image:
tag: v0.1.0
keda:
enabled: true
monitoring:
serviceMonitor:
enabled: true
Then set the streaming domain per DevicePool (see DevicePool CRD reference) so each device gets its own hostname under that domain.
To use a dedicated Gateway instead of the shared one, also set:
streaming:
gateway:
enabled: true
name: droidfarm-stream
gatewayClassName: cilium
domain: streaming.example.com
tlsSecretName: droidfarm-stream-tls
certManager:
enabled: true
clusterIssuer: cloudflare-issuer
Each DevicePool then needs spec.streaming.gatewayName: droidfarm-stream and spec.streaming.gatewayNamespace: droidfarm-system to attach there instead of the cluster default.
Apply:
helm upgrade --install droidfarm droidfarm/droidfarm \
--namespace droidfarm-system \
--create-namespace \
-f values-prod.yaml \
--set turn.credentials.username=$TURN_USER \
--set turn.credentials.password=$TURN_PASS