This guide is a technical manual for installing, configuring, and operating the RustFS Kubernetes Operator.
Chinese version: operator-user-guide.zh-CN.md
RustFS Operator manages RustFS object storage clusters on Kubernetes. Users describe the desired storage cluster with a namespaced Tenant custom resource, and the operator reconciles Kubernetes resources needed to run RustFS.
The operator provides:
TenantCRD (rustfs.com/v1alpha1) for declaring RustFS pools, persistence, scheduling, credentials, TLS, logging, encryption, and bootstrap provisioning.- Controller reconciliation for Tenant-owned RBAC, Services, StatefulSets, PVC templates, status conditions, and Kubernetes Events.
- Helm chart under
deploy/rustfs-operator/for production-style installation. - Operator Console API and UI for management workflows.
- Optional operator STS endpoint for workload identity based temporary RustFS credentials.
- Optional tenant provisioning for canned policies, regular users, and buckets.
- Metrics, health probes, and optional Prometheus Operator resources.
Important service separation:
| Component | Purpose | Default port |
|---|---|---|
| RustFS S3 API inside a Tenant | S3-compatible object storage access | 9000 |
| RustFS Tenant Console | Web console for one RustFS Tenant | 9001 |
| Operator Console API/UI | Operator management API and UI | 9090 |
| Operator STS | Temporary credentials endpoint | 4223 |
| Operator observability endpoint | /metrics, /healthz, /readyz |
8080 |
A Tenant is one RustFS cluster. A Tenant can contain one or more pools, but all pools in the same Tenant form one unified RustFS cluster. Do not use pools as hot/warm/cold storage tiers. If you need separate performance, isolation, lifecycle, or administrative boundaries, create separate Tenants.
When a Tenant is applied, the operator creates and owns:
- one ServiceAccount, Role, and RoleBinding when Tenant RBAC is enabled;
- one headless Service named
{tenant}-hlfor StatefulSet peer DNS; - one S3 Service named
{tenant}-ioon port9000; - one Tenant Console Service named
{tenant}-consoleon port9001; - one StatefulSet per pool;
- PVC templates named
vol-0,vol-1, and so on; - generated RustFS environment variables such as
RUSTFS_VOLUMES,RUSTFS_ADDRESS,RUSTFS_CONSOLE_ADDRESS, andRUSTFS_CONSOLE_ENABLE.
- Kubernetes v1.30 or newer.
- Helm 3.0 or newer for chart installation.
- A StorageClass that can satisfy the Tenant PVCs.
kubectlconfigured for the target cluster.- Access to the configured operator and RustFS images.
- Optional: Prometheus Operator when enabling
ServiceMonitororPrometheusRule. - Optional: cert-manager when using cert-manager managed Tenant TLS.
Install with the included Helm chart:
helm install rustfs-operator deploy/rustfs-operator/ \
--namespace rustfs-system \
--create-namespaceVerify the operator and Console pods:
kubectl get pods -n rustfs-system
kubectl logs -n rustfs-system \
-l app.kubernetes.io/name=rustfs-operator,app.kubernetes.io/component=operator \
-fUpgrade an existing installation:
helm upgrade rustfs-operator deploy/rustfs-operator/ \
--namespace rustfs-systemUninstall:
helm uninstall rustfs-operator --namespace rustfs-systemUse a values file for repeatable installation:
helm upgrade --install rustfs-operator deploy/rustfs-operator/ \
--namespace rustfs-system \
--create-namespace \
-f values.yamlCommon chart sections:
| Section | Purpose |
|---|---|
operator |
Operator Deployment replicas, image, resources, probes, metrics, scheduling, leader election, and tenant monitoring. |
sts |
Operator STS endpoint, service port, TokenReview audience, and TLS handling. |
serviceAccount / rbac |
Operator ServiceAccount and RBAC creation. |
console |
Operator Console backend/UI Deployment, service, session cookie secret, ingress, resources, and optional split frontend. |
namespace |
Namespace override for chart resources; defaults to the Helm release namespace. |
commonLabels / commonAnnotations |
Labels and annotations added to chart-managed resources. |
Example production-oriented values:
operator:
replicas: 2
image:
repository: registry.example.com/rustfs/operator
tag: v0.1.0
resources:
requests:
cpu: 200m
memory: 256Mi
limits:
cpu: 1000m
memory: 1Gi
tenantMonitor:
enabled: true
intervalSeconds: 300
serviceMonitor:
enabled: true
console:
enabled: true
replicas: 2
jwtSecret: "<stable-base64-or-random-secret>"
ingress:
enabled: true
className: nginx
hosts:
- host: console.example.com
sts:
enabled: true
audience: sts.rustfs.com
tls:
enabled: true
auto: trueNotes:
operator.leaderElectcan be unset. The chart enables leader election automatically whenoperator.replicas > 1.- Keep
console.jwtSecretstable when running multiple Console replicas. If unset, the chart generates or reuses a Secret. - Keep
CONSOLE_COOKIE_SECUREenabled for production HTTPS. Only disable it for local HTTP testing. sts.tls.auto=truelets the operator create thests-tlsSecret when missing.
A minimal development Tenant:
apiVersion: rustfs.com/v1alpha1
kind: Tenant
metadata:
name: dev-minimal
namespace: default
spec:
image: rustfs/rustfs:latest
pools:
- name: dev-pool
servers: 1
persistence:
volumesPerServer: 1Apply and verify:
kubectl apply -f tenant.yaml
kubectl get tenant dev-minimal
kubectl get pods,pvc,svc -l rustfs.tenant=dev-minimalWait for pods:
kubectl wait --for=condition=ready pod \
-l rustfs.tenant=dev-minimal \
--timeout=300sAccess the Tenant S3 API:
kubectl port-forward svc/dev-minimal-io 9000:9000Access the Tenant Console:
kubectl port-forward svc/dev-minimal-console 9001:9001Use examples in examples/ as starting points:
| Example | Use case |
|---|---|
examples/minimal-dev-tenant.yaml |
Smallest valid development Tenant. |
examples/secret-credentials-tenant.yaml |
Secret-based admin credentials. |
examples/provisioning-tenant.yaml |
Bootstrap policies, users, and buckets. |
examples/production-ha-tenant.yaml |
High-availability production-style layout. |
examples/multi-pool-tenant.yaml |
Multiple pools in one unified Tenant cluster. |
examples/custom-rbac-tenant.yaml |
Custom ServiceAccount and RBAC patterns. |
Tenant names must be DNS-1035 compatible and no longer than 55 characters because the operator derives Service names such as {tenant}-console.
Use lowercase names that start with a letter and contain only lowercase letters, digits, and -.
spec.pools is required. Each pool creates one StatefulSet.
Key fields:
| Field | Purpose |
|---|---|
name |
Pool name used in labels, StatefulSet names, and peer DNS. Must be unique in the Tenant. |
servers |
Number of RustFS pods in the pool. Must be greater than 0. Immutable after creation. |
persistence.volumesPerServer |
Number of PVCs mounted into each server. Must be greater than 0. Immutable after creation. |
persistence.volumeClaimTemplate |
PVC spec used for each generated volume. Set storage size, access modes, and StorageClass here. |
persistence.path |
Base mount path. Defaults to /data; mounted paths become {path}/rustfs0, {path}/rustfs1, and so on. |
nodeSelector, affinity, tolerations, topologySpreadConstraints |
Pool-level scheduling controls. |
resources |
Container resource requests and limits for the pool. |
priorityClassName |
Pool-level priority class override. |
Operator admission checks:
serversandpersistence.volumesPerServermust be greater than0.- Pool names must be unique.
- Pool peer DNS labels must fit Kubernetes DNS label limits.
- Existing pool
serversandvolumesPerServercannot be changed in place.
The operator does not validate whether a RustFS storage layout, erasure set size, or storage class parity is supported. RustFS performs those checks when the Tenant workload starts.
Example:
spec:
pools:
- name: pool-0
servers: 4
persistence:
volumesPerServer: 4
volumeClaimTemplate:
accessModes: ["ReadWriteOnce"]
resources:
requests:
storage: 100Gi
storageClassName: fast-ssd
resources:
requests:
cpu: "2"
memory: 8Gi
limits:
cpu: "4"
memory: 16GiFor production, use spec.credsSecret. The Secret must be in the same namespace as the Tenant and contain UTF-8 accesskey and secretkey keys. Both values must be at least 8 characters.
apiVersion: v1
kind: Secret
metadata:
name: rustfs-admin-creds
namespace: storage
type: Opaque
stringData:
accesskey: "replace-with-access-key"
secretkey: "replace-with-secret-key"
---
apiVersion: rustfs.com/v1alpha1
kind: Tenant
metadata:
name: rustfs-a
namespace: storage
spec:
credsSecret:
name: rustfs-admin-creds
pools:
- name: pool-0
servers: 2
persistence:
volumesPerServer: 2Credential priority:
spec.credsSecret.- Explicit
RUSTFS_ACCESS_KEYandRUSTFS_SECRET_KEYinspec.env. - RustFS built-in defaults. Use defaults only for development.
Useful Tenant-level fields:
| Field | Purpose |
|---|---|
image |
RustFS server image. Defaults to the operator's configured fallback. |
imagePullSecret |
Image pull Secret reference. |
imagePullPolicy |
RustFS image pull policy. |
scheduler |
Custom scheduler name. |
env |
Additional RustFS container environment variables. Do not override operator-managed variables. |
serviceAccountName |
Custom ServiceAccount for RustFS pods. |
createServiceAccountRbac |
Whether the operator should create Role/RoleBinding for the Tenant ServiceAccount. |
priorityClassName |
Tenant-level priority class. |
lifecycle |
Kubernetes container lifecycle hooks. |
podManagementPolicy |
StatefulSet pod management policy. |
podDeletionPolicyWhenNodeIsDown |
Node-down pod deletion behavior. |
securityContext |
Pod SecurityContext override for RustFS pods. |
The operator reserves these environment variables and manages them automatically:
RUSTFS_VOLUMESRUSTFS_ADDRESSRUSTFS_CONSOLE_ADDRESSRUSTFS_CONSOLE_ENABLERUSTFS_KMS_*variables; usespec.encryptioninstead.- TLS-related RustFS variables when Tenant TLS is enabled.
For a single-pool single-node single-disk Tenant, RUSTFS_VOLUMES is rendered as the local data path, for example /data/rustfs0. Multi-pool tenants and other layouts render peer DNS URLs through the Tenant headless Service and are validated by RustFS at runtime.
podDeletionPolicyWhenNodeIsDown accepts:
DoNothing: do not delete pods automatically.Delete: request a best-effort normal pod delete; this does not force-release a StatefulSet identity when the kubelet is unreachable.ForceDelete: force delete the pod withgracePeriodSeconds=0.DeleteStatefulSetPod: Longhorn-compatible force delete for StatefulSet pods stuck on down nodes.DeleteDeploymentPod: Longhorn-compatible force delete for Deployment pods stuck on down nodes.DeleteBothStatefulSetAndDeploymentPod: Longhorn-compatible force delete for both StatefulSet and Deployment pods.
Force deletion can have data consistency implications. Use it only when the storage backend and operational procedure are designed for that failure mode. Force deletion requires the Node object to be deleted or marked with an effective node.kubernetes.io/out-of-service taint that the target Pod does not tolerate, so volume detach fencing is explicit. Before using force policies, confirm the node is powered off or otherwise isolated; deleting the Node object is treated as that operational assertion.
Tenant TLS is configured under spec.tls.
Important fields:
| Field | Purpose |
|---|---|
mode |
disabled or certManager for current usable configurations. external is reserved and currently blocks reconciliation. |
mountPath |
TLS mount path. Defaults to /var/run/rustfs/tls. |
rotationStrategy |
Rollout is supported. HotReload is accepted by the CRD but currently blocks reconciliation. |
enableInternodeHttps |
Use HTTPS for RustFS peer communication. |
requireSanMatch |
Require generated DNS names to match certificate SANs. Defaults to true. |
certManager |
Backward-compatible single certificate settings. secretName is required for mode: certManager when certificates is empty. |
certificates |
Multiple server certificate entries rendered into the RustFS TLS directory for SNI. Exactly one entry must set default: true; non-default entries must set hosts. |
caTrust |
Process-wide RustFS trust settings. This controls ca.crt, client_ca.crt, RUSTFS_TRUST_SYSTEM_CA, and server mTLS; it is not selected per SNI host. |
For cert-manager managed certificates:
spec:
tls:
mode: certManager
rotationStrategy: Rollout
enableInternodeHttps: true
certManager:
manageCertificate: true
secretName: rustfs-a-server-tls
issuerRef:
group: cert-manager.io
kind: Issuer
name: rustfs-issuer
includeGeneratedDnsNames: trueWhen manageCertificate: true, issuerRef is also required. The operator creates or reconciles the cert-manager Certificate, waits for the referenced Secret, validates tls.crt and tls.key, and uses ca.crt unless another CA trust source is configured.
For the backward-compatible single-certificate form, omitted includeGeneratedDnsNames behaves as true.
For separate public and internal certificates:
spec:
tls:
mode: certManager
rotationStrategy: Rollout
enableInternodeHttps: true
caTrust:
source: CertificateSecretCa
certificates:
- name: internal
default: true
hosts:
- rustfs.internal.example.local
certManager:
manageCertificate: true
secretName: rustfs-internal-tls
issuerRef:
group: cert-manager.io
kind: Issuer
name: private-ca
includeGeneratedDnsNames: true
- name: public
hosts:
- s3.example.com
certManager:
manageCertificate: true
secretName: rustfs-public-tls
issuerRef:
group: cert-manager.io
kind: ClusterIssuer
name: letsencrypt-prod
includeGeneratedDnsNames: falseThe default certificate is projected to rustfs_cert.pem and rustfs_key.pem at mountPath, so RustFS can use it as the fallback certificate and for internode HTTPS. Each hosts value is projected as a RustFS SNI directory, for example s3.example.com/rustfs_cert.pem and s3.example.com/rustfs_key.pem.
When certificates is set, omitted includeGeneratedDnsNames is treated as true only on the default: true certificate. Non-default entries include only hosts and certManager.dnsNames unless they explicitly set includeGeneratedDnsNames: true.
When enableInternodeHttps: true, the default managed certificate must cover the generated RustFS peer DNS names. Keep includeGeneratedDnsNames enabled, or list the generated peer names explicitly in hosts or certManager.dnsNames.
When certificates is set, configure process-wide trust with top-level caTrust or the caTrust on the default: true certificate. The legacy certManager.caTrust field is only used by the single-certificate form, and certManager.caTrust on non-default entries is rejected.
Tenant logging is configured under spec.logging.
Modes:
| Mode | Purpose |
|---|---|
stdout |
Default and recommended. Kubernetes collects logs from stdout/stderr. |
emptyDir |
Temporary local log storage for debugging. Logs are lost on pod restart. |
persistent |
PVC-backed logs. Use only with external storage independent of RustFS. |
Do not store RustFS startup logs in RustFS itself. That creates a circular dependency because the storage service is not available during startup.
Example:
spec:
logging:
mode: stdoutTenant encryption is configured under spec.encryption.
Supported backends:
| Backend | Purpose |
|---|---|
local |
File-based local KMS key directory and local master key. The directory must be absolute, must be in a subdirectory under a RustFS data PVC mount, and the Tenant must have exactly one RustFS server replica across all pools. |
vault |
HashiCorp Vault endpoint. Requires a Secret containing vault-token. |
Local KMS does not use kmsSecret; if you set one, it is ignored. Configure the local master key with spec.encryption.local.masterKeySecretRef, which maps to RustFS RUSTFS_KMS_LOCAL_MASTER_KEY. By default, Local KMS stores key files under the first data PVC mount, for example /data/rustfs0/.kms-keys when persistence.path is /data. Use Vault KMS for multi-server Tenants. allowInsecureDevDefaults: true maps to RUSTFS_KMS_ALLOW_INSECURE_DEV_DEFAULTS=true and should only be used for development because RustFS may store Local KMS key material as plaintext-dev-only.
Upgrade note: older operator versions defaulted Local KMS to /data/kms-keys, which was not on a data PVC. The operator does not migrate key files automatically. For an existing Local KMS Tenant that still uses the old implicit default, or that explicitly set the legacy path, the operator blocks reconciliation or StatefulSet rollout until you copy any existing key files and .master-key.salt into the new PVC-backed directory, keep using the same local master key Secret, then set spec.encryption.local.keyDirectory explicitly to that subdirectory.
Local example:
apiVersion: v1
kind: Secret
metadata:
name: rustfs-local-kms
namespace: storage
type: Opaque
stringData:
local-master-key: "replace-with-a-strong-local-kms-master-key"
---
apiVersion: rustfs.com/v1alpha1
kind: Tenant
metadata:
name: rustfs-local
namespace: storage
spec:
pools:
- name: pool-0
servers: 1
persistence:
volumesPerServer: 1
encryption:
enabled: true
backend: local
local:
keyDirectory: /data/rustfs0/.kms-keys
masterKeySecretRef:
name: rustfs-local-kms
key: local-master-key
defaultKeyId: tenant-defaultVault example:
apiVersion: v1
kind: Secret
metadata:
name: rustfs-kms
namespace: storage
type: Opaque
stringData:
vault-token: "replace-with-vault-token"
---
apiVersion: rustfs.com/v1alpha1
kind: Tenant
metadata:
name: rustfs-a
namespace: storage
spec:
pools:
- name: pool-0
servers: 2
persistence:
volumesPerServer: 2
encryption:
enabled: true
backend: vault
vault:
endpoint: https://vault.example.com:8200
kmsSecret:
name: rustfs-kms
defaultKeyId: tenant-defaultThe operator can create RustFS policies, users, and buckets after the Tenant workload is ready. Configure:
spec.credsSecretfor RustFS admin credentials.spec.policiesfor canned policies sourced from ConfigMaps.spec.usersfor regular users. Each user must have at least one direct policy mapping.spec.bucketsfor buckets and optional object lock.
ConfigMaps and user Secrets must live in the Tenant namespace. If managed outside the Operator Console, label them with rustfs.tenant=<tenant-name> so updates enqueue the owning Tenant.
Policy documents are parsed by RustFS. Use S3 ARN resource patterns such as arn:aws:s3:::bucket and arn:aws:s3:::bucket/*; for all buckets, use arn:aws:s3:::*. A bare Resource: "*" is not accepted by RustFS policy parsing.
For each spec.users[] entry, the operator reads a Secret with the same name as the user. The Secret must contain accesskey and secretkey, or the MinIO-compatible keys CONSOLE_ACCESS_KEY and CONSOLE_SECRET_KEY. If both key formats are present, their values must match. User access keys must be at least 8 characters and must not contain whitespace, =, or ,; user secret keys must be at least 8 characters.
Updating a user Secret's secretkey rotates that RustFS user's credential. The accesskey is immutable after the first successful reconciliation; use a new user entry and Secret when it must change, then migrate clients before removing the old entry.
apiVersion: v1
kind: ConfigMap
metadata:
name: app-policy
namespace: storage
labels:
rustfs.tenant: rustfs-a
data:
policy.json: |
{
"Version": "2012-10-17",
"Statement": [
{
"Effect": "Allow",
"Action": ["s3:ListBucket", "s3:GetObject", "s3:PutObject", "s3:DeleteObject"],
"Resource": ["arn:aws:s3:::app-data", "arn:aws:s3:::app-data/*"]
}
]
}
---
apiVersion: v1
kind: Secret
metadata:
name: app-user
namespace: storage
labels:
rustfs.tenant: rustfs-a
type: Opaque
stringData:
accesskey: appuser01
secretkey: appuser01secret
---
apiVersion: rustfs.com/v1alpha1
kind: Tenant
metadata:
name: rustfs-a
namespace: storage
spec:
credsSecret:
name: rustfs-admin-creds
pools:
- name: pool-0
servers: 1
persistence:
volumesPerServer: 4
policies:
- name: app-readwrite
document:
configMapKeyRef:
name: app-policy
key: policy.json
users:
- name: app-user
policies:
- app-readwrite
buckets:
- name: app-data
objectLock: trueDeletion behavior is conservative: provisioned resources are retained when removed from the Tenant spec.
spec.poolLifecycle controls explicit pool lifecycle requests. The current PVC retention policy is Retain.
Example decommission request:
spec:
poolLifecycle:
pvcRetentionPolicy: Retain
decommissionRequests:
- poolName: pool-old
requestId: decommission-pool-old-20250623
action: Start
reason: "capacity migrated to pool-new"Use pool lifecycle operations carefully. Keep a backup and verify RustFS-level decommission behavior before removing capacity.
The Helm chart enables the Operator Console by default with console.enabled=true.
Recommended same-origin deployment:
console:
enabled: true
ingress:
enabled: true
className: nginx
hosts:
- host: console.example.comThe unified operator image serves both / and /api/v1 from the Console service. No backend CORS configuration is needed for this mode.
Console login uses a Kubernetes ServiceAccount bearer token. For the chart-managed Console ServiceAccount:
kubectl -n rustfs-system create token rustfs-operator-console --duration=24hPaste the token into the login form. The Console stores the validated token in an encrypted session cookie.
If your Helm release uses a custom namespace or console.serviceAccount.name,
use the command printed in the Helm install notes.
For local port-forward testing:
kubectl -n rustfs-system port-forward svc/rustfs-operator-console 19090:9090Open http://127.0.0.1:19090.
The operator STS endpoint lets a Kubernetes workload exchange a projected ServiceAccount token for temporary RustFS credentials, authorized by a PolicyBinding.
STS route:
POST /sts/{tenantNamespace}/{tenantName}
Create a PolicyBinding in the target Tenant namespace:
apiVersion: sts.rustfs.com/v1alpha1
kind: PolicyBinding
metadata:
name: reports-readonly
namespace: storage
spec:
application:
namespace: reports
serviceaccount: reports-api
policies:
- readonlyThe workload ServiceAccount token audience must match sts.audience, which defaults to sts.rustfs.com.
volumes:
- name: rustfs-sts-token
projected:
sources:
- serviceAccountToken:
path: token
audience: sts.rustfs.com
expirationSeconds: 3600Call STS from the workload:
TOKEN="$(cat /var/run/secrets/rustfs-sts/token)"
curl -sS -X POST \
--cacert /var/run/secrets/rustfs-sts-ca/ca.crt \
"https://rustfs-operator-sts.rustfs-system.svc:4223/sts/storage/rustfs-a" \
-H "Content-Type: application/x-www-form-urlencoded" \
--data-urlencode "Version=2011-06-15" \
--data-urlencode "Action=AssumeRoleWithWebIdentity" \
--data-urlencode "WebIdentityToken=${TOKEN}" \
--data-urlencode "DurationSeconds=3600"Current STS constraints:
- STS only issues credentials for TLS-enabled Tenants.
- Operator STS uses the explicit Tenant route with both namespace and name.
- The
PolicyBindingmust reference at least one policy. - Every policy referenced by the matched
PolicyBindingmust resolve to a valid RustFS policy document. - Caller-supplied
Policyrequest parameters are rejected; issued credentials use the matchedPolicyBindingpolicies. - Tenants requiring client certificates for upstream Tenant calls are rejected by Operator STS.
Check Tenant status:
kubectl get tenant -A
kubectl describe tenant -n <namespace> <tenant>The operator reports status.currentState values such as:
ReadyReconcilingBlockedDegradedNotReadyUnknown
Important conditions include:
ReadyReconcilingDegradedSpecValidCredentialsReadyKmsReadyTlsReadyPoolsReadyWorkloadsReadyProvisioningReady
Check chart-managed observability:
kubectl -n rustfs-system port-forward svc/rustfs-operator-metrics 18080:8080
curl http://127.0.0.1:18080/healthz
curl http://127.0.0.1:18080/readyz
curl http://127.0.0.1:18080/metricsEnable Prometheus Operator integration:
operator:
serviceMonitor:
enabled: true
prometheusRule:
enabled: truespec:
image: rustfs/rustfs:v1.0.0The operator reconciles StatefulSets and reports rollout status in Tenant conditions and pool status.
PVC expansion depends on the StorageClass and Kubernetes environment. Do not change immutable pool shape fields (servers and volumesPerServer) in place. To add capacity, add a new pool when appropriate and follow RustFS decommission and migration procedures.
Use Kubernetes primitives:
kubectl rollout restart statefulset -n <namespace> -l rustfs.tenant=<tenant>
kubectl rollout status statefulset -n <namespace> -l rustfs.tenant=<tenant>Update the referenced Secret and restart Tenant StatefulSets so pods consume the new Secret values:
kubectl create secret generic rustfs-admin-creds \
-n <namespace> \
--from-literal=accesskey=<new-access-key> \
--from-literal=secretkey=<new-secret-key> \
--dry-run=client -o yaml | kubectl apply -f -
kubectl rollout restart statefulset -n <namespace> -l rustfs.tenant=<tenant>kubectl describe tenant -n <namespace> <tenant>
kubectl get events -n <namespace> --sort-by=.lastTimestamp
kubectl logs -n rustfs-system \
-l app.kubernetes.io/name=rustfs-operator,app.kubernetes.io/component=operatorCommon blocked reasons:
| Reason | Check |
|---|---|
InvalidTenantName |
Tenant name length and DNS-1035 format. |
InvalidPoolSpec |
Pool count, total volume count, pool name, and immutable fields. |
CredentialSecretNotFound |
Secret exists in the Tenant namespace. |
CredentialSecretMissingKey |
Secret contains accesskey and secretkey. |
CredentialSecretTooShort |
Both credential values are at least 8 characters. |
KmsSecretNotFound / KmsSecretMissingKey |
KMS Secret exists and contains required keys, such as Vault vault-token or the Local KMS masterKeySecretRef.key. |
CertManagerCrdMissing / CertManagerIssuerNotFound |
cert-manager is installed and the issuer exists. |
StatefulSetUpdateValidationFailed |
An immutable StatefulSet or pool-shape field was changed. |
ProvisioningFailed |
Check status.provisioning, policy ConfigMaps, user Secrets, and RustFS admin credentials. |
kubectl get pods -n <namespace> -l rustfs.tenant=<tenant>
kubectl describe pod -n <namespace> -l rustfs.tenant=<tenant>
kubectl logs -n <namespace> -l rustfs.tenant=<tenant>Check PVC binding, StorageClass availability, image pull errors, node selectors, tolerations, and resource requests.
Verify the Tenant S3 service and endpoints:
kubectl get svc,endpoints -n <namespace> <tenant>-io
kubectl port-forward -n <namespace> svc/<tenant>-io 9000:9000For the Operator Console, verify the ServiceAccount token and Console logs:
kubectl -n rustfs-system create token rustfs-operator-console --duration=24h
kubectl logs -n rustfs-system \
-l app.kubernetes.io/name=rustfs-operator,app.kubernetes.io/component=consoleFor the RustFS Tenant Console, use the Tenant admin credentials from spec.credsSecret or configured RustFS environment variables.
- Use
spec.credsSecretor an external secret manager for production credentials. - Enable Kubernetes Secret encryption at rest.
- Use one StorageClass performance class within a Tenant unless you have a deliberate RustFS layout reason.
- Do not model hot/warm/cold tiers as pools inside one Tenant.
- Use separate Tenants for separate clusters, administrative boundaries, or performance isolation.
- Keep the Operator Console on HTTPS in production.
- Keep
console.jwtSecretstable for multi-replica Console deployments. - Use
ServiceMonitorandPrometheusRuleonly when Prometheus Operator is installed. - Keep Tenant examples under version control, but never commit raw Secret values.
- Check
status.conditionsbefore debugging lower-level StatefulSets.