Photon¶
Photon is the self-hosted geocoder that backs Tomoda's place-search autocomplete. It runs as a single in-cluster Deployment in the data namespace, serves the backend on photon.data.svc.cluster.local:2322, and pulls its index from a GCS bucket maintained by the Photon Indexer.
The Argo CD Application at k8s/apps/photon/application.yaml points at k8s/apps/photon/manifests.yaml and syncs into namespace: data.
Image and replication¶
image: rtuszik/photon-docker:2.2.0
The tag is pinned deliberately. Photon's index file format is sensitive to the binary version: a mismatch between the running pod and the index in the GCS bucket will fail to load. When bumping this tag also bump the matching tag in k8s/apps/photon-indexer/Dockerfile (PHOTON_RUNTIME_IMAGE) and in the developer-facing docker-compose.dev.yml over in the application repo. rtuszik/photon-docker:2.2.0 ships Photon 1.1.0.
Deployment is single-replica with strategy.type: Recreate. There is no rolling update — when a new pod comes up the old one must already be gone, because both would want to mount the same ReadWriteOnce PVC. Multi-replica scale-out is not supported by this layout; Photon itself can be replicated but would need a per-pod copy of the index (or RWX storage, which we don't run).
Storage¶
A single PersistentVolumeClaim named photon-data-pvc requests 250 Gi on the standard-rwo StorageClass:
accessModes: [ReadWriteOnce]
storageClassName: standard-rwo
resources:
requests:
storage: 250Gi
The size is set for UPDATE_STRATEGY=PARALLEL (see below) — during an atomic swap both the current index and the incoming index sit on disk side-by-side, so peak usage is roughly 2× the index size.
Resources and probes¶
requests: { memory: 2Gi, cpu: 250m }
limits: { memory: 6Gi, cpu: 2000m }
JAVA_OPTS=-Xmx4g caps the heap inside the limit. The cold-start path (load index from disk, warm Lucene) is slow, so probes are tuned long:
| Probe | Path | Initial delay | Period | Notes |
|---|---|---|---|---|
| Readiness | /status |
120s | 30s | Pod stays out of the Service until Photon answers |
| Liveness | /status |
300s | 60s | failureThreshold: 10 to tolerate transient stalls during the atomic swap |
Index updates¶
Photon is configured to auto-update from a static GCS URL:
env:
- name: UPDATE_STRATEGY
value: "PARALLEL" # atomic swap; no downtime
- name: UPDATE_INTERVAL
value: "24h" # poll the MD5 once a day
- name: FILE_URL
value: "https://storage.googleapis.com/development-485000-photon-index/planet/photon-db-planet-multilang-latest.tar.bz2"
- name: MD5_URL
value: "https://storage.googleapis.com/development-485000-photon-index/planet/photon-db-planet-multilang-latest.tar.bz2.md5"
The bucket is ${project_id}-photon-index. Photon polls the .md5 once every 24h; if it has changed it downloads the new tar alongside the running index, verifies the checksum, and atomically flips to the new index. This is the only update path — bumping the bucket contents is what rolls Photon forward.
Multilingual index¶
The index served from the bucket today is the 28-language multilingual build covering: en, ja, ko, zh, zh-Hans, zh-Hant, ar, he, hi, vi, th, id, tr, es, fr, de, it, pt, nl, pl, ru, sv, no, da, fi, el, cs, uk. This list mirrors services.SupportedLocalizationLanguages in the backend.
The multilingual rollout is in progress — see the Photon Multilang Rollout runbook for current status, per-region cutover plan, and how to verify the running pod is serving the new index.
Service¶
kind: Service
metadata:
name: photon
namespace: data
spec:
type: ClusterIP
ports:
- port: 2322
targetPort: 2322
Backend pods reach Photon at http://photon.data.svc.cluster.local:2322 — this exact URL is wired into the Tomoda backend Deployment as PHOTON_URL. The Service is not exposed via Ingress; there is no public Photon endpoint.
Operations¶
- New index — build it via Photon Indexer (or the local script), upload to GCS, update the
*-latestaliases. The running pod picks it up within 24h. - Force an update — restart the pod; on boot Photon re-checks the MD5 and downloads if the local copy is stale.
- Storage pressure — if the PVC fills (large planet rebuild), expand it via
kubectl edit pvc photon-data-pvcon a CSI driver that supports online expansion. Then bounce the pod. - Version bump — coordinate the runtime image and the indexer image in the same PR; cross-version index loads will fail readiness.