Kubernetes operator — GitOps-native cluster reconciliation via custom resources.
kranix-operator runs inside your Kubernetes cluster as a controller watching Kranix's Custom Resource Definitions (CRDs). When you apply a KranixApp manifest to the cluster, the operator picks it up and drives the desired state through kranix-core. It is what makes Kranix GitOps-native: commit YAML, the operator reconciles. No manual kubectl apply chains, no out-of-band state.
- Installs and watches
KranixApp,KranixNamespace, andKranixPolicyCRDs - Runs a Kubernetes controller loop using controller-runtime
- Translates CRD spec changes into
kranix-coreoperations - Reports reconciliation status back to the CRD's
.statusfield - Supports progressive rollouts, rollback triggers, and health gates
- Respects RBAC — operates only in namespaces it has been granted access to
Git repo ──► kubectl apply ──► Kubernetes API server
│
kranix-operator
│
kranix-core
│
kranix-runtime
The operator sits between the Kubernetes API server (where CRD state lives) and kranix-core (where orchestration logic lives). It is the GitOps bridge.
The primary resource. Describes a workload you want Kranix to manage.
apiVersion: kranix.io/v1alpha1
kind: KranixApp
metadata:
name: api-server
namespace: production
spec:
image: myorg/api-server:v1.4.2
replicas: 3
namespace: production
env:
DATABASE_URL: "postgres://..."
resources:
cpu: "500m"
memory: "512Mi"
ports:
- containerPort: 8080
protocol: TCP
rollout:
strategy: RollingUpdate
maxUnavailable: 1
healthCheckPath: /healthz
healthCheckTimeout: 30s
autoHeal: true
status:
phase: Running # Pending | Deploying | Running | Degraded | Failed
readyReplicas: 3
lastReconciled: "2025-04-01T12:00:00Z"
conditions:
- type: Ready
status: "True"Declares a namespace that Kranix should manage:
apiVersion: kranix.io/v1alpha1
kind: KranixNamespace
metadata:
name: staging
spec:
labels:
env: staging
resourceQuota:
cpu: "4"
memory: "8Gi"Defines infra policies applied to workloads in a namespace:
apiVersion: kranix.io/v1alpha1
kind: KranixPolicy
metadata:
name: staging-policy
namespace: staging
spec:
enforceResourceLimits: true
defaultCpuLimit: "500m"
defaultMemoryLimit: "512Mi"
allowPrivileged: false
networkPolicy:
ingressFrom: ["production"]For each KranixApp the operator:
- Reads the
.specfrom the Kubernetes API - Calls
kranix-corewith the desired workload spec - Core computes the diff and drives
kranix-runtime - Operator watches for status events from core
- Writes observed state back to
.statuson the CRD - Re-queues after the configured resync period
If a workload enters Degraded or Failed state and autoHeal: true is set, the operator triggers automatic remediation via core.
kranix-operator/
├── cmd/
│ └── operator/ # Entry point (controller-runtime manager)
├── internal/
│ ├── controllers/
│ │ ├── kraneapp_controller.go
│ │ ├── kranenamespace_controller.go
│ │ └── kranepolicy_controller.go
│ ├── reconciler/ # Reconciler logic (calls kranix-core)
│ ├── predicates/ # Event filter predicates
│ └── webhooks/ # Admission webhooks (validation + mutation)
├── api/
│ └── v1alpha1/ # CRD Go types + generated deepcopy
├── config/
│ ├── crd/ # CRD YAML manifests (generated by controller-gen)
│ ├── rbac/ # ClusterRole, ClusterRoleBinding
│ └── manager/ # Deployment, ServiceAccount manifests
└── tests/
├── unit/
└── e2e/ # Uses envtest or a real cluster
- Go 1.22+
controller-gen(go install sigs.k8s.io/controller-tools/cmd/controller-gen@latest)- A Kubernetes cluster (
kind,minikube, or real) kranix-corereachable from inside the cluster
controller-gen crd:trivialVersions=true rbac:roleName=kranix-operator-role \
paths="./..." output:crd:artifacts:config=config/crd/baseskubectl apply -f config/crd/bases/git clone https://github.com/kranix-io/kranix-operator
cd kranix-operator
go mod download
KRANE_CORE_ADDRESS=localhost:50051 \
go run ./cmd/operator --kubeconfig ~/.kube/config# Unit tests
go test ./internal/...
# E2E with envtest
go test ./tests/e2e/... -tags e2eThe operator is deployed to the cluster via kranix-charts. Manual install:
kubectl apply -f config/rbac/
kubectl apply -f config/manager/The operator's ServiceAccount needs the following cluster permissions:
rules:
- apiGroups: ["kranix.io"]
resources: ["kraneapps", "kranenamespaces", "kranepolicies"]
verbs: ["get", "list", "watch", "create", "update", "patch"]
- apiGroups: ["kranix.io"]
resources: ["kraneapps/status"]
verbs: ["get", "update", "patch"]
- apiGroups: [""]
resources: ["namespaces", "events"]
verbs: ["get", "list", "watch", "create", "patch"]operator:
resync_period: 30s
max_concurrent_reconciles: 5
leader_election: true
leader_election_namespace: kranix-system
core:
address: "kranix-core.kranix-system.svc.cluster.local:50051"
metrics:
port: 8383
health:
port: 8081| Repo | Relationship |
|---|---|
kranix-core |
Operator calls core for all reconciliation logic |
kranix-charts |
Operator is packaged and deployed via Helm charts |
kranix-packages |
Imports CRD types and shared utilities |
| Kubernetes API | Operator watches and updates CRDs via controller-runtime |
See CONTRIBUTING.md. CRD type changes require regenerating deepcopy and CRD YAML via controller-gen. All controllers must have E2E tests using envtest.
Apache 2.0 — see LICENSE.