Skip to main content
Version: Next 🚧

Storage Architecture

This document describes the data storage solutions managed by TFRS Operator, including middleware deployment patterns, storage configuration priority, and isolation models.

Storage Configuration Priority​

TFRS Operator uses a three-level priority chain to resolve storage configuration:

Component-level config > Tenant-level config > System default
PrioritySourceExample
1 - Componentspec.postgresql.storage, spec.redis.storage, etc.Specify 100Gi with cbs-ssd StorageClass for PostgreSQL only
2 - Tenantspec.storageTenant-wide default StorageClass and size
3 - System DefaultHardcoded10Gi, cluster default StorageClass

Configuration example in TFRTenant:

apiVersion: infra.tfrobot.io/v1
kind: TFRTenant
spec:
# Tenant-level default (priority 2)
storage:
storageClass: "cbs-ssd"
size: "50Gi"
# Component-level override (priority 1)
postgresql:
storage:
storageClass: "cbs-ssd-enhanced"
size: "200Gi"
redis:
storage:
size: "20Gi" # Uses tenant-level storageClass: cbs-ssd

PostgreSQL​

Deployment Method​

Managed through CloudNativePG (CNPG). TFRTenant creates an independent CNPG Cluster for each tenant:

ConfigurationValue
Cluster Name{namespace}-pg
Imageghcr.io/cloudnative-pg/postgresql:16-minimal-bookworm
Credentials Secret{namespace}-pg-credentials
Default Storage10Gi (overridable via priority chain)

Credential Management​

  • username: User-specified (cannot be postgres, reserved by CNPG)
  • password: User-specified or auto-generated by the Operator
PostgreSQL Isolation Level Warning

TFRS Operator only provides database-level isolation, not schema-level isolation.

Each TFRTenant gets an independent CNPG Cluster (separate Pod and PVC), achieving database instance-level isolation. However, when multiple TFRServers share the same database, schema isolation must be managed at the application layer.

ResponsibilityOwnerAutomation Level
Database creationOperator (automatic)Fully automated
Schema creationPython application (db-init script)Semi-automated (triggered by TFRServer Job)
Schema naming & isolationOperations team (via TFS_ROBOT__DB_SCHEMA config)Manual configuration
Schema conflict detectionNoneNo validation mechanism

Risk: If two TFRServers are configured with the same TFS_ROBOT__DB_SCHEMA, they will share the same schema, potentially causing data conflicts. Operations personnel must ensure schema name uniqueness manually.

Redis​

Deployment Method​

Deployed as a Kubernetes Deployment + PVC, not managed by an Operator:

ConfigurationValue
Imageredis/redis-stack-server:7.2.0-v17
PVC Nameredis-data
Port6379
UIRedisInsight (redislabs/redisinsight:latest, port 5540)
Default Storage10Gi (overridable via priority chain)

Redis uses a single-instance deployment model with one Deployment per tenant. Redis Sentinel or Cluster mode is not used.

RabbitMQ​

Deployment Method​

Managed through RabbitMQ Cluster Operator and Messaging Topology Operator:

Operators installed by TFRCluster:

  • rabbitmq-cluster-operator: Manages RabbitMQ cluster lifecycle
  • rabbitmq-messaging-topology-operator: Manages Vhost, User, Permission and other topology resources

Instances created by TFRTenant:

Resource TypeDescription
RabbitmqClusterTenant-level RabbitMQ instance
VhostVirtual host isolation
UserApplication access credentials
PermissionVhost-level access permissions

Each tenant owns an independent RabbitMQ cluster instance, with Vhost providing an additional logical isolation layer.

MinIO​

Deployment Method​

Managed through MinIO Operator. TFRTenant creates a MinIO Tenant CR for each tenant:

ConfigurationValue
Imageminio/minio:RELEASE.2025-07-23T15-54-02Z
Default Credentialsminioadmin / minioadmin
TLSDisabled by default (relies on Istio mTLS for inter-service encryption)
ReplicasConfigurable (default: 1)
Port9000 (API)
Default Storage10Gi (overridable via priority chain)

Per-Robot Credentials​

TFRServer creates independent Buckets and access credentials for each robot instance through the MinIO Init Job, achieving logical isolation of object storage.

Shared Cache (SharedCache)​

Used to share image extraction cache between multiple TFRServer instances and TFRSUtils.

Configuration​

Enable in TFRTenant:

spec:
sharedCache:
enabled: true
pvcName: "image-extracted-dir" # Default value
storageClass: "cfs" # Must support ReadWriteMany
size: "100Gi"
cacheDir: "~/.tfrobot/documents/extracted" # Default value

Requirements​

RequirementDescription
AccessModeReadWriteMany (RWX)
StorageClassMust support RWX (e.g., NFS, CephFS, Tencent Cloud CFS)
Mount PathConfigured via cacheDir

Automatic Environment Variable Injection​

When SharedCache is enabled, the Operator automatically injects the following environment variables into TFRServer Pods:

VariableValue SourceDescription
TFC_IMAGE__SHARED_CACHEsharedCache.cacheDirShared cache root directory
TFS_ROBOT__DOC_EXTRACTED_IMAGES_DIRVolumeMount.MountPathImage extraction directory (highest priority, overrides ConfigMap)

Other Storage Components​

ComponentDeployment MethodStorage TypeDescription
TimescaleDBCNPG + ExtensionPVCTime-series data, independent from primary PostgreSQL
JaegerHelm ChartPVCDistributed tracing data
GrafanaHelm ChartPVCDashboard configuration and data

TimescaleDB uses an independent CNPG Cluster with credentials separate from the primary PostgreSQL. The username similarly cannot be postgres.

Isolation Model Summary​

ComponentIsolation LevelIsolation MethodManaged By
PostgreSQLInstance-levelIndependent CNPG Cluster per tenant (Pod + PVC)Operator
PostgreSQL SchemaApplication-levelTFS_ROBOT__DB_SCHEMA environment variableOperations (manual)
RedisInstance-levelIndependent Deployment + PVC per tenantOperator
RabbitMQInstance + LogicalIndependent Cluster + Vhost isolationOperator
MinIOInstance + LogicalIndependent Tenant + per-robot Bucket/credentialsOperator
SharedCacheTenant-levelRWX PVC within tenant namespaceOperator
NetworkNamespace-levelmTLS + AuthorizationPolicyOperator

Storage Architecture Overview​

graph TB
subgraph TFRTenant[Tenant Namespace]
subgraph databases[Database Layer]
PG[(PostgreSQL<br/>CNPG Cluster)]
TSDB[(TimescaleDB<br/>CNPG + Extension)]
RD[(Redis<br/>Deployment)]
end

subgraph messaging[Messaging Layer]
RQ[(RabbitMQ<br/>Cluster Operator)]
end

subgraph storage[Object Storage Layer]
MN[(MinIO<br/>MinIO Tenant)]
SC[(SharedCache<br/>RWX PVC)]
end

subgraph monitoring[Monitoring Layer]
JG[(Jaeger)]
GF[(Grafana)]
end

subgraph servers[TFRServer Instances]
S1[tf-robot-1]
S2[tf-robot-2]
end

S1 --> PG
S1 --> RD
S1 --> RQ
S1 --> MN
S1 --> SC
S2 --> PG
S2 --> RD
S2 --> RQ
S2 --> MN
S2 --> SC
end

subgraph resolution[Storage Config Priority]
C1[Component-level] -->|overrides| C2[Tenant-level]
C2 -->|overrides| C3[System Default 10Gi]
end