Actors/Packages/Kubernetes/Installation
@sigx/actors-k8s · Preview

Installation#

One Role, one RoleBinding, and everything else is discovered from the pod.

Install#

Terminal
pnpm add @sigx/actors-k8s

RBAC#

The ServiceAccount needs Lease access in the host namespace, and nothing else:

YAML
apiVersion: rbac.authorization.k8s.io/v1
kind: Role
metadata:
    name: sigx-actors-membership
rules:
    - apiGroups: ["coordination.k8s.io"]
      resources: ["leases"]
      verbs: ["get", "list", "watch", "create", "update", "patch", "delete"]
---
apiVersion: rbac.authorization.k8s.io/v1
kind: RoleBinding
metadata:
    name: sigx-actors-membership
roleRef:
    apiGroup: rbac.authorization.k8s.io
    kind: Role
    name: sigx-actors-membership
subjects:
    - kind: ServiceAccount
      name: my-host

Options#

OptionDefaultMeaning
namespaceServiceAccount namespace, else defaultwhere the Leases live
clusterNamedefaultvalue of the sigx.dev/cluster label — two clusters can share a namespace
labelsextra labels stamped on the own Lease and selecting peers
leasePrefixsigxLease names are {leasePrefix}-{hostId}
heartbeatMs5000Lease renewal cadence
ttlMs15000liveness TTL, serialized as spec.leaseDurationSeconds
clockSkewMs2000slack added to peer freshness checks
relistMs60000reconciling LIST cadence under the watch; 0 disables
apiServerin-cluster env, else https://kubernetes.default.svcAPI server origin
tokenServiceAccount token filebearer token, or a provider function
caServiceAccount ca.crtPEM bundle
fetchnode:https shimtransport override
watchBackoff{ minMs: 250, maxMs: 5000 }watch reconnect bounds

Clocks#

renewTime is written by each host's own clock and compared against the observer's, so peer freshness assumes NTP-synced nodes — the same assumption kubelet node Leases make. clockSkewMs is the slack; raise it if your nodes drift more.

If that assumption is uncomfortable, pgMembership() judges expiry on the database clock instead.

Scale#

Every renewal is a watch event delivered to every host: n hosts beating every 5s ≈ n²/5 events per second cluster-wide.

At tens of hosts this is trivial — 30 hosts is about 180 tiny JSON lines per second, and none of them touch the membership view, because renewals never bump its version. Only descriptor-set changes (join, leave, drain, expiry) do.

For hundreds of hosts, raise heartbeatMs and ttlMs; the volume falls quadratically.

Local development#

Kubeconfigs are deliberately not parsed — client certificates and exec plugins are a dependency magnet. Let kubectl do the auth instead:

Terminal
kubectl proxy --port=8001
TypeScript
k8sMembership({ apiServer: 'http://127.0.0.1:8001', token: '', ca: '' });

Next steps#