Skip to content

Quick Start

This guide gets you from zero to a running Android emulator in a Kubernetes cluster. No KVM nodes, no kernel modules, no node preparation required.

Prerequisites

  • Kubernetes 1.28+
  • kubectl and helm (3.x) in your PATH
  • TURN server credentials (you can generate random ones for internal clusters)

Cilium prerequisites

DroidFarm's per-device streaming pipeline depends on two Cilium Gateway-API flags that ship as false by default and that a Cilium Helm upgrade at the cluster level resets back to false every time it runs:

  • enable-gateway-api-alpn — without this, the TLS listener does not advertise ALPN h2, browsers fall back to HTTP/1.1, and Cilium strips the gRPC-Web trailer frame. The WebRTC UI stays on "connecting" forever.
  • enable-gateway-api-app-protocol — without this, Cilium ignores the per-device Service's appProtocol: kubernetes.io/h2c and speaks HTTP/1.1 to the in-pod envoy sidecar. The emulator's gRPC backend is unreachable.

Run the helper script before installing DroidFarm:

./scripts/cilium-prereqs.sh

It patches kube-system/cilium-config, restarts cilium-operator and the cilium DaemonSet, and is safe to re-run (idempotent — it skips if both flags are already true).

Re-run this script after every Cilium Helm upgrade at the cluster level — or bake the same two values into your Cilium Helm values overlay so they survive upgrades automatically.

Step 1 — Add the Helm repo

helm repo add droidfarm https://christopherime.github.io/droidfarm/
helm repo update

Step 2 — Deploy DroidFarm

helm install droidfarm droidfarm/droidfarm \
  --namespace droidfarm-system \
  --create-namespace \
  --set turn.credentials.username=myuser \
  --set turn.credentials.password=mypass

No node preparation needed. The cuttlefish-qemu backend runs the Android device using QEMU software emulation inside the container. WebRTC is built-in at port 8443. Any standard Kubernetes node works.

Verify all pods are running:

kubectl get pods -n droidfarm-system

Expected output:

NAME                                  READY   STATUS    RESTARTS   AGE
droidfarm-operator-6b9d4f8b5c-x7kp   1/1     Running   0          30s
droidfarm-dashboard-7d6c9f4b9d-q2lm   1/1     Running   0          30s
droidfarm-coturn-5f8c6b7d9f-p8nw      1/1     Running   0          30s

Step 3 — Create a DeviceTemplate

A DeviceTemplate is the device profile — Android version, hardware profile, APKs to install, permissions, and system settings.

kubectl apply -f manifests/examples/device-template-basic.yaml

Or create one inline:

kubectl apply -f - <<EOF
apiVersion: droidfarm.io/v1alpha1
kind: DeviceTemplate
metadata:
  name: android14-basic
  namespace: droidfarm-system
spec:
  androidVersion: "14"
  emulationBackend: cuttlefish-qemu   # no KVM required
  avdProfile: pixel_6
  resources:
    cpu: "2"
    memory: "4Gi"
  appConfig:
    - packageName: com.example.myapp
      apkSource:
        url: https://artifacts.example.com/app.apk
      autoLaunch: true
      clearDataBetweenSessions: true
EOF

Expect a boot time of approximately 5–10 minutes for the first device in the pool.

Step 4 — Create a DevicePool

A DevicePool defines a fleet backed by a template.

kubectl apply -f - <<EOF
apiVersion: droidfarm.io/v1alpha1
kind: DevicePool
metadata:
  name: staging-pool
  namespace: droidfarm-system
spec:
  templateRef:
    name: android14-basic
  replicas:
    min: 1
    max: 4
  streaming:
    enabled: true
    domain: local.geekxflood.io
EOF

The operator generates one HTTPRoute per device on the cluster's shared Cilium Gateway (kube-system/cilium-gateway, listener section https). With the snippet above, the first device's stream URL is https://staging-pool-0.local.geekxflood.io.

Watch devices come online:

kubectl get devicepool staging-pool -n droidfarm-system -w

Step 5 — Run a test session

Once the pool has at least one Idle device, create a TestSession:

kubectl create -f manifests/examples/test-session-basic.yaml

Poll until it reaches Running:

kubectl get testsession -n droidfarm-system -w

Retrieve the Appium endpoint and stream URL:

kubectl get testsession <name> -n droidfarm-system \
  -o jsonpath='{.status.appiumEndpoint}{"\n"}{.status.streamURL}{"\n"}'

Step 6 — Open the per-device URL

The streamURL printed in the previous step is a fully qualified HTTPS URL served by the cluster's shared Cilium Gateway (kube-system/cilium-gateway, listener section https) and terminated with the wildcard certificate for *.<streaming.domain>. Paste it into a browser:

https://staging-pool-0.local.geekxflood.io

The browser hits the shared Cilium Gateway over HTTP/2 (ALPN h2), the matching HTTPRoute forwards to the per-device envoy sidecar over h2c, and Cuttlefish's web UI loads. From there it negotiates WebRTC media directly with the emulator (coturn-relayed if your browser and the emulator can't reach each other directly).

If the page never loads, the most common causes are:

  • enable-gateway-api-alpn: true is missing in kube-system/cilium-config — the browser drops to HTTP/1.1 and the gRPC-Web trailer is stripped on the way back.
  • The wildcard DNS record *.<streaming.domain> does not point to the shared Gateway's LoadBalancer address.
  • The shared Cilium Gateway's wildcard TLS certificate does not cover *.<streaming.domain>.

Step 7 — Open the dashboard

For quick local access:

kubectl port-forward -n droidfarm-system svc/droidfarm-dashboard 8080:8080

Then open http://localhost:8080 in your browser.

To expose the dashboard through the shared Cilium Gateway instead, enable the HTTPRoute:

helm upgrade droidfarm droidfarm/droidfarm \
  --namespace droidfarm-system \
  --reuse-values \
  --set dashboard.gateway.enabled=true \
  --set dashboard.gateway.hostname=droidfarm.local.geekxflood.io

The route attaches to kube-system/cilium-gateway listener https; the shared Gateway terminates TLS via its wildcard cert, so no extra cert plumbing is required on the chart side.

Using hardware acceleration (optional)

If your nodes have /dev/kvm, set emulationBackend: cuttlefish for approximately 10x faster boot times (~60 s vs ~5–10 min). See Hardware Acceleration for node setup instructions.

Next steps