Kubernetes operator for Multigres — deploys, scales, and manages horizontally scalable PostgreSQL clusters with automated topology orchestration, drain-safe rolling updates, and admission webhooks
See the codeThe Multigres Operator is the Kubernetes entry point for Multigres v0.1.0 Alpha. It manages distributed, sharded PostgreSQL clusters across multiple failure domains (zones or regions) and provides a unified API to define the topology of your database system, handling the complex orchestration of shards, cells (failure domains), and gateways.
This alpha release is suitable for experimentation, demos, local testing, and feedback. It is not production-ready.
MultigresCluster) for the entire database topology.TableGroups and Shards as first-class citizens.CoreTemplate, CellTemplate, ShardTemplate) and reuse it across the cluster.spec.externalGateway with configurable externalIPs, tracked by a GatewayExternalReady condition.spec.externalAdminWeb, mirroring the gateway pattern with an AdminWebExternalReady condition.postgresql.conf overrides via postgresConfigRef on shard templates. ConfigMap content changes trigger automatic rolling updates.cert-manager.Install the operator with built-in self-signed certificate management:
kubectl apply --server-side -f \
https://github.com/multigres/multigres-operator/releases/download/v0.11.0/install.yaml
This deploys the operator into the multigres-operator namespace with:
Once the operator is running, try a sample cluster:
kubectl apply -f \
https://raw.githubusercontent.com/multigres/multigres-operator/v0.11.0/config/samples/postgres-password-secret.yaml
kubectl apply -f \
https://raw.githubusercontent.com/multigres/multigres-operator/v0.11.0/config/samples/minimal.yaml
For more sample configurations, see the samples directory.
| Option | Description | Guide |
|---|---|---|
| Self-signed certs (default) | Zero-config TLS — operator generates and rotates its own CA. | (Installed above) |
| cert-manager | External certificate management via cert-manager. | Cert-Manager Demo |
| Observability stack | Full metrics, tracing, and dashboards (Prometheus, Tempo, Grafana). | Observability Demo |
Multigres core and Multigres Operator are versioned separately. Documented release pairings are listed in the Multigres core release documentation.
| Release | Operator | Core | Kubernetes | PostgreSQL | Primary install path | Status |
|---|---|---|---|---|---|---|
| Initial OSS release | v0.11.x | v0.1.x | Kubernetes v1.25+ | PostgreSQL 17.x | Multigres Operator release manifests | Supported alpha |
The quick start above uses Multigres Operator v0.11.0, which defaults runtime images to Multigres core v0.1.0.
The Multigres Operator follows a Parent/Child architecture. You, the user, manage the Root resource (MultigresCluster) and its shared Templates. The operator automatically creates and reconciles all necessary child resources (Cells, TableGroups, Shards, TopoServers) to match your desired state.
[MultigresCluster] 🚀 (Root CR - User Editable)
│
├── 📍 Defines [TemplateDefaults] (Cluster-wide default templates)
│
├── 🌍 [GlobalTopoServer] (Child CR) ← 📄 Uses [CoreTemplate] OR inline [spec]
│
├── 🤖 MultiAdmin Resources ← 📄 Uses [CoreTemplate] OR inline [spec]
│
├── 💠 [Cell] (Child CR) ← 📄 Uses [CellTemplate] OR inline [spec]
│ │
│ ├── 🚪 MultiGateway Resources
│ └── 📡 [LocalTopoServer] (Child CR, optional)
│
└── 🗃️ [TableGroup] (Child CR)
│
└── 📦 [Shard] (Child CR) ← 📄 Uses [ShardTemplate] OR inline [spec]
│
├── 🧠 MultiOrch Resources (Deployment)
└── 🏊 Pools (Operator-managed Pods + PVCs)
📄 [CoreTemplate] (User-editable, scoped config)
├── globalTopoServer
└── multiadmin
📄 [CellTemplate] (User-editable, scoped config)
├── multigateway
└── localTopoServer (optional)
📄 [ShardTemplate] (User-editable, scoped config)
├── multiorch
└── pools (postgres + multipooler)
Important:
MultigresCluster, CoreTemplate, CellTemplate, and ShardTemplate are meant to be edited by users.Cell, TableGroup, Shard, TopoServer) are Read-Only. Any manual changes to them will be immediately reverted by the operator to ensure the system stays in sync with the root configuration.The operator uses a 4-Level Override Chain to resolve configuration for every component. This allows you to keep your MultigresCluster spec clean while maintaining full control when needed.
When determining the configuration for a component (e.g., a Shard), the operator looks for configuration in this order:
MultigresCluster YAML.spec.templateDefaults of the MultigresCluster.ShardTemplate) named "default" in the same namespace.Templates allow you to define standard configurations (e.g., "Standard High-Availability Cell"). You can then apply specific overrides on top of a template.
Example: Using a Template with Overrides
spec:
cells:
- name: "us-east-1a"
cellTemplate: "standard-ha-cell" # <--- Uses the template
overrides: # <--- Patches specific fields
multigateway:
replicas: 5 # <--- Overrides only the replica count
Note on Overrides: When using overrides, you must provide the complete struct for the section you are overriding if it's a pointer. For specific fields like resources, it's safer to ensure you provide the full context if the merge behavior isn't granular enough for your needs (currently, the resolver performs a deep merge).
[!WARNING] When a template (
CoreTemplate,CellTemplate, orShardTemplate) is updated, all clusters using that template are reconciled immediately. This means changes to a shared template propagate to every referencing cluster at once.
For production environments where you want controlled rollouts, consider versioning templates by name:
# Instead of editing "standard-shard" in-place...
apiVersion: multigres.com/v1alpha1
kind: ShardTemplate
metadata:
name: standard-shard-v2 # <--- New version = new resource
spec:
# ... updated configuration
Then update each cluster's templateRef individually when ready:
spec:
templateDefaults:
shardTemplate: "standard-shard-v2" # <--- Opt-in to the new version
[!NOTE] Avoid using
default-named templates (the namespace-level fallback) in production if you need controlled rollouts. They cannot be versioned since any cluster without an explicit template reference will automatically use whichever template is nameddefault.This mechanism may change in future versions. See Template Propagation for details on planned improvements.
The operator integrates pgBackRest for automated backups, WAL archiving, and point-in-time recovery (PITR). Two storage backends are supported: S3 (recommended for production and multi-cell clusters) and Filesystem (PVC-based, for development/single-node). Backup configuration is fully declarative and propagates from the cluster level down to individual shards.
Key features:
[!WARNING] Filesystem backups are cell-local. Cross-cell failover cannot restore from another cell's backup. Use S3 for multi-cell clusters.
📖 Full documentation: Backup & Restore Guide
The operator ships with built-in support for metrics, alerting, distributed tracing, and structured logging.
trace_id/span_id injection for log-trace correlation📖 Full documentation: Observability Guide · Observability Demo
The operator includes a Mutating and Validating Webhook to enforce defaults and data integrity.
By default, the operator manages its own TLS certificates using the generic pkg/cert module. This implements a Split-Secret PKI architecture:
MutatingWebhookConfiguration and ValidatingWebhookConfiguration with the CA bundle.If you prefer to use cert-manager or another external tool, deploy using the cert-manager overlay (install-certmanager.yaml). This overlay:
Certificate and ClusterIssuer resource for cert-manager to manage./var/run/secrets/webhook so certificates exist on disk at startup.The operator automatically detects the certificate management strategy on startup:
📖 Cert-Manager walkthrough: Cert-Manager Demo
The operator's Mutating Webhook materialises all defaults (images, replicas, resources, backup config, etc.) directly into the MultigresCluster spec stored in etcd. This means kubectl get multigrescluster -o yaml always shows the full effective configuration — no hidden in-memory defaults.
Some fields (like cell assignments on shards) are intentionally kept dynamic and resolved at reconcile time. The resolved values are visible on child CRs (Shard, TableGroup).
If you use GitOps tooling (ArgoCD, Flux), the webhook-materialised fields can cause diffs between your Git manifests and the live state. The documentation covers recommended mitigations.
📖 Full documentation: Webhook Defaults & GitOps Guide
Multigres uses a configurable durability policy to control synchronous replication quorum. The default policy is AT_LEAST_2, which requires every write to be acknowledged by at least 2 nodes (the primary + 1 synchronous standby). For multi-AZ clusters, MULTI_CELL_AT_LEAST_2 enforces cross-zone quorum. This has implications for how many replicas you should run per cell in readWrite pools.
| Replicas per Cell | Configuration | Rolling Upgrade Behavior |
|---|---|---|
| 1 | 1 pod (primary only, no standbys) | Downtime during upgrades. No standby to maintain quorum. |
| 2 | 1 primary + 1 standby | Downtime during upgrades. Draining the standby leaves zero synchronous standbys, violating AT_LEAST_2. Upstream multigres rejects the UpdateSynchronousStandbyList REMOVE because it would empty the synchronous standby list. |
| 3 (recommended) | 1 primary + 2 standbys | Zero-downtime upgrades. One standby can be drained while the other maintains quorum. |
Pools default to replicasPerCell: 1. AT_LEAST_2 requires 2 total poolers; MULTI_CELL_AT_LEAST_2 requires poolers in 2 cells. For high availability, use at least 3 total poolers so the policy remains achievable while one pooler is unavailable.
📖 Full documentation: Durability Policy
Please be aware of the following constraints in the current version:
postgres and marked default: true.0-inf - this is a limitation of the current implementation of Multigres.cluster-db-tg) exceeds 28 characters, the operator automatically hashes the database and tablegroup names to ensure that the resulting child resource names (Shards, Pods, PVCs) stay within Kubernetes limits (63 chars).zone and region in Cell definitions are immutable after creation.| Resource | Description |
|---|---|
| Operator Capability Levels | Maturity assessment against the Operator Framework capability model |
| Webhook Defaults & GitOps | How the webhook materialises defaults, dynamic cell resolution, and GitOps compatibility |
| Durability Policy | Configurable replication quorum: AT_LEAST_2 (default) and MULTI_CELL_AT_LEAST_2 for cross-AZ durability |
| External Admin Web | External exposure for the multiadmin-web Service |
| PostgreSQL Configuration | Custom postgresql.conf overrides via ConfigMap reference |
| Storage Management | PVC deletion policies (Retain/Delete) and volume expansion |
| Configuration Reference | Operator flags, environment variables, and logging |
| Demos | Guided walkthroughs (webhook, cert-manager, observability) |
| Developer Documentation | Internal architecture, controller patterns, caching strategy |
| Contributing | Development setup, local Kind deployment, code style |
| Changelog | Release history |
| Multigres v0.1.0 Alpha | Core alpha release paired with this operator release |
| Multigres Discussions | Feedback, questions, and community discussion |
| Operator Releases | Published operator versions and install manifests |
Go
97.6%
JavaScript
1.2%
Kubernetes operator for Multigres — deploys, scales, and manages horizontally scalable PostgreSQL clusters with automated topology orchestration, drain-safe rolling updates, and admission webhooks
See the codeThe Multigres Operator is the Kubernetes entry point for Multigres v0.1.0 Alpha. It manages distributed, sharded PostgreSQL clusters across multiple failure domains (zones or regions) and provides a unified API to define the topology of your database system, handling the complex orchestration of shards, cells (failure domains), and gateways.
This alpha release is suitable for experimentation, demos, local testing, and feedback. It is not production-ready.
MultigresCluster) for the entire database topology.TableGroups and Shards as first-class citizens.CoreTemplate, CellTemplate, ShardTemplate) and reuse it across the cluster.spec.externalGateway with configurable externalIPs, tracked by a GatewayExternalReady condition.spec.externalAdminWeb, mirroring the gateway pattern with an AdminWebExternalReady condition.postgresql.conf overrides via postgresConfigRef on shard templates. ConfigMap content changes trigger automatic rolling updates.cert-manager.Install the operator with built-in self-signed certificate management:
kubectl apply --server-side -f \
https://github.com/multigres/multigres-operator/releases/download/v0.11.0/install.yaml
This deploys the operator into the multigres-operator namespace with:
Once the operator is running, try a sample cluster:
kubectl apply -f \
https://raw.githubusercontent.com/multigres/multigres-operator/v0.11.0/config/samples/postgres-password-secret.yaml
kubectl apply -f \
https://raw.githubusercontent.com/multigres/multigres-operator/v0.11.0/config/samples/minimal.yaml
For more sample configurations, see the samples directory.
| Option | Description | Guide |
|---|---|---|
| Self-signed certs (default) | Zero-config TLS — operator generates and rotates its own CA. | (Installed above) |
| cert-manager | External certificate management via cert-manager. | Cert-Manager Demo |
| Observability stack | Full metrics, tracing, and dashboards (Prometheus, Tempo, Grafana). | Observability Demo |
Multigres core and Multigres Operator are versioned separately. Documented release pairings are listed in the Multigres core release documentation.
| Release | Operator | Core | Kubernetes | PostgreSQL | Primary install path | Status |
|---|---|---|---|---|---|---|
| Initial OSS release | v0.11.x | v0.1.x | Kubernetes v1.25+ | PostgreSQL 17.x | Multigres Operator release manifests | Supported alpha |
The quick start above uses Multigres Operator v0.11.0, which defaults runtime images to Multigres core v0.1.0.
The Multigres Operator follows a Parent/Child architecture. You, the user, manage the Root resource (MultigresCluster) and its shared Templates. The operator automatically creates and reconciles all necessary child resources (Cells, TableGroups, Shards, TopoServers) to match your desired state.
[MultigresCluster] 🚀 (Root CR - User Editable)
│
├── 📍 Defines [TemplateDefaults] (Cluster-wide default templates)
│
├── 🌍 [GlobalTopoServer] (Child CR) ← 📄 Uses [CoreTemplate] OR inline [spec]
│
├── 🤖 MultiAdmin Resources ← 📄 Uses [CoreTemplate] OR inline [spec]
│
├── 💠 [Cell] (Child CR) ← 📄 Uses [CellTemplate] OR inline [spec]
│ │
│ ├── 🚪 MultiGateway Resources
│ └── 📡 [LocalTopoServer] (Child CR, optional)
│
└── 🗃️ [TableGroup] (Child CR)
│
└── 📦 [Shard] (Child CR) ← 📄 Uses [ShardTemplate] OR inline [spec]
│
├── 🧠 MultiOrch Resources (Deployment)
└── 🏊 Pools (Operator-managed Pods + PVCs)
📄 [CoreTemplate] (User-editable, scoped config)
├── globalTopoServer
└── multiadmin
📄 [CellTemplate] (User-editable, scoped config)
├── multigateway
└── localTopoServer (optional)
📄 [ShardTemplate] (User-editable, scoped config)
├── multiorch
└── pools (postgres + multipooler)
Important:
MultigresCluster, CoreTemplate, CellTemplate, and ShardTemplate are meant to be edited by users.Cell, TableGroup, Shard, TopoServer) are Read-Only. Any manual changes to them will be immediately reverted by the operator to ensure the system stays in sync with the root configuration.The operator uses a 4-Level Override Chain to resolve configuration for every component. This allows you to keep your MultigresCluster spec clean while maintaining full control when needed.
When determining the configuration for a component (e.g., a Shard), the operator looks for configuration in this order:
MultigresCluster YAML.spec.templateDefaults of the MultigresCluster.ShardTemplate) named "default" in the same namespace.Templates allow you to define standard configurations (e.g., "Standard High-Availability Cell"). You can then apply specific overrides on top of a template.
Example: Using a Template with Overrides
spec:
cells:
- name: "us-east-1a"
cellTemplate: "standard-ha-cell" # <--- Uses the template
overrides: # <--- Patches specific fields
multigateway:
replicas: 5 # <--- Overrides only the replica count
Note on Overrides: When using overrides, you must provide the complete struct for the section you are overriding if it's a pointer. For specific fields like resources, it's safer to ensure you provide the full context if the merge behavior isn't granular enough for your needs (currently, the resolver performs a deep merge).
[!WARNING] When a template (
CoreTemplate,CellTemplate, orShardTemplate) is updated, all clusters using that template are reconciled immediately. This means changes to a shared template propagate to every referencing cluster at once.
For production environments where you want controlled rollouts, consider versioning templates by name:
# Instead of editing "standard-shard" in-place...
apiVersion: multigres.com/v1alpha1
kind: ShardTemplate
metadata:
name: standard-shard-v2 # <--- New version = new resource
spec:
# ... updated configuration
Then update each cluster's templateRef individually when ready:
spec:
templateDefaults:
shardTemplate: "standard-shard-v2" # <--- Opt-in to the new version
[!NOTE] Avoid using
default-named templates (the namespace-level fallback) in production if you need controlled rollouts. They cannot be versioned since any cluster without an explicit template reference will automatically use whichever template is nameddefault.This mechanism may change in future versions. See Template Propagation for details on planned improvements.
The operator integrates pgBackRest for automated backups, WAL archiving, and point-in-time recovery (PITR). Two storage backends are supported: S3 (recommended for production and multi-cell clusters) and Filesystem (PVC-based, for development/single-node). Backup configuration is fully declarative and propagates from the cluster level down to individual shards.
Key features:
[!WARNING] Filesystem backups are cell-local. Cross-cell failover cannot restore from another cell's backup. Use S3 for multi-cell clusters.
📖 Full documentation: Backup & Restore Guide
The operator ships with built-in support for metrics, alerting, distributed tracing, and structured logging.
trace_id/span_id injection for log-trace correlation📖 Full documentation: Observability Guide · Observability Demo
The operator includes a Mutating and Validating Webhook to enforce defaults and data integrity.
By default, the operator manages its own TLS certificates using the generic pkg/cert module. This implements a Split-Secret PKI architecture:
MutatingWebhookConfiguration and ValidatingWebhookConfiguration with the CA bundle.If you prefer to use cert-manager or another external tool, deploy using the cert-manager overlay (install-certmanager.yaml). This overlay:
Certificate and ClusterIssuer resource for cert-manager to manage./var/run/secrets/webhook so certificates exist on disk at startup.The operator automatically detects the certificate management strategy on startup:
📖 Cert-Manager walkthrough: Cert-Manager Demo
The operator's Mutating Webhook materialises all defaults (images, replicas, resources, backup config, etc.) directly into the MultigresCluster spec stored in etcd. This means kubectl get multigrescluster -o yaml always shows the full effective configuration — no hidden in-memory defaults.
Some fields (like cell assignments on shards) are intentionally kept dynamic and resolved at reconcile time. The resolved values are visible on child CRs (Shard, TableGroup).
If you use GitOps tooling (ArgoCD, Flux), the webhook-materialised fields can cause diffs between your Git manifests and the live state. The documentation covers recommended mitigations.
📖 Full documentation: Webhook Defaults & GitOps Guide
Multigres uses a configurable durability policy to control synchronous replication quorum. The default policy is AT_LEAST_2, which requires every write to be acknowledged by at least 2 nodes (the primary + 1 synchronous standby). For multi-AZ clusters, MULTI_CELL_AT_LEAST_2 enforces cross-zone quorum. This has implications for how many replicas you should run per cell in readWrite pools.
| Replicas per Cell | Configuration | Rolling Upgrade Behavior |
|---|---|---|
| 1 | 1 pod (primary only, no standbys) | Downtime during upgrades. No standby to maintain quorum. |
| 2 | 1 primary + 1 standby | Downtime during upgrades. Draining the standby leaves zero synchronous standbys, violating AT_LEAST_2. Upstream multigres rejects the UpdateSynchronousStandbyList REMOVE because it would empty the synchronous standby list. |
| 3 (recommended) | 1 primary + 2 standbys | Zero-downtime upgrades. One standby can be drained while the other maintains quorum. |
Pools default to replicasPerCell: 1. AT_LEAST_2 requires 2 total poolers; MULTI_CELL_AT_LEAST_2 requires poolers in 2 cells. For high availability, use at least 3 total poolers so the policy remains achievable while one pooler is unavailable.
📖 Full documentation: Durability Policy
Please be aware of the following constraints in the current version:
postgres and marked default: true.0-inf - this is a limitation of the current implementation of Multigres.cluster-db-tg) exceeds 28 characters, the operator automatically hashes the database and tablegroup names to ensure that the resulting child resource names (Shards, Pods, PVCs) stay within Kubernetes limits (63 chars).zone and region in Cell definitions are immutable after creation.| Resource | Description |
|---|---|
| Operator Capability Levels | Maturity assessment against the Operator Framework capability model |
| Webhook Defaults & GitOps | How the webhook materialises defaults, dynamic cell resolution, and GitOps compatibility |
| Durability Policy | Configurable replication quorum: AT_LEAST_2 (default) and MULTI_CELL_AT_LEAST_2 for cross-AZ durability |
| External Admin Web | External exposure for the multiadmin-web Service |
| PostgreSQL Configuration | Custom postgresql.conf overrides via ConfigMap reference |
| Storage Management | PVC deletion policies (Retain/Delete) and volume expansion |
| Configuration Reference | Operator flags, environment variables, and logging |
| Demos | Guided walkthroughs (webhook, cert-manager, observability) |
| Developer Documentation | Internal architecture, controller patterns, caching strategy |
| Contributing | Development setup, local Kind deployment, code style |
| Changelog | Release history |
| Multigres v0.1.0 Alpha | Core alpha release paired with this operator release |
| Multigres Discussions | Feedback, questions, and community discussion |
| Operator Releases | Published operator versions and install manifests |
Go
97.6%
JavaScript
1.2%