Resource Governance
This document describes the compute resource governance model of TFRS Operator, including ResourceQuota management, component resource defaults, and auto-fill mechanisms.
Governance Model Overviewâ
ResourceQuota (Namespace-level)
âââ TFRTenant Internal Components (12) ââ User config > Operator defaults
âââ TFRServer Containers (3) ââ User config > Operator defaults
Core logic: When a namespace has a ResourceQuota with CPU/Memory constraints, Kubernetes requires all containers to declare resources. The Operator uses a three-layer mechanism to prevent Pod rejection by the apiserver:
- Component resource auto-fill: Components without explicit config use Operator defaults
- LimitRange defaults: Provides fallback resources for third-party operator injected containers (e.g., MinIO sidecar)
- Istio sidecar annotations: Declares resources for the istio-proxy container
ResourceQuota Managementâ
Enablingâ
Controlled via the spec.resourceQuota field of the TFRTenant CR:
apiVersion: infra.tfrobot.io/v1
kind: TFRTenant
spec:
resourceQuota:
enabled: true
spec:
hard:
requests.cpu: "8"
requests.memory: "16Gi"
limits.cpu: "16"
limits.memory: "32Gi"
pods: "50"
- CRD type definition:
api/infra/v1/tfrtenant_types.go:316-329 - Deployable implementation:
internal/controller/infra/tenant/resource_quota.go
Lifecycleâ
| Operation | Behavior |
|---|---|
enabled: true | Creates or updates the tfrs-quota-{tenantName} object |
enabled: true + compute resources | Also creates tfrs-limit-{tenantName} LimitRange |
enabled: false | Auto-deletes both ResourceQuota and LimitRange |
| TFRTenant deletion | Cascade-deleted via OwnerReference |
| Spec change | Spec drift detection auto-corrects (resource_quota.go:155-191) |
LimitRange Auto-Creationâ
When ResourceQuota contains compute resources (CPU/Memory), the Operator automatically creates a LimitRange to provide default values for containers without resource declarations:
| Type | Default (limits) | DefaultRequest (requests) |
|---|---|---|
| Container | 50m / 64Mi | 10m / 32Mi |
Positioned as a "minimum safety net": only prevents containers without resource declarations from being rejected by Quota, not intended as reasonable defaults. Solves the problem of third-party operator injected containers (e.g., MinIO's sidecar and validate-arguments) lacking resource declarations and being rejected by ResourceQuota.
Implementation: internal/controller/infra/tenant/resource_quota.go
Istio Sidecar Resource Annotationsâ
When a component has Resources set, the Operator automatically adds Istio sidecar resource annotations to the Pod:
| Annotation | Value |
|---|---|
sidecar.istio.io/proxyCPU | 10m |
sidecar.istio.io/proxyMemory | 64Mi |
sidecar.istio.io/proxyCPULimit | 100m |
sidecar.istio.io/proxyMemoryLimit | 128Mi |
Implementation: MergeIstioSidecarAnnotations() in internal/controller/infra/tenant/resources.go
Quota Detectionâ
The Operator detects whether a namespace has compute resource quotas through two methods:
- APIServer query: Checks all ResourceQuota objects in the namespace (
resources.go:192-213) - TFRTenant Spec check: Handles first reconcile when the ResourceQuota object doesn't exist yet (
resources.go:172-188)
Monitored fields: requests.cpu, requests.memory, limits.cpu, limits.memory â matching any one triggers auto-fill.
Entry point: tfrtenant_controller.go:276-277
TFRTenant Component Resourcesâ
Default Valuesâ
All defaults are defined in internal/controller/infra/tenant/resources.go:
| Component | Requests (CPU/Mem) | Limits (CPU/Mem) |
|---|---|---|
| PostgreSQL | 200m / 256Mi | 1000m / 1Gi |
| MinIO | 200m / 256Mi | 1000m / 1Gi |
| RabbitMQ | 200m / 256Mi | 1000m / 1Gi |
| TimescaleDB | 250m / 1Gi | 500m / 2Gi |
| TFRSUtils Worker | 250m / 256Mi | 1000m / 2Gi |
| Prometheus | 100m / 128Mi | 500m / 512Mi |
| Redis Server | 100m / 128Mi | 500m / 512Mi |
| OtelCollector | 100m / 128Mi | 500m / 512Mi |
| Vector | 100m / 128Mi | 500m / 512Mi |
| Grafana | 100m / 128Mi | 500m / 512Mi |
| TFRSUtils Beat | 100m / 128Mi | 500m / 512Mi |
| Jaeger | 50m / 128Mi | 500m / 1Gi |
| TFRobotFront | 50m / 64Mi | 200m / 256Mi |
| Redis Insight | 50m / 64Mi | 200m / 256Mi |
Total Requests for all components: ~1.85 CPU / 3Gi Memory
Total Limits for all components: ~8.4 CPU / 11.5Gi Memory
Resource Priorityâ
User-specified in TFRTenant spec > Operator defaults
Implemented via EnsureResources() (resources.go:289-294): uses user config when non-nil, otherwise falls back to defaults.
User Configuration Exampleâ
apiVersion: infra.tfrobot.io/v1
kind: TFRTenant
spec:
postgresql:
resources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "2000m"
memory: "2Gi"
redis:
resources:
requests:
cpu: "200m"
memory: "256Mi"
See component Options definitions for supported resource fields: internal/controller/infra/tenant/options.go:131-207
TFRServer Container Resourcesâ
Default Valuesâ
Defined in internal/controller/tfrobot/deployables/resources.go:22-46:
| Container | Requests (CPU/Mem) | Limits (CPU/Mem) |
|---|---|---|
| API | 250m / 256Mi | 1000m / 1Gi |
| Worker (memory-worker) | 500m / 512Mi | 2000m / 2Gi |
| RobotWorker | 500m / 512Mi | 2000m / 2Gi |
Total Requests per TFRServer: 1.25 CPU / 1.25Gi Memory
Total Limits per TFRServer: 5 CPU / 5Gi Memory
Auto-Fill Trigger Conditionsâ
Triggered when both conditions are met (deployables/resources.go:48-60):
- At least one container has nil resources
- The namespace has a ResourceQuota with CPU/Memory constraints
Entry point: tfrserver_controller.go:286-295
User Configuration Exampleâ
apiVersion: tfrobot.tfrobot.io/v1
kind: TFRServer
spec:
apiResources:
requests:
cpu: "500m"
memory: "512Mi"
limits:
cpu: "2000m"
memory: "2Gi"
workerResources:
requests:
cpu: "1000m"
memory: "1Gi"
CRD field definitions: api/tfrobot/v1/tfrserver_types.go:401-418
Quota Capacity Planningâ
Minimum quota for a single tenant (1 TFRTenant + 1 TFRServer) using default values:
| Resource Type | Requests | Limits |
|---|---|---|
| CPU | 3.1 (1.85 + 1.25) | 13.4 (8.4 + 5) |
| Memory | 4.3Gi (3 + 1.25) | 16.5Gi (11.5 + 5) |
- The above covers only Operator-managed Pods, excluding Kubernetes system components and third-party Operator Pods
- For multiple TFRServers, scale proportionally: each additional TFRServer adds 1.25 CPU / 1.25Gi to Requests
- Recommend reserving 20-30% headroom for rolling updates and temporary Pods
Code Reference Indexâ
| Module | Path |
|---|---|
| TFRTenant component defaults | internal/controller/infra/tenant/resources.go |
| ResourceQuota Deployable | internal/controller/infra/tenant/resource_quota.go |
| TFRTenant auto-fill logic | internal/controller/infra/tfrtenant_controller.go:255-295 |
| TFRServer container defaults | internal/controller/tfrobot/deployables/resources.go |
| TFRServer auto-fill logic | internal/controller/tfrobot/tfrserver_controller.go:286-295 |
| ResourceQuota CRD types | api/infra/v1/tfrtenant_types.go:316-329 |
| Container resource CRD types | api/tfrobot/v1/tfrserver_types.go:401-418 |
| Options definitions | internal/controller/infra/tenant/options.go |