diff --git a/values/temporal/env-ekman.yaml.gotmpl b/values/temporal/env-ekman.yaml.gotmpl index edebb9ae..ecd14ae9 100644 --- a/values/temporal/env-ekman.yaml.gotmpl +++ b/values/temporal/env-ekman.yaml.gotmpl @@ -1,6 +1,6 @@ temporal: enabled: true - autosync: false + autosync: true ingress: true grpcIngress: true workerController: true diff --git a/values/temporal/manifests/network/temporal-policies.yaml b/values/temporal/manifests/network/temporal-policies.yaml index f97e5897..e7a81532 100644 --- a/values/temporal/manifests/network/temporal-policies.yaml +++ b/values/temporal/manifests/network/temporal-policies.yaml @@ -60,4 +60,19 @@ spec: protocol: UDP - port: "53" protocol: TCP +--- +apiVersion: cilium.io/v2 +kind: CiliumNetworkPolicy +metadata: + name: allow-web-oidc-login + namespace: temporal +spec: + description: Allow Temporal Web UI OIDC login to Entra ID + endpointSelector: + matchLabels: + app.kubernetes.io/component: web + egress: + - toFQDNs: + - matchName: login.microsoftonline.com + - matchPattern: '*.microsoftonline.com' {{- end }} diff --git a/values/temporal/manifests/temporal-db.yaml b/values/temporal/manifests/temporal-db.yaml index 41bd79a9..00b2aec5 100644 --- a/values/temporal/manifests/temporal-db.yaml +++ b/values/temporal/manifests/temporal-db.yaml @@ -12,9 +12,20 @@ spec: initdb: database: temporal owner: temporal + # headroom for ~240 server connections (30/pod x 8 pods) plus CNPG's own + postgresql: + parameters: + max_connections: "300" + resources: + requests: + cpu: 500m + memory: 1Gi + limits: + cpu: "2" + memory: 2Gi storage: resizeInUseVolumes: true - size: 10Gi + size: 20Gi --- apiVersion: postgresql.cnpg.io/v1 kind: Database diff --git a/values/temporal/values/temporal.yaml b/values/temporal/values/temporal.yaml index 24446433..8d531dfc 100644 --- a/values/temporal/values/temporal.yaml +++ b/values/temporal/values/temporal.yaml @@ -1,8 +1,12 @@ server: + # 2 replicas per role for HA; per-role blocks inherit this. + replicaCount: 2 config: + logLevel: "info" persistence: defaultStore: default visibilityStore: visibility + # immutable after first deploy numHistoryShards: 512 datastores: default: @@ -20,7 +24,7 @@ server: maxConns: 20 maxIdleConns: 20 maxConnLifetime: "1h" - # TODO: migrate visibility to Elasticsearch for advanced visibility search. + # Postgres 12+ gives advanced visibility; no Elasticsearch needed. visibility: sql: createDatabase: false @@ -41,8 +45,127 @@ server: timerType: histogram listenAddress: "0.0.0.0:9090" + # this cluster's Prometheus scrapes via ServiceMonitor, not pod annotations + metrics: + serviceMonitor: + enabled: true + interval: 30s + + resources: + requests: + cpu: 250m + memory: 512Mi + limits: + cpu: "1" + memory: 1Gi + + frontend: + podDisruptionBudget: + maxUnavailable: 1 + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: ScheduleAnyway + labelSelector: + matchLabels: + app.kubernetes.io/name: temporal + app.kubernetes.io/instance: temporal + app.kubernetes.io/component: frontend + + history: + # memory-heavy (shard/mutable-state cache) + resources: + requests: + cpu: 250m + memory: 768Mi + limits: + cpu: "1" + memory: 1536Mi + podDisruptionBudget: + maxUnavailable: 1 + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: ScheduleAnyway + labelSelector: + matchLabels: + app.kubernetes.io/name: temporal + app.kubernetes.io/instance: temporal + app.kubernetes.io/component: history + + matching: + podDisruptionBudget: + maxUnavailable: 1 + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: ScheduleAnyway + labelSelector: + matchLabels: + app.kubernetes.io/name: temporal + app.kubernetes.io/instance: temporal + app.kubernetes.io/component: matching + + worker: + podDisruptionBudget: + maxUnavailable: 1 + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: ScheduleAnyway + labelSelector: + matchLabels: + app.kubernetes.io/name: temporal + app.kubernetes.io/instance: temporal + app.kubernetes.io/component: worker + +# no persistent debug pod; use temporalio/admin-tools on demand +admintools: + enabled: false + web: enabled: true + replicaCount: 2 + resources: + requests: + cpu: 50m + memory: 128Mi + limits: + cpu: 250m + memory: 256Mi + podDisruptionBudget: + maxUnavailable: 1 + topologySpreadConstraints: + - maxSkew: 1 + topologyKey: kubernetes.io/hostname + whenUnsatisfiable: ScheduleAnyway + labelSelector: + matchLabels: + app.kubernetes.io/name: temporal + app.kubernetes.io/instance: temporal + app.kubernetes.io/component: web + # native OIDC SSO via Entra ID (same oceanbox-oidc secret as Grafana); gates UI login only + additionalEnv: + - name: TEMPORAL_AUTH_ENABLED + value: "true" + - name: TEMPORAL_AUTH_TYPE + value: "oidc" + - name: TEMPORAL_AUTH_PROVIDER_URL + value: "https://login.microsoftonline.com/3f737008-e9a0-4485-9d27-40329d288089/v2.0" + - name: TEMPORAL_AUTH_CLIENT_ID + valueFrom: + secretKeyRef: + name: oceanbox-oidc + key: client_id + - name: TEMPORAL_AUTH_CLIENT_SECRET + valueFrom: + secretKeyRef: + name: oceanbox-oidc + key: client_secret + - name: TEMPORAL_AUTH_CALLBACK_URL + value: "https://temporal.ekman.oceanbox.io/auth/sso/callback" + - name: TEMPORAL_AUTH_SCOPES + value: "openid,profile,email" schema: useHelmHooks: false