Skip to content

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 ALPN h2. 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's appProtocol: kubernetes.io/h2c and 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:

./scripts/cilium-prereqs.sh

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 gatewayClassName or 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

Uninstall

helm uninstall droidfarm -n droidfarm-system
# CRDs are not deleted automatically — remove manually if desired:
kubectl delete crd devicetemplates.droidfarm.io devicepools.droidfarm.io testsessions.droidfarm.io