# Run Tachyon on Kubernetes
URL: /docs/guides/kubernetes

A StatefulSet, Service, and PVC for running Tachyon on Kubernetes — Tachyon has no clustering, so this runs exactly one pod.



Tachyon has no first-party Helm chart or manifest — see
[Deployment → Orchestration](/docs/deployment#orchestration) for why, and
the [Roadmap](/roadmap) for what's planned. What follows is a manifest you
can adapt, applying Tachyon's own image and flags to plain Kubernetes
primitives.

<Callout type="warn">
  Tachyon has no clustering or replication — see the
  [Roadmap](/roadmap). Running more than one replica does **not** give you
  a distributed Tachyon; each pod would be an independent, separately-
  indexed instance. This manifest deliberately runs exactly one.
</Callout>

## Why a StatefulSet, not a Deployment [#why-a-statefulset-not-a-deployment]

A `Deployment` assumes replicas are interchangeable and disposable. Tachyon
is a single stateful instance with its own persistent volume — a
`StatefulSet` with `replicas: 1` gives it a stable identity and a
`volumeClaimTemplate` that survives pod restarts, which is what a single
persistent search index actually needs.

## Secret for API keys [#secret-for-api-keys]

```bash
kubectl create secret generic tachyon-keys \
  --from-literal=admin-key=change-me-before-anything-shared \
  --from-literal=search-key=a-different-read-only-key
```

## Manifest [#manifest]

```yaml
# tachyon.yaml
apiVersion: apps/v1
kind: StatefulSet
metadata:
  name: tachyon
spec:
  serviceName: tachyon
  replicas: 1
  selector:
    matchLabels:
      app: tachyon
  template:
    metadata:
      labels:
        app: tachyon
    spec:
      containers:
        - name: tachyon
          image: adikeshri/tachyon:latest
          ports:
            - containerPort: 8108
              name: http
          env:
            - name: TACHYON_ADMIN_KEY
              valueFrom:
                secretKeyRef:
                  name: tachyon-keys
                  key: admin-key
            - name: TACHYON_SEARCH_KEY
              valueFrom:
                secretKeyRef:
                  name: tachyon-keys
                  key: search-key
            - name: TACHYON_DATA_DIR
              value: /data
          volumeMounts:
            - name: data
              mountPath: /data
          readinessProbe:
            httpGet:
              path: /health
              port: 8108
            initialDelaySeconds: 5
            periodSeconds: 10
          livenessProbe:
            httpGet:
              path: /health
              port: 8108
            initialDelaySeconds: 15
            periodSeconds: 20
  volumeClaimTemplates:
    - metadata:
        name: data
      spec:
        accessModes: ["ReadWriteOnce"]
        resources:
          requests:
            storage: 20Gi
---
apiVersion: v1
kind: Service
metadata:
  name: tachyon
spec:
  selector:
    app: tachyon
  ports:
    - port: 8108
      targetPort: 8108
```

`/health` is documented as always public regardless of auth configuration —
see [Configuration → Authentication](/docs/configuration#authentication) —
which is exactly what makes it usable for both probes without also handing
the kubelet an API key.

## Sizing the volume [#sizing-the-volume]

`storage: 20Gi` above is a placeholder, not a recommendation. Segment disk
usage scales with corpus size — see [Persistence](/docs/persistence) and
the disk-size figures in the [preliminary benchmark](/benchmarks) for a
starting point, then size for headroom: segment merges briefly need space
for both the old and new segment simultaneously.

## Applying it [#applying-it]

```bash
kubectl apply -f tachyon.yaml
kubectl get pods -w
```

From inside the cluster, other workloads reach Tachyon at
`http://tachyon:8108` (or `tachyon.<namespace>.svc.cluster.local` from a
different namespace). Nothing above exposes it outside the cluster — add an
`Ingress` only for routes you actually intend to expose, and only ever with
`TACHYON_SEARCH_KEY`, never the admin key, reachable from outside.
