Title
Create new category
Edit page index title
Edit category
Edit link
Deploy Pulse databases with Helm
Use the helm-databases umbrella chart to deploy Pulse database dependencies on Kubernetes by using supported operators and charts.
Supported databases
| Database | Operator or chart | Version |
|---|---|---|
| MongoDB | MongoDB Controllers for Kubernetes (MCK) | 1.7.0 |
| PostgreSQL | CloudNativePG | 0.27.1 |
| Elasticsearch | ECK Operator | 3.3.0 |
| VictoriaMetrics | VictoriaMetrics Operator | 0.58.1 |
| Redis | OpsTree Redis Operator | 0.23.0 |
| NATS | NATS Helm Chart | 1.3.16 |
Before You Begin
Make sure you have:
- Kubernetes 1.21 or later
- Helm 3.x
kubectlconfigured for your cluster- Cluster admin permissions to install CRDs and ClusterRoles
Add Helm repositories
Before installing, you must register the Helm repositories that this chart references. Run all six commands, or only the ones for the databases you plan to install:
helm repo add mongodb https://mongodb.github.io/helm-chartshelm repo add cnpg https://cloudnative-pg.github.io/chartshelm repo add elastic https://helm.elastic.cohelm repo add victoriametrics https://victoriametrics.github.io/helm-charts/helm repo add ot-container-kit https://ot-container-kit.github.io/helm-chartshelm repo add nats https://nats-io.github.io/k8s/helm/charts/helm repo updateThen pull the dependency charts:
helm dependency update ./helm-databasesInstallation Modes
This chart supports two install modes using the same chart.
Fresh Install: Two-Step Process
On a fresh cluster where operator CRDs do not exist yet, Helm cannot create custom resources (database instances) in the same transaction that installs the CRDs. The chart handles this automatically.
Step 1 -- Install operators + CRDs (database instances are auto-deferred)
helm install pulse-db ./helm-databases \ --namespace pulse-databases \ --create-namespaceStep 2 -- Create database instances (CRDs now exist in the API)
helm upgrade pulse-db ./helm-databases \ --namespace pulse-databases \ --reuse-valuesThe post-install notes will tell you when step 2 is needed. On subsequent upgrades, everything works in a single command.
Mode 1: All databases in a single namespace
Deploy every enabled database into one shared namespace. Follow the two-step process above on a fresh cluster.
helm install pulse-db ./helm-databases \ --namespace pulse-databases \ --create-namespaceDisable specific databases at install time:
helm install pulse-db ./helm-databases \ --namespace pulse-databases \ --create-namespace \ --set nats.enabled=false \ --set victoriametrics.enabled=falseMode 2: Each database in its own namespace
Use the convenience value files in values/ to install one database per release. The same two-step process applies per release.
MongoDB
helm install pulse-mongo ./helm-databases \ -n pulse-mongo --create-namespace \ -f helm-databases/values/mongo-only.yamlPostgreSQL
helm install pulse-pg ./helm-databases \ -n pulse-postgres --create-namespace \ -f helm-databases/values/postgres-only.yamlElasticsearch
helm install pulse-es ./helm-databases \ -n pulse-elastic --create-namespace \ -f helm-databases/values/elastic-only.yamlVictoriaMetrics
helm install pulse-vm ./helm-databases \ -n pulse-victoriametrics --create-namespace \ -f helm-databases/values/victoriametrics-only.yamlRedis
helm install pulse-redis ./helm-databases \ -n pulse-redis --create-namespace \ -f helm-databases/values/redis-only.yamlNATS
helm install pulse-nats ./helm-databases \ -n pulse-nats --create-namespace \ -f helm-databases/values/nats-only.yamlMongoDB Sharded Cluster
The chart supports deploying a sharded MongoDB cluster by using the Community Operator. No Ops Manager is required. Set mongodb.cr.type=shardedCluster to enable it.
The MongoDBCommunity operator does not officially support sharding. It works by deploying separate MongoDBCommunity CRs for config servers, shard servers, and mongos routers, wired together through a shared keyfile and a mongos command override. Test thoroughly before production use.
What Gets Created
When type: shardedCluster is set, the chart creates:
| Resource | Name | Description |
|---|---|---|
| Secret | {name}-shared-keyfile | Master keyfile (auto-generated or user-provided) |
| Secret (×N) | {name}-configsvr-keyfile, {name}-shard-N-keyfile, {name}-mongos-keyfile | Per-component copies of the keyfile |
| Secret | admin password secret | Shared admin credentials |
| MongoDBCommunity | {name}-configsvr | Config server replica set (clusterRole: configsvr) |
| MongoDBCommunity (×shardCount) | {name}-shard-0, {name}-shard-1, ... | Shard replica sets (clusterRole: shardsvr) |
| MongoDBCommunity | {name}-mongos | mongos query routers (command override) |
| Job (Helm hook) | {name}-add-shards | Post-install job that runs sh.addShard() for each shard |
Deploy
Step 1 -- Install the operator (same two-step process as a fresh install)
helm install pulse-db ./helm-databases \ --namespace pulse-databases \ --create-namespace \ --set mongodb.cr.type=shardedClusterStep 2 -- Create the sharded cluster CRs
helm upgrade pulse-db ./helm-databases \ --namespace pulse-databases \ --reuse-valuesDeploy with Custom Settings
Override shard count, router count, or provide your own keyfile:
helm install pulse-db ./helm-databases \ --namespace pulse-databases \ --create-namespace \ --set mongodb.cr.type=shardedCluster \ --set mongodb.cr.shardedCluster.shardCount=3 \ --set mongodb.cr.shardedCluster.membersPerShard=3 \ --set mongodb.cr.shardedCluster.mongosCount=3 \ --set mongodb.cr.shardedCluster.configServerCount=3 \ --set mongodb.cr.auth.adminPassword=mySecurePasswordTo supply your own keyfile (must be at least 6 characters):
helm install pulse-db ./helm-databases \ --namespace pulse-databases \ --create-namespace \ --set mongodb.cr.type=shardedCluster \ --set mongodb.cr.shardedCluster.keyfile.value="$(openssl rand -base64 756)"If keyfile.value is left empty, which is the default, a random keyfile is auto-generated on first install and preserved across upgrades.
Verify the Cluster
After the install and upgrade cycle, check the status of all components:
kubectl get mongodbcommunity -n pulse-databaseskubectl get job pulse-mongodb-add-shards -n pulse-databaseskubectl logs job/pulse-mongodb-add-shards -n pulse-databaseskubectl exec -it pulse-mongodb-mongos-0 -n pulse-databases -- \ mongosh --eval "sh.status()"Architecture Overview
┌──────────────────────────────────────────────────────────┐│ Client Applications │└───────────────────────────┬──────────────────────────────┘ │ ┌─────────────▼─────────────┐ │ pulse-mongodb-mongos │ │ (mongos query routers) │ │ N = mongosCount │ └──┬──────────────────────┬──┘ │ │ ┌────────────▼──────────┐ ┌───────▼────────────────┐ │ pulse-mongodb-shard-0 │ │ pulse-mongodb-shard-N │ │ (shardsvr replset) │ │ (shardsvr replset) │ │ M = membersPerShard │ │ M = membersPerShard │ └───────────────────────┘ └─────────────────────────┘ │ │ ┌───────────────────────────────────┐ │ pulse-mongodb-configsvr │ │ (configsvr replica set) │ │ N = configServerCount │ └───────────────────────────────────┘All components share a common keyfile for internal authentication.
Using a Self-Hosted / Mirror Chart Repository
The Chart.yaml references repositories by using Helm aliases, such as @mongodb. To point at your own mirror, re-add the alias before running helm dependency update.
helm repo add mongodb https://my-internal-registry.example.com/mongodb-chartshelm repo add elastic https://my-internal-registry.example.com/elastic-chartshelm dependency update ./helm-databasesEach repository alias can be overridden independently, which gives you per-database control over the chart source.
Configuration
Global Values
| Parameter | Description | Default |
|---|---|---|
global.imagePullSecrets | Image pull secrets for operator pods | [] |
global.openshift | Enable OpenShift-compatible security contexts | false |
Per-Database Values
Each database section in values.yaml has the same structure:
<database>: enabled: true <operator-alias>: {} cr: create: true name: pulse-<database> ...MongoDB
| Parameter | Description | Default |
|---|---|---|
mongodb.enabled | Deploy MCK operator + instance | true |
mongodb.cr.create | Create MongoDB CR(s) | true |
mongodb.cr.name | Instance name (base name for sharded components) | pulse-mongodb |
mongodb.cr.type | replicaSet or shardedCluster | replicaSet |
mongodb.cr.version | MongoDB version | 7.0.14 |
mongodb.cr.replicaSet.members | Replica set members (replicaSet mode) | 3 |
mongodb.cr.shardedCluster.shardCount | Number of shard replica sets | 2 |
mongodb.cr.shardedCluster.membersPerShard | Members per shard replica set | 3 |
mongodb.cr.shardedCluster.mongosCount | mongos router instances | 2 |
mongodb.cr.shardedCluster.configServerCount | Config server replica set members | 3 |
mongodb.cr.shardedCluster.keyfile.value | Custom keyfile string (auto-generated if empty) | "" |
mongodb.cr.storage.size | Data volume size | 10Gi |
mongodb.cr.auth.adminUser | Default admin username | pulse-admin |
mongodb.cr.auth.adminPassword | Default admin password (CHANGE THIS) | changeme |
PostgreSQL (CloudNativePG)
| Parameter | Description | Default |
|---|---|---|
postgresql.enabled | Deploy CNPG operator + cluster | true |
postgresql.cr.create | Create Cluster CR | true |
postgresql.cr.name | Cluster name | pulse-postgresql |
postgresql.cr.instances | Number of instances | 3 |
postgresql.cr.version | PostgreSQL major version | 16 |
postgresql.cr.storage.size | Data volume size | 10Gi |
postgresql.cr.bootstrap.database | Initial database name | pulse |
postgresql.cr.bootstrap.owner | Database owner | pulse |
Elasticsearch (ECK)
| Parameter | Description | Default |
|---|---|---|
elasticsearch.enabled | Deploy ECK operator + cluster | true |
elasticsearch.cr.create | Create Elasticsearch CR | true |
elasticsearch.cr.name | Cluster name | pulse-elasticsearch |
elasticsearch.cr.version | Elasticsearch version | 8.17.0 |
elasticsearch.cr.nodeSets | Node set definitions (count, storage, resources) | 1 set, 3 nodes, 20Gi |
VictoriaMetrics
| Parameter | Description | Default |
|---|---|---|
victoriametrics.enabled | Deploy VM operator + instance | true |
victoriametrics.cr.create | Create VMSingle CR | true |
victoriametrics.cr.name | Instance name | pulse-victoriametrics |
victoriametrics.cr.retentionPeriod | Data retention period | 30d |
victoriametrics.cr.storage.size | Data volume size | 10Gi |
Redis (OpsTree)
| Parameter | Description | Default |
|---|---|---|
redis.enabled | Deploy Redis operator + instance | true |
redis.cr.create | Create Redis CR | true |
redis.cr.name | Instance name | pulse-redis |
redis.cr.mode | Deployment mode: standalone, cluster, replication, sentinel | standalone |
redis.cr.clusterSize | Nodes (for cluster, replication, sentinel modes) | 3 |
redis.cr.version | Redis image tag | v7.2.6 |
redis.cr.storage.size | Data volume size | 5Gi |
redis.cr.exporter.enabled | Enable Prometheus exporter sidecar | true |
NATS
nats.enabled | Deploy NATS | true |
nats.global.image.pullSecretNames | List of image pull secret names for private registries | [] |
nats.container.image.repository | Custom NATS server image repository | nats |
nats.container.image.tag | Custom NATS server image tag | 2.11.10-alpine |
nats.container.image.registry | Custom image registry (overrides Docker Hub) | "" |
nats.container.image.fullImageName | Full image name (overrides registry + repo + tag) | "" |
nats.natsBox.enabled | Deploy nats-box diagnostic toolbox | false |
nats.config.cluster.enabled | Enable NATS clustering | true |
nats.config.cluster.replicas | Cluster replicas | 3 |
nats.config.jetstream.enabled | Enable JetStream persistence | true |
nats.config.jetstream.fileStore.pvc.size | JetStream PVC size | 5Gi |
For full NATS chart values, see the official NATS chart docs.
Operator-Only Install
To deploy only the operators without creating database instances, which is useful for shared operator installations, set cr.create: false:
helm install pulse-db ./helm-databases \ --namespace pulse-databases \ --create-namespace \ --set mongodb.cr.create=false \ --set postgresql.cr.create=false \ --set elasticsearch.cr.create=false \ --set victoriametrics.cr.create=false \ --set redis.cr.create=falseYou can then create database instances separately by applying CRs with kubectl.
Skipping CRD Installation
If CRDs already exist in the cluster, from a prior install or another release, you may get ownership conflicts. Use these options to skip CRD installation:
helm install pulse-db ./helm-databases \ --namespace pulse-databases \ --create-namespace \ --skip-crds \ --set postgresql.crds.create=false \ --set elasticsearch.installCRDs=false \ --set victoriametrics.crds.enabled=false| Database | How to skip CRDs |
|---|---|
| MongoDB | --skip-crds flag (MCK uses Helm-native crds/ directory) |
| PostgreSQL | postgresql.crds.create=false |
| Elasticsearch | elasticsearch.installCRDs=false |
| VictoriaMetrics | victoriametrics.crds.enabled=false |
| Redis | --skip-crds flag (CRDs are in Helm-native crds/ directory) |
| NATS | No CRDs |
Alternatively, adopt existing CRDs into your release:
kubectl label crd mongodbcommunity.mongodbcommunity.mongodb.com \ app.kubernetes.io/managed-by=Helmkubectl annotate crd mongodbcommunity.mongodbcommunity.mongodb.com \ meta.helm.sh/release-name=<RELEASE_NAME> \ meta.helm.sh/release-namespace=<NAMESPACE>OpenShift Support
Set global.openshift=true to enable OpenShift-compatible settings:
helm install pulse-db ./helm-databases \ --namespace pulse-databases \ --create-namespace \ --set global.openshift=true \ --set postgresql.containerSecurityContext.runAsUser=null \ --set postgresql.containerSecurityContext.runAsGroup=nullThis will:
- Remove fixed
runAsUser/runAsGroupsettings from all CR pod templates (MongoDB, Elasticsearch, Redis, VictoriaMetrics, PostgreSQL) - Let OpenShift Security Context Constraints (SCCs) assign UIDs
- Avoid
privileged: truein all workloads
Built-in OpenShift support per operator
| Operator | OpenShift handling |
|---|---|
| ECK | Auto-detects OpenShift via config.setDefaultSecurityContext: "auto-detect" |
| VictoriaMetrics | Auto-adapts via global.compatibility.openshift.adaptSecurityContext: "auto" |
| OpsTree Redis | Built-in OpenShift support (openshift chart keyword) |
| CloudNativePG | Set postgresql.containerSecurityContext.runAsUser=null to clear hardcoded UID |
| MongoDB | CR template clears securityContext when global.openshift=true |
| NATS | Standard securityContext, runs as non-root by default |
Upgrading
helm dependency update ./helm-databaseshelm upgrade pulse-db ./helm-databases \ --namespace pulse-databasesUninstalling
helm uninstall pulse-db --namespace pulse-databasesCRDs are not automatically removed by Helm.
To remove CRDs manually, which deletes all custom resources, run:
kubectl get crd | grep -E 'mongodb|cnpg|elastic|victoriametrics|redis.opstreelabs' | awk '{print $1}' | xargs kubectl delete crdCommands to Install Databases on OpenShift
MongoDB
helm install pulse-mongo ./helm-databases \ -n pulse-mongo --create-namespace \ -f helm-databases/values/mongo-only.yaml \ --set mongodb.cr.version="8.0.18" \ --set mongodb.cr.mongodImage="191579300362.dkr.ecr.us-east-1.amazonaws.com/acceldata/ad-database:testBuild-k8sqe" \ --set global.openshift=true \ --set mongodb.managedSecurityContext=true \ --set global.imagePullSecrets[0]=adreg \ --set mongodb.registry.imagePullSecrets=adreg \ --set global.imagePullPolicy=IfNotPresent \ --set global.storageClassName='gp2-csi' \ --set global.imageCredentials.password='<REDACTED_EXISTING_SECRET>' \ --set mongodb.cr.storage.size=50Gi \ --set mongodb.cr.resources.limits.cpu=1 \ --set mongodb.cr.resources.limits.memory=4Gi \ --set mongodb.cr.resources.requests.cpu=500m \ --set mongodb.cr.resources.requests.memory=2Gi \ --timeout 20mVictoriaMetrics
helm install pulse-vm ./helm-databases \ -n pulse-vm --create-namespace \ --set victoriametrics.cr.auth.username=acceldata \ --set 'victoriametrics.cr.auth.password=D@t@Ops' \ --set mongodb.managedSecurityContext=true \ --set global.openshift=true \ --set nats.global.image.pullSecretNames[0]=adreg \ --set global.storageClassName='gp2-csi' \ --set global.imageCredentials.password='<REDACTED_EXISTING_SECRET>' \ --set victoriametrics.cr.vmstorage.storage.size=50Gi \ --set victoriametrics.cr.vmstorage.resources.limits.cpu=1 \ --set victoriametrics.cr.vmstorage.resources.limits.memory=4Gi \ --set victoriametrics.cr.vmstorage.resources.requests.cpu=500m \ --set victoriametrics.cr.vmstorage.resources.requests.memory=1Gi \ --set victoriametrics.cr.vmselect.storage.size=10Gi \ --set victoriametrics.cr.vmselect.resources.limits.cpu=1 \ --set victoriametrics.cr.vmselect.resources.limits.memory=2Gi \ --set victoriametrics.cr.vmselect.resources.requests.cpu=500m \ --set victoriametrics.cr.vmselect.resources.requests.memory=512Mi \ --set victoriametrics.cr.vminsert.resources.limits.cpu=1 \ --set victoriametrics.cr.vminsert.resources.limits.memory=2Gi \ --set victoriametrics.cr.vminsert.resources.requests.cpu=500m \ --set victoriametrics.cr.vminsert.resources.requests.memory=512Mi \ -f helm-databases/values/victoriametrics-only.yamlhelm upgrade pulse-vm ./helm-databases \ --namespace pulse-vm \ --reuse-valuesElastic
helm install pulse-es ./helm-databases \ -n pulse-es --create-namespace \ --set global.openshift=true \ --set mongodb.managedSecurityContext=true \ --set elasticsearch.cr.auth.password="admin_password" \ --set elasticsearch.cr.auth.additionalUsers[0].username=pulse \ --set elasticsearch.cr.auth.additionalUsers[0].password="data@ops" \ --set elasticsearch.cr.auth.additionalUsers[0].roles[0]=superuser \ --set elasticsearch.cr.tls.p12.password="" \ --set elasticsearch.cr.httpPort=19013 \ --set elasticsearch.cr.tls.disabled=true \ --set nats.global.image.pullSecretNames[1]=adreg \ --set global.storageClassName='gp2-csi' \ --set global.imageCredentials.password='<REDACTED_EXISTING_SECRET>' \ --set elasticsearch.cr.nodeSets[0].name=default \ --set elasticsearch.cr.nodeSets[0].count=3 \ --set elasticsearch.cr.nodeSets[0].config.node\\.store\\.allow_mmap=true \ --set elasticsearch.cr.nodeSets[0].storage.size=50Gi \ --set elasticsearch.cr.nodeSets[0].resources.limits.cpu=1 \ --set elasticsearch.cr.nodeSets[0].resources.limits.memory=8Gi \ --set elasticsearch.cr.nodeSets[0].resources.requests.cpu=500m \ --set elasticsearch.cr.nodeSets[0].resources.requests.memory=4Gi \ -f helm-databases/values/elastic-only.yamlhelm upgrade pulse-es ./helm-databases \ --namespace pulse-es \ --reuse-valueskubectl port-forward svc/pulse-elasticsearch-es-http -n pulse-es 19013:19013curl -s -u "pulse:data@ops" \ -X PUT "http://localhost:19013/_index_template/pulse-defaults" \ -H 'Content-Type: application/json' \ -d '{ "index_patterns": ["*"], "priority": 1, "template": { "settings": { "number_of_replicas": 1 } } }'Postgres
helm install pulse-pg ./helm-databases \ -n pulse-pg --create-namespace \ -f helm-databases/values/postgres-only.yaml \ --set postgresql.useOperator=false \ --set nats.global.image.pullSecretNames[0]=adreg \ --set global.storageClassName='gp2-csi' \ --set global.imageCredentials.password='<REDACTED_EXISTING_SECRET>' \ --set postgresql.standalone.storage.size=50Gi \ --set postgresql.standalone.resources.limits.cpu=1 \ --set postgresql.standalone.resources.limits.memory=4Gi \ --set postgresql.standalone.resources.requests.cpu=500m \ --set postgresql.standalone.resources.requests.memory=2Gi \ -f helm-databases/values/openshift.yamlNATS
helm install pulse-nats ./helm-databases \ -n pulse-nats --create-namespace \ --set global.openshift=true \ -f helm-databases/values/nats-only.yaml \ --set nats.global.image.pullSecretNames[0]=adreg \ --set nats.loadBalancer.enabled=true \ --set global.storageClassName='gp2-csi' \ --set nats.config.jetstream.fileStore.pvc.storageClassName='gp2-csi' \ --set global.imageCredentials.password='<REDACTED_EXISTING_SECRET>' \ --set nats.config.jetstream.fileStore.pvc.size=20Gi \ --set nats.container.merge.resources.limits.cpu=1 \ --set nats.container.merge.resources.limits.memory=4Gi \ --set nats.container.merge.resources.requests.cpu=500m \ --set nats.container.merge.resources.requests.memory=2GiFor additional help, contact www.acceldata.force.com OR call our service desk +1 844 9433282
Copyright © 2026