Skip to content

Repository files navigation

sei-k8s-controller

A Kubernetes operator for managing the full lifecycle of Sei blockchain infrastructure. It defines two CRDs — SeiNetwork and SeiNode — under the sei.io/v1alpha1 API group.

Overview

SeiNetwork orchestrates fleets of nodes: it manages genesis ceremonies, coordinates deployments, and provisions networking and monitoring. SeiNode manages a single Sei node — its PVC, StatefulSet, headless Service, and sidecar-driven bootstrap.

Key design decisions

  • One StatefulSet per node — each SeiNode gets its own single-replica StatefulSet rather than pooling nodes. Groups exist for fleet coordination.
  • Dedicated node scheduling — pods require karpenter.sh/nodepool=sei-node and tolerate sei.io/workload=sei-node:NoSchedule, keeping blockchain workloads off general-purpose nodes.
  • Sidecar architecture — every node runs a sei-sidecar container (built from sidecar/ in this repo) as a restartable init container that drives bootstrap tasks before seid starts and handles runtime operations afterward. The controller renders no command for it; the image's entrypoint is the command.
  • Plan model — bootstrap is driven by a TaskPlan stored in status.plan. The controller builds a task sequence based on the node's mode, submits tasks to the sidecar one at a time, and advances through the plan.
  • Environment-driven genesis — genesis resolution is handled by the sidecar autonomously. Embedded sei-config is checked first for well-known chains (pacific-1, atlantic-2, arctic-1), then S3 fallback at {SEI_GENESIS_BUCKET}/{chainID}/genesis.json.

CRDs

SeiNetwork

Bootstraps a new Sei chain via a genesis ceremony that mints the chain's genesis.json and its founding validator set. replicas are the genesis validators; each gets a distinct ceremony-generated identity. The spec is scalar (no SeiNode template) — the controller synthesizes each child SeiNode's validator spec from these fields. replicas, genesis, and dataVolume are immutable after create (the validator set and on-disk identity are minted into genesis state at the ceremony).

apiVersion: sei.io/v1alpha1kind: SeiNetworkmetadata:
name: devnetspec:
replicas: 4image: sei-protocol/seid:v6.3.0genesis:
chainId: my-devnetstakingAmount: "10000000usei"

spec.sidecar.image is omitted here on purpose, as in every sample under manifests/samples/: the sidecar image comes from images.sidecar in the platform app-config, so one value governs a whole cell. Setting it per node overrides that, and a pin left behind on an older image outlives a coordinated entrypoint change — the container then exits 0 in a restart loop while seid waits on /v0/healthz behind a five-day startup probe. Pin only to debug, and only to an image whose entrypoint matches what the controller renders.

SeiNode

Manages a single Sei node. Supports full nodes, validators, archivers, and replayers.

apiVersion: sei.io/v1alpha1kind: SeiNodemetadata:
name: mainnet-0spec:
chainId: pacific-1image: sei-protocol/seid:v5.0.0fullNode:
snapshot:
s3:
targetHeight: 100000000trustPeriod: "9999h0m0s"peers:
- ec2Tags:
region: us-east-2tags:
Network: pacific-1

Bootstrap modes (determined by spec):

ModeConditionKey tasks
Full nodespec.fullNode setconfigure-genesis > snapshot-restore > config-apply > mark-ready
Validatorspec.validator setSame as full node, or genesis ceremony flow for new networks
Archivespec.archive setState sync with archival pruning configuration
Replayerspec.replayer setSnapshot restore with result export for shadow validation

SeiNodeTask

A one-shot operation against a single SeiNode (governance votes/proposals, image updates, height/condition waits). See https://github.com/sei-protocol/bdchatham-designs/blob/main/designs/seinode-task/seinode-task.md for the kinds, lifecycle, signing topology, idempotency, and operational gotchas.

Platform Configuration

Infrastructure-level settings (node pools, storage, resources, snapshot/genesis/result-export buckets, sidecar images) are read from the mounted app-config file (SEI_CONTROLLER_CONFIGplatform.FileConfig), which is authoritative — the controller fails fast at startup if a required field is unset. See the controller-app-config schema (in bdchatham-designs — relocated per Design 05 / PLT-497).

Gateway config (SEI_GATEWAY_NAME, SEI_GATEWAY_NAMESPACE, SEI_GATEWAY_DOMAIN) and the config-file path (SEI_CONTROLLER_CONFIG) remain environment variables.

Development

make build # Build the manager binary
make test# Run unit tests
make lint # Run golangci-lint
make manifests generate # Regenerate CRDs, RBAC, DeepCopy after type changes

Deployment

The controller image is built and pushed to ECR by GitHub Actions on every push to main.

Deployment ordering: When adding new environment variables to the sidecar, the controller must be deployed first — it injects env vars into pod specs. If the sidecar image is updated before the controller, existing pods will crash because they lack the new env vars. The safe sequence is: (1) deploy the controller, (2) then update the sidecar image in SeiNode specs.

That ordering holds only for additive env vars. It does not hold for a change to the sidecar's entrypoint or binary name: the controller renders no Command, so the image's ENTRYPOINT is the command, and the two must move together. Split apart, the container prints help and exits 0 in a restart loop while seid waits on /v0/healthz behind a FailureThreshold: 86400 probe — silent for roughly five days. See CLAUDE.md, "The sidecar binary".

The config/ directory follows the standard Kubebuilder layout:

config/
├── crd/ # Generated CRD manifests (SeiNode, SeiNetwork)
├── rbac/ # ServiceAccount, ClusterRole, bindings, leader election
├── manager/ # Deployment and metrics Service
├── monitoring/ # PrometheusRule and ServiceMonitor
├── network-policy/ # Metrics traffic NetworkPolicy
└── default/ # Top-level kustomization (namePrefix: sei-k8s-)

Platform repos reference config/default as a remote kustomize base:

apiVersion: kustomize.config.k8s.io/v1beta1kind: Kustomizationnamespace: sei-k8s-controller-systemresources:
- github.com/sei-protocol/sei-k8s-controller/config/default?ref=main
- namespace.yaml

About

A Kubernetes controller used to manage Sei network nodes.

Resources

Stars

1 star

Watchers

0 watching

Forks

Releases

Packages

Contributors

Languages