Manifests
#
01-cnpg.yaml
#
# CloudNativePG (CNPG) Postgres used as the Temporal datastore.
#
# Prerequisite: the CNPG operator must be installed in the cluster, e.g.:
# kubectl apply --server-side -f \
# https://raw.githubusercontent.com/cloudnative-pg/cloudnative-pg/release-1.24/releases/cnpg-1.24.0.yaml
#
# Two things Temporal needs that aren't obvious:
#
# 1. Two databases. The operator only runs schema setup (setup-schema); it
# does NOT create databases. initdb creates "temporal"; the postInitSQL
# below creates the separate "temporal_visibility" database.
#
# 2. Enough connections. Each Temporal service pod opens a connection pool to
# BOTH stores, which blows past Postgres's default max_connections of 100
# and surfaces as "remaining connection slots are reserved for ... SUPERUSER"
# (SQLSTATE 53300). Raise it to 200.
#
# CNPG generates a Secret "temporal-pg-app" (keys: username, password) for the
# "temporal" app user, referenced by the TemporalCluster. Do NOT redeclare the
# "temporal" role under spec.managed.roles without a passwordSecret — CNPG would
# reset it to PASSWORD NULL / NOLOGIN and break password authentication.
apiVersion: v1
kind: Namespace
metadata:
name: temporal
---
apiVersion: postgresql.cnpg.io/v1
kind: Cluster
metadata:
name: temporal-pg
namespace: temporal
spec:
instances: 1
storage:
size: 5Gi
postgresql:
parameters:
max_connections: "200"
bootstrap:
initdb:
database: temporal
owner: temporal
postInitSQL:
- CREATE DATABASE temporal_visibility OWNER temporal;
02-temporalcluster.yaml
#
# A TemporalCluster backed by the CNPG Postgres from 01-cnpg.yaml.
#
# The operator reconciler pings the datastore from its OWN pod (in the
# temporal-system namespace), so the persistence host must be a
# namespace-qualified FQDN. A bare "temporal-pg-rw" would resolve in the
# operator's namespace and fail with PersistenceUnreachable.
apiVersion: temporal.bmor10.com/v1alpha1
kind: TemporalCluster
metadata:
name: temporal
namespace: temporal
spec:
version: "1.31.1"
numHistoryShards: 512
persistence:
defaultStore:
sql:
pluginName: postgres12
host: temporal-pg-rw.temporal.svc.cluster.local
port: 5432
database: temporal
user: temporal
passwordSecretRef:
name: temporal-pg-app
key: password
visibilityStore:
sql:
pluginName: postgres12
host: temporal-pg-rw.temporal.svc.cluster.local
port: 5432
database: temporal_visibility
user: temporal
passwordSecretRef:
name: temporal-pg-app
key: password
# Web UI. Reach it with `kubectl -n temporal port-forward svc/temporal-ui
# 8080:8080`, or uncomment the ingress block to expose it.
ui:
enabled: true
# ingress:
# enabled: true
# ingressClassName: nginx
# host: temporal.example.com
# tlsSecretName: temporal-example-com-tls
# annotations:
# cert-manager.io/cluster-issuer: letsencrypt-prod
---
# Declarative namespace registered on the cluster once it is Ready.
apiVersion: temporal.bmor10.com/v1alpha1
kind: TemporalNamespace
metadata:
name: default
namespace: temporal
spec:
clusterRef:
name: temporal
retentionPeriod: "72h"
description: "Default namespace"
allowDeletion: true