Skip to main content
Version: 2.0-rc2

Deployment Concept

Before you configure or deploy anything, make two independent, combinable decisions about how CIVITAS/CORE V2 lays out on your cluster. Both shape your namespace structure, RBAC, DNS planning and how upgrades roll out — and both are much easier to get right up front than to change later.

  1. How many instances share the cluster? — one installation per cluster, or several with shared operators.
  2. Namespace layout per instance — all components in one namespace, or one namespace per component.

This page explains the trade-offs and advises on each. For the actual settings see the Configuration guide; for the deploy commands see the Deployment guide.

How many instances per cluster?​

CIVITAS/CORE supports two deployment topologies on a cluster:

TopologyOperatorsWhen to use
Single instance per clusterDeployed together with the instance (all-in-one)Development clusters, dedicated single-tenantTenantAn isolated organizational partition that owns Data pools, Datasets, Users, Groups, and Roles. All access rules exist within their Tenant, and the Tenant is the widest Scope of a Role. Currently, one Tenant corresponds to the Platform. production clusters — anything that runs exactly one instance
Multiple instances per clusterDeployed once per cluster, shared by all instancesOne cluster hosting several independent installations (e.g. multiple clients, or staging + production)
tip

If there is any chance you will eventually run more than one instance on a cluster, start with the two-layer model below from the beginning. Splitting an already-deployed single instance into the shared-operator layout afterwards is more work than setting it up correctly up front.

The two-layer model​

For multi-instance deployments, the deployment is split into two layers:

  1. Operator layer — deployed once per cluster. Installs the cluster operators (CloudNativePGCloudNativePGA Kubernetes operator for running and managing PostgreSQL clusters. In CIVITAS/CORE it is used to provision and operate Postgres databases. for PostgreSQL, Strimzi for KafkaApache KafkaA distributed event streaming platform. In CIVITAS/CORE it is used as the message bus to transport events, models and data in data flows.) plus their CRDs and cluster-wide RBAC into a fixed, instance-independent namespace (civitas-operators by default), and the cluster-scoped runtime Kyverno policies (runtime-policies). The operators watch all namespaces, so a single deployment reconciles every instance on the cluster.
  2. Instance layer — deployed once per instance, any number of times. Installs everything else (KeycloakKeycloakAn open-source Identity and Access Management (IAM) solution providing SSO and OAuth2/OpenID Connect flows. In CIVITAS/CORE it is used to authenticate users and issue JWTs., APISIXApache APISIXAn open-source API gateway for traffic management, security and observability. In CIVITAS/CORE it is used as the centralized entrypoint to route and protect externally exposed APIs., Postgres clusters, KafkaApache KafkaA distributed event streaming platform. In CIVITAS/CORE it is used as the message bus to transport events, models and data in data flows. clusters, Portal, …) into a dedicated namespace named after the instance (global.instanceSlug). Each instance gets its own KeycloakKeycloakAn open-source Identity and Access Management (IAM) solution providing SSO and OAuth2/OpenID Connect flows. In CIVITAS/CORE it is used to authenticate users and issue JWTs. realm and its own subdomains and is fully isolated from the others.
Cluster
├── civitas-operators # operator layer (deployed ONCE)
│ ├── cloudnative-pg # watches all namespaces (clusterWide)
│ ├── strimzi-kafka-operator # watches all namespaces (watchAnyNamespace)
│ └── runtime-policies # cluster-scoped Kyverno ClusterPolicies (once per cluster)
├── <instanceSlug-a> # instance layer (per instance)
│ ├── postgres-cluster, kafka-cluster, keycloak, apisix, portal, …
└── <instanceSlug-b>
└── postgres-cluster, kafka-cluster, keycloak, apisix, portal, …

The shared operators reconcile the Cluster (CloudNativePGCloudNativePGA Kubernetes operator for running and managing PostgreSQL clusters. In CIVITAS/CORE it is used to provision and operate Postgres databases.) and Kafka (Strimzi) custom resources in every instance namespace — each instance still runs its own isolated Postgres cluster and KafkaApache KafkaA distributed event streaming platform. In CIVITAS/CORE it is used as the message bus to transport events, models and data in data flows. cluster. Only the cluster-scoped pieces (the operators with their CRDs and cluster-wide RBAC, and the runtime ClusterPolicy objects) are shared.

Because these shared pieces are cluster-scoped, they are deployed and upgraded once per cluster. The Deployment guide walks through the operator/instance flow; the Configuration guide covers instanceSlug and the operator namespace.

Namespace layout per instance​

Independently of how many instances share the cluster, each instance can run all its components in one namespace or give each component its own. This is controlled by global.singleNamespace:

ModelSettingWhen to use it
Single namespaceglobal.singleNamespace: true (default)Local development, demos, small clusters, or shared-tenantTenantAn isolated organizational partition that owns Data pools, Datasets, Users, Groups, and Roles. All access rules exist within their Tenant, and the Tenant is the widest Scope of a Role. Currently, one Tenant corresponds to the Platform. restrictions where you only get one namespace.
Multi namespaceglobal.singleNamespace: falseProduction and staging. Gives per-component isolation, clearer RBAC boundaries, and stricter network policies.

Namespaces are derived from global.instanceSlug and the component name:

  • Single namespace: everything lands in <instanceSlug> (e.g. dev).
  • Multi namespace: each component gets <instanceSlug>-<component> (e.g. dev-postgres, dev-keycloak, dev-apisix).
note

In multi-namespace mode the component suffix is appended to instanceSlug, so the combined name must stay within Kubernetes' 63-character limit — keep instanceSlug short.

Because everything is derived from instanceSlug, switching between the two models is a single configuration flag — you never rename namespaces by hand, and cross-namespace references that use component names keep working in both models. Set it in the Configuration guide. The per-component wiring (namespace overrides, cross-namespace references) is covered in Component Configuration.

How the two decisions combine​

The two choices are orthogonal and combine freely:

  • How many instances is about running the whole platform many times on one cluster behind one shared set of operators; each instance is keyed by its own instanceSlug.
  • Namespace layout is about how a single instance spreads its own components across namespaces.

So a single instance can still spread across many namespaces, and several instances can each run single-namespace — pick each independently. Neither choice constrains the other.