Infrastructure Prerequisites
Plexicus runs on five infrastructure services — MongoDB, Redis, an S3-compatible object store, PostgreSQL and Temporal — plus a StorageClass and, usually, cert-manager. This page covers all of them: how to size the cluster, how to point Plexicus at services you already operate, and the exact commands to install them if you do not.
Step 6 of the Production Installation is where this page fits into the sequence. If you enable the bundled subcharts — the short path shown in that step — you can install Plexicus without reading further here. Come back when you want to run any of these services yourself, which is the usual choice for a production deployment.
Cluster sizing
Match your node sizing to the expected workload before installing:
| Profile | vCPU | RAM | Notes |
|---|---|---|---|
| Evaluation / light single-tenant | 4 | 8 GB | Minimum that fits the platform and all bundled infra subcharts |
| Small production baseline | 8 | 16 GB | Recommended starting point |
| High-throughput (many concurrent scans) | 16 | 32 GB+ | Scale further with scan concurrency |
The chart ships default resources.requests for the services that have them (fastapi, worker, plexalyzer-*). Apply a LimitRange or equivalent to your cluster so that pods without explicit requests receive non-zero QoS. Without request values set, the Kubernetes scheduler cannot make correct placement decisions — pods land in BestEffort QoS and are the first evicted under memory pressure. See global.limitRange in the values reference for the chart's built-in defaults.
Object storage — any S3-compatible service
Plexicus talks to object storage through a generic S3 client, so any S3-compatible endpoint is the recommended production choice — AWS S3, Cloudflare R2, Ceph RGW, or your cloud provider's hosted object storage. The bundled MinIO subchart exists only as a zero-dependency default for evaluation installs; it is not a production recommendation.
# In your values overlay:
minio:
enabled: false # disable the bundled subchart
global:
required:
minio:
service: "<your-s3-host>" # hostname ONLY — no https://, no trailing port
buckets: "<your-bucket-name>"
rootUser: "<access-key-id>" # S3 access key ID, supplied via existingSecret
rootPassword: "<secret-access-key>" # S3 secret access key, via existingSecret
global.required.minio.service expects the hostname (and optional :port) only — no https:// prefix, no trailing slash. Adding a scheme breaks S3 connectivity without an obvious error message. Correct: s3.us-east-1.amazonaws.com. Wrong: https://s3.us-east-1.amazonaws.com.
The rootUser and rootPassword values are read by the plexicus-fastapi and plexicus-worker Secrets, as OBJECT_STORAGE_ACCESS_KEY / OBJECT_STORAGE_SECRET_KEY (the minio.* naming predates generic S3 support and stayed to avoid a breaking rename — it works the same for any S3-compatible provider). If you use an existing secret rather than literal values, set fastapi.existingSecret and worker.existingSecret to a Secret that contains those keys.
When minio.enabled: false you can skip the MinIO Helm release in the steps below — install only MongoDB, Redis, PostgreSQL, and Temporal.
StorageClass for persistent data
Set global.storageClass in your values overlay to a StorageClass that has reclaimPolicy: Retain for your MongoDB, PostgreSQL, and MinIO PVCs. A Delete reclaim policy means the underlying storage volume is automatically removed when a PVC is deleted — a serious data-loss risk for production. Do not use node-local StorageClasses (such as local-path) for any stateful Plexicus component in production: the data lives on a single node and is irrecoverably lost if that node is replaced.
Check which StorageClasses are available in your cluster: kubectl get storageclass. Consult your cloud provider's documentation for the name of their Retain-policy block-storage class.
cert-manager ClusterIssuer
helm install cert-manager installs only the controller and CRDs — it does not create a ClusterIssuer. After cert-manager pods reach Running, create one before you run helm install plexicus (the chart references it on every TLS-enabled Ingress). Example for Let's Encrypt HTTP-01:
apiVersion: cert-manager.io/v1
kind: ClusterIssuer
metadata:
name: letsencrypt-prod
spec:
acme:
server: https://acme-v02.api.letsencrypt.org/directory
email: <your-email>
privateKeySecretRef:
name: letsencrypt-prod
solvers:
- http01:
ingress:
ingressClassName: nginx # adjust to match your ingress controller
Set global.certManager.clusterIssuer in your values overlay to match metadata.name above. For additional issuer examples see the examples/ directory inside the chart artifact (helm pull --untar).
Plexicus depends on five infrastructure services: MongoDB, Redis, MinIO, PostgreSQL, and Temporal. Since chart 1.2.6, all five ship as opt-in bundled subcharts (enabled: false by default). This page keeps separate Helm releases as the primary path — giving you independent version control, lifecycle management, and tuning per service. Customers who already operate any of these services can skip the corresponding install and point Plexicus at their existing endpoints via global.required.* and global.dependencies.* overrides.
Since chart 1.2.6, all five infra services can be enabled directly inside the umbrella chart. Add the following block to your values overlay instead of running separate Helm releases:
mongodb:
enabled: true
fullnameOverride: "mongodb"
auth:
rootPassword: "<same value as global.required.database.password>"
redis:
enabled: true
fullnameOverride: "redis"
auth:
password: "<same value as global.required.redis.password>"
minio:
enabled: true
fullnameOverride: "minio"
auth:
rootUser: minioadmin
rootPassword: "<same value as global.required.minio.rootPassword>"
temporal-postgresql:
enabled: true
fullnameOverride: "temporal-postgresql"
auth:
postgresPassword: "<same value as global.required.postgresql.password>"
temporal:
enabled: true
fullnameOverride: "temporal"
The fullnameOverride values produce the in-cluster Service names the chart expects (mongodb:27017, redis-master:6379, minio:9000, temporal-frontend:7233). The subchart auth passwords must equal the corresponding global.required.* values — mismatches cause runtime authentication failures that helm template does not detect.
For a complete single-command install using bundled infrastructure on k3s, see the Local Evaluation guide.
If you enable mongodb.architecture: replicaset for high-availability, do not set DATABASE_HOST=mongodb — that hostname resolves to the ClusterIP service, which is incompatible with the MongoDB replica-set protocol. Instead, use the full headless-service connection string that lists every replica member:
mongodb-0.mongodb-headless:27017,mongodb-1.mongodb-headless:27017,mongodb-2.mongodb-headless:27017/?replicaSet=rs0
In addition, create a mongodb-replica-set-key Kubernetes Secret containing a base64-encoded keyfile for intra-cluster replica-set authentication before the first MongoDB pod starts — the pod crashes on startup without it. Standalone architecture (mongodb.architecture: standalone) does not have these requirements and is simpler to operate for single-node deployments.
Bitnami moved its official chart images to a paid distribution in August 2025. The free images remain published under docker.io/bitnamilegacy/*, so the commands below override every image reference — main containers, init containers and sidecars — to point there.
global.security.allowInsecureImages=true is not a security downgrade. It is a Bitnami chart guard that refuses to run when the image repository is not the one the chart shipped with; the flag tells the chart you have deliberately changed the repository. It disables no verification, relaxes no TLS, and changes nothing about how images are pulled — the pull is still an authenticated HTTPS pull of the digest the tag resolves to.
For a production or certified deployment, mirror these images into a registry you control and pin them by digest, then point the image.repository overrides at your mirror instead of bitnamilegacy/. See Air-Gapped Installation.
helm repo add bitnami https://charts.bitnami.com/bitnami
helm repo add temporal https://go.temporal.io/helm-charts
helm repo add jetstack https://charts.jetstack.io
helm repo update
# 1. MongoDB
helm upgrade --install mongodb bitnami/mongodb --version 18.6.31 -n plexicus \
--set global.security.allowInsecureImages=true \
--set image.registry=docker.io \
--set image.repository=bitnamilegacy/mongodb \
--set volumePermissions.image.repository=bitnamilegacy/os-shell \
--set metrics.image.repository=bitnamilegacy/mongodb-exporter \
--set 'auth.rootPassword=<your-mongo-root-password>' \
--set 'auth.databases={plexicus}' \
--set 'auth.usernames={plexicus}' \
--set 'auth.passwords={<your-plexicus-db-password>}' \
--set persistence.size=10Gi --wait
# 2. Redis
helm upgrade --install redis bitnami/redis --version 25.5.1 -n plexicus \
--set global.security.allowInsecureImages=true \
--set image.registry=docker.io \
--set image.repository=bitnamilegacy/redis \
--set sentinel.image.repository=bitnamilegacy/redis-sentinel \
--set metrics.image.repository=bitnamilegacy/redis-exporter \
--set kubectl.image.repository=bitnamilegacy/kubectl \
--set volumePermissions.image.repository=bitnamilegacy/os-shell \
--set sysctl.image.repository=bitnamilegacy/os-shell \
--set auth.password=<your-redis-password> \
--set replica.replicaCount=0 \
--set master.persistence.size=4Gi --wait
# 3. MinIO
helm upgrade --install minio bitnami/minio --version 17.0.21 -n plexicus \
--set global.security.allowInsecureImages=true \
--set image.registry=docker.io \
--set image.repository=bitnamilegacy/minio \
--set defaultInitContainers.volumePermissions.image.repository=bitnamilegacy/os-shell \
--set console.image.repository=bitnamilegacy/minio-object-browser \
--set apiIngress.enabled=false --set ingress.enabled=false \
--set auth.rootUser=<your-minio-user> \
--set auth.rootPassword=<your-minio-password> \
--set defaultBuckets=platform \
--set persistence.size=10Gi --wait
# 4. PostgreSQL (for Temporal)
helm upgrade --install temporal-postgresql bitnami/postgresql --version 18.6.2 -n plexicus \
--set global.security.allowInsecureImages=true \
--set image.registry=docker.io \
--set image.repository=bitnamilegacy/postgresql \
--set metrics.image.repository=bitnamilegacy/postgres-exporter \
--set volumePermissions.image.repository=bitnamilegacy/os-shell \
--set auth.postgresPassword=<your-temporal-pg-password> \
--set primary.persistence.size=4Gi --wait
# 5. Temporal
# NOTE: --wait is intentionally omitted. Temporal pods crash-loop for ~2
# minutes while the schema-setup Job seeds the database — that is expected.
# Wait for the schema Job to complete (the section below polls the pods).
helm upgrade --install temporal temporal/temporal --version 0.73.2 -n plexicus \
--set image.registry=docker.io \
--set server.replicaCount=1 \
--set cassandra.enabled=false --set elasticsearch.enabled=false \
--set prometheus.enabled=false --set grafana.enabled=false \
--set server.config.persistence.default.driver=sql \
--set server.config.persistence.default.sql.driver=postgres12 \
--set server.config.persistence.default.sql.host=temporal-postgresql \
--set server.config.persistence.default.sql.port=5432 \
--set server.config.persistence.default.sql.database=temporal \
--set server.config.persistence.default.sql.user=postgres \
--set server.config.persistence.default.sql.password=<your-temporal-pg-password> \
--set server.config.persistence.visibility.driver=sql \
--set server.config.persistence.visibility.sql.driver=postgres12 \
--set server.config.persistence.visibility.sql.host=temporal-postgresql \
--set server.config.persistence.visibility.sql.port=5432 \
--set server.config.persistence.visibility.sql.database=temporal_visibility \
--set server.config.persistence.visibility.sql.user=postgres \
--set server.config.persistence.visibility.sql.password=<your-temporal-pg-password>
kubectl -n plexicus get pods # confirm all 5 prereqs are Running before continuing
The default in-cluster service names produced by these installs are mongodb, redis-master, minio, temporal-postgresql, and temporal-frontend. Chart 1.2.7+ defaults global.required.database.host, global.required.redis.host, global.required.minio.service, and the wait-loop endpoints to those names — so as long as you used the release names above, the customer overlay does not need to repeat them. Override only when connecting to externally-managed services or when ArgoCD prefixes the release names (see the ArgoCD Deployment).
Next steps
- Production Installation — continue at step 7, Prepare Your Values File
- Backup and Restore — protecting MongoDB, PostgreSQL and object storage
- Air-Gapped Installation — mirroring these images into your own registry