The complete celld-operator.io/v1alpha1WorkerApp API:
every spec field with its default and validation, and the full status surface. One
WorkerApp is one celld fleet serving one application deployment, so the resource, the
fleet, and the app are 1:1:1.
Hostnames routed to this app on the shared Gateway; one route per hostname is reconciled in the app's namespace. Omit for internal-only apps.
appVersion
string
yes
unset
The application deployment in the fleet bucket (written by celld deploy). Changing it triggers the gated rollout. The sentinel auto follows the bucket's deploy/current.json instead.
replicas
int32 ≥ 1
no
3
Fleet size when autoscaling is disabled; the initial size otherwise.
websockets
bool
no
false
Selects the WebSocket ingress profile: session affinity, long idle timeouts, conservative scale-down.
The celld container image, tag included (e.g. ghcr.io/denoland/celld:v0.2.0). Mixed-version fleets are never created; changing this triggers the update strategy.
celld.updateStrategy
Rolling | Recreate
no
Rolling
Rollout path for celld version changes. Rolling is partition-stepped and restoring-gated; a Rolling request across a known-breaking celld boundary is refused. Recreate scales to zero first, which is an availability event by design.
The fleet bucket and prefix, e.g. s3://platform-cells/apps/chat or gs://…. The store must satisfy the fencing contract.
bucket.endpoint
string
no
unset
S3-compatible endpoint URL when not AWS S3 (e.g. an R2 account endpoint). Rejected by celld for gs:// buckets.
bucket.region
string
no
unset
Storage region, when it cannot be inferred (auto for R2).
bucket.credentialsFrom.iamRole
string
no
unset
IAM role ARN assumed via the pod's service account (IRSA / Workload Identity), or the literal auto to have the operator provision a prefix-scoped role. auto provisioning is not implemented yet, so the fleet reports BucketCredentialsReady: False and you annotate the fleet ServiceAccount yourself.
bucket.credentialsFrom.secretRef
string
no
unset
A Secret with static credentials (AWS_ACCESS_KEY_ID / AWS_SECRET_ACCESS_KEY), for stores without role-based auth. Exactly one mechanism applies; prefer iamRole.
Container memory limit per pod, in GiB. The operator derives CELLD_MAX_RSS_MB (~80% of the limit, set explicitly because the upstream default is not cgroup-aware).
resources.maxResidentCells
int32 ≥ 1
no
1000
Hard per-node resident-cell admission limit (CELLD_MAX_RESIDENT_CELLS). Upstream sizing: ~1,000 cells per 8 GiB.
Secret whose vars.env data (NAME=value lines) is mounted and passed via CELLD_VARS_FILE. Rotation rolls the fleet through an ordinary gated rollout.
service.type
ClusterIP | LoadBalancer | NodePort
no
ClusterIP
Shape of the serving Service fronting the Worker listener. ClusterIP suits ingress backends and in-cluster consumers (<app>-celld.<ns>.svc:8080); LoadBalancer provisions a cloud LB; NodePort suits bare-metal edges.
Materializes a KEDA ScaledObject over the operator's /state-derived metrics; paused during rollouts.
autoscaling.minReplicas
int32 ≥ 1
no
2
Scale floor; keep ≥ 2 for HA. Also the PodDisruptionBudget floor.
autoscaling.maxReplicas
int32 ≥ 1
no
10
The tenant's cost ceiling.
autoscaling.targets.residentCellUtilization
int32 1-100
no
70
Target fleet-average percentage of occupied vs maxResidentCells. Conservative by default, since celld has no rebalancer. Any shedding pod triggers scale-up regardless.
autoscaling.targets.p95LatencyMs
int32 ≥ 1
no
unset
Optional gateway-side latency target so traffic-bound, stateless-heavy apps scale even at low cell counts. Unset disables the latency signal.