chore: import upstream snapshot with attribution
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
Publish CLI Package / publish-npm (push) Waiting to run
Publish Python SDK / publish-pypi (push) Waiting to run
Publish TypeScript SDK / publish-npm (push) Waiting to run
CI / Migrate Dev DB (push) Has been skipped
CI / Detect Version (push) Has been cancelled
CI / Migrate DB (push) Has been cancelled
CI / Build Dev ECR (./docker/app.Dockerfile, ECR_APP) (push) Has been cancelled
CI / Build Dev ECR (./docker/db.Dockerfile, ECR_MIGRATIONS) (push) Has been cancelled
CI / Build Dev ECR (./docker/pii.Dockerfile, ECR_PII) (push) Has been cancelled
CI / Build Dev ECR (./docker/realtime.Dockerfile, ECR_REALTIME) (push) Has been cancelled
CI / Deploy Trigger.dev (Dev) (push) Has been cancelled
CI / Build AMD64 (./docker/app.Dockerfile, ECR_APP, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build AMD64 (./docker/db.Dockerfile, ECR_MIGRATIONS, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build AMD64 (./docker/pii.Dockerfile, ECR_PII, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build AMD64 (./docker/realtime.Dockerfile, ECR_REALTIME, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/app.Dockerfile, ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/db.Dockerfile, ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/pii.Dockerfile, ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Build ARM64 (GHCR Only) (./docker/realtime.Dockerfile, ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/migrations) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/pii) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/realtime) (push) Has been cancelled
CI / Create GHCR Manifests (ghcr.io/simstudioai/simstudio) (push) Has been cancelled
CI / Check Docs Changes (push) Has been cancelled
CI / Process Docs (push) Has been cancelled
CI / Create GitHub Release (push) Has been cancelled
CI / Test and Build (push) Has been cancelled
This commit is contained in:
@@ -0,0 +1,101 @@
|
||||
{{- /*
|
||||
NOTES.txt — printed after every `helm install` or `helm upgrade`.
|
||||
Keep this short and action-oriented. Users land here and decide what to do next.
|
||||
*/ -}}
|
||||
|
||||
Thank you for installing {{ .Chart.Name }} ({{ .Chart.Name }}-{{ .Chart.Version }}, app {{ .Chart.AppVersion }}).
|
||||
|
||||
Your release is named {{ .Release.Name }} in namespace {{ .Release.Namespace }}.
|
||||
|
||||
1. Watch the rollout finish:
|
||||
|
||||
kubectl --namespace {{ .Release.Namespace }} rollout status deployment/{{ include "sim.fullname" . }}-app
|
||||
{{- if .Values.realtime.enabled }}
|
||||
kubectl --namespace {{ .Release.Namespace }} rollout status deployment/{{ include "sim.fullname" . }}-realtime
|
||||
{{- end }}
|
||||
{{- if .Values.copilot.enabled }}
|
||||
kubectl --namespace {{ .Release.Namespace }} rollout status deployment/{{ include "sim.fullname" . }}-copilot
|
||||
{{- end }}
|
||||
{{- if .Values.pii.enabled }}
|
||||
kubectl --namespace {{ .Release.Namespace }} rollout status deployment/{{ include "sim.fullname" . }}-pii
|
||||
{{- end }}
|
||||
|
||||
2. Reach the application:
|
||||
{{- if and .Values.ingress.enabled .Values.ingress.app.host }}
|
||||
|
||||
Sim is exposed at:
|
||||
{{- if .Values.ingress.tls.enabled }}
|
||||
https://{{ .Values.ingress.app.host }}
|
||||
{{- else }}
|
||||
http://{{ .Values.ingress.app.host }}
|
||||
{{- end }}
|
||||
|
||||
If DNS is not yet wired up, point your hostname at the ingress controller's
|
||||
external IP/LoadBalancer.
|
||||
{{- else }}
|
||||
|
||||
Ingress is disabled. Use port-forward to reach the app locally:
|
||||
|
||||
kubectl --namespace {{ .Release.Namespace }} port-forward svc/{{ include "sim.fullname" . }}-app {{ .Values.app.service.port | default 3000 }}:{{ .Values.app.service.port | default 3000 }}
|
||||
|
||||
Then open http://localhost:{{ .Values.app.service.port | default 3000 }}
|
||||
|
||||
To expose Sim on the public internet, enable `ingress.enabled=true` and set
|
||||
`ingress.app.host`. See examples/values-production.yaml.
|
||||
{{- end }}
|
||||
|
||||
3. Required secrets:
|
||||
|
||||
Sim requires three application secrets and a Postgres password to start.
|
||||
{{- if .Values.externalSecrets.enabled }}
|
||||
|
||||
Using External Secrets Operator. Verify the ExternalSecret has synced:
|
||||
kubectl --namespace {{ .Release.Namespace }} get externalsecret
|
||||
kubectl --namespace {{ .Release.Namespace }} get secret {{ include "sim.fullname" . }}-app-secrets
|
||||
{{- else if .Values.app.secrets.existingSecret.enabled }}
|
||||
|
||||
Using existing Kubernetes Secret: {{ .Values.app.secrets.existingSecret.name }}
|
||||
{{- else if or (eq (default "" .Values.app.env.BETTER_AUTH_SECRET) "") (eq (default "" .Values.app.env.ENCRYPTION_KEY) "") (eq (default "" .Values.app.env.INTERNAL_API_SECRET) "") }}
|
||||
|
||||
WARNING: one or more required secrets is empty. The pods will fail to start
|
||||
until these are set. Generate values with:
|
||||
|
||||
openssl rand -hex 32 # BETTER_AUTH_SECRET, ENCRYPTION_KEY, INTERNAL_API_SECRET, CRON_SECRET
|
||||
openssl rand -hex 32 # API_ENCRYPTION_KEY (must be 64 hex chars)
|
||||
|
||||
Then pass them on `helm upgrade --set app.env.BETTER_AUTH_SECRET=...` or
|
||||
provision an existing Kubernetes Secret and set
|
||||
`app.secrets.existingSecret.enabled=true`.
|
||||
{{- else }}
|
||||
|
||||
Secrets are set inline. For production, prefer pre-existing Kubernetes
|
||||
Secrets or External Secrets Operator — see
|
||||
examples/values-existing-secret.yaml and examples/values-external-secrets.yaml.
|
||||
{{- end }}
|
||||
|
||||
4. Useful commands:
|
||||
|
||||
# Tail app logs
|
||||
kubectl --namespace {{ .Release.Namespace }} logs -f deployment/{{ include "sim.fullname" . }}-app
|
||||
|
||||
# Show the rendered values
|
||||
helm get values {{ .Release.Name }} --namespace {{ .Release.Namespace }}
|
||||
|
||||
# Upgrade after changing values
|
||||
helm upgrade {{ .Release.Name }} ./helm/sim --namespace {{ .Release.Namespace }} -f your-values.yaml
|
||||
|
||||
5. Upgrade notes (read before upgrading from a chart version released before this one):
|
||||
|
||||
* externalSecrets.apiVersion default is "v1beta1" (was "v1"). v1beta1 is
|
||||
supported by every ESO release from v0.7+ through current. If you're on
|
||||
ESO v0.17+ and want the graduated v1 API, set externalSecrets.apiVersion: "v1".
|
||||
* networkPolicy.egress remains a list of custom egress rules (unchanged).
|
||||
Cloud-metadata CIDR blocking is now configured via networkPolicy.egressExceptCidrs
|
||||
(defaults to AWS/GCP/Azure IMDS + ECS task metadata).
|
||||
|
||||
6. Where to go next:
|
||||
|
||||
* Production checklist: helm/sim/README.md (search "Production checklist")
|
||||
* Troubleshooting: helm/sim/README.md (search "Troubleshooting")
|
||||
* Docs: https://docs.sim.ai
|
||||
* Issues: https://github.com/simstudioai/sim/issues
|
||||
@@ -0,0 +1,683 @@
|
||||
{{/*
|
||||
Expand the name of the chart.
|
||||
*/}}
|
||||
{{- define "sim.name" -}}
|
||||
{{- default .Chart.Name .Values.nameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create a default fully qualified app name.
|
||||
We truncate at 63 chars because some Kubernetes name fields are limited to this (by the DNS naming spec).
|
||||
If release name contains chart name it will be used as a full name.
|
||||
*/}}
|
||||
{{- define "sim.fullname" -}}
|
||||
{{- if .Values.fullnameOverride }}
|
||||
{{- .Values.fullnameOverride | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- $name := default .Chart.Name .Values.nameOverride }}
|
||||
{{- if contains $name .Release.Name }}
|
||||
{{- .Release.Name | trunc 63 | trimSuffix "-" }}
|
||||
{{- else }}
|
||||
{{- printf "%s-%s" .Release.Name $name | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create chart name and version as used by the chart label.
|
||||
*/}}
|
||||
{{- define "sim.chart" -}}
|
||||
{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Common labels
|
||||
*/}}
|
||||
{{- define "sim.labels" -}}
|
||||
helm.sh/chart: {{ include "sim.chart" . }}
|
||||
{{ include "sim.selectorLabels" . }}
|
||||
{{- if .Chart.AppVersion }}
|
||||
app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
|
||||
{{- end }}
|
||||
app.kubernetes.io/managed-by: {{ .Release.Service }}
|
||||
{{- with .Values.global.commonLabels }}
|
||||
{{ toYaml . }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Selector labels
|
||||
*/}}
|
||||
{{- define "sim.selectorLabels" -}}
|
||||
app.kubernetes.io/name: {{ include "sim.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
App specific labels
|
||||
*/}}
|
||||
{{- define "sim.app.labels" -}}
|
||||
{{ include "sim.labels" . }}
|
||||
app.kubernetes.io/component: app
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
App selector labels
|
||||
*/}}
|
||||
{{- define "sim.app.selectorLabels" -}}
|
||||
{{ include "sim.selectorLabels" . }}
|
||||
app.kubernetes.io/component: app
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Realtime specific labels
|
||||
*/}}
|
||||
{{- define "sim.realtime.labels" -}}
|
||||
{{ include "sim.labels" . }}
|
||||
app.kubernetes.io/component: realtime
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Realtime selector labels
|
||||
*/}}
|
||||
{{- define "sim.realtime.selectorLabels" -}}
|
||||
{{ include "sim.selectorLabels" . }}
|
||||
app.kubernetes.io/component: realtime
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
PostgreSQL specific labels
|
||||
*/}}
|
||||
{{- define "sim.postgresql.labels" -}}
|
||||
{{ include "sim.labels" . }}
|
||||
app.kubernetes.io/component: postgresql
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
PostgreSQL selector labels
|
||||
*/}}
|
||||
{{- define "sim.postgresql.selectorLabels" -}}
|
||||
{{ include "sim.selectorLabels" . }}
|
||||
app.kubernetes.io/component: postgresql
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Ollama specific labels
|
||||
*/}}
|
||||
{{- define "sim.ollama.labels" -}}
|
||||
{{ include "sim.labels" . }}
|
||||
app.kubernetes.io/component: ollama
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Ollama selector labels
|
||||
*/}}
|
||||
{{- define "sim.ollama.selectorLabels" -}}
|
||||
{{ include "sim.selectorLabels" . }}
|
||||
app.kubernetes.io/component: ollama
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
PII (Presidio) specific labels
|
||||
*/}}
|
||||
{{- define "sim.pii.labels" -}}
|
||||
{{ include "sim.labels" . }}
|
||||
app.kubernetes.io/component: pii
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
PII (Presidio) selector labels
|
||||
*/}}
|
||||
{{- define "sim.pii.selectorLabels" -}}
|
||||
{{ include "sim.selectorLabels" . }}
|
||||
app.kubernetes.io/component: pii
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Migrations specific labels
|
||||
*/}}
|
||||
{{- define "sim.migrations.labels" -}}
|
||||
{{ include "sim.labels" . }}
|
||||
app.kubernetes.io/component: migrations
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Copilot specific labels
|
||||
*/}}
|
||||
{{- define "sim.copilot.labels" -}}
|
||||
{{ include "sim.labels" . }}
|
||||
app.kubernetes.io/component: copilot
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Copilot selector labels
|
||||
*/}}
|
||||
{{- define "sim.copilot.selectorLabels" -}}
|
||||
{{ include "sim.selectorLabels" . }}
|
||||
app.kubernetes.io/component: copilot
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Copilot PostgreSQL specific labels
|
||||
*/}}
|
||||
{{- define "sim.copilotPostgresql.labels" -}}
|
||||
{{ include "sim.labels" . }}
|
||||
app.kubernetes.io/component: copilot-postgresql
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Copilot PostgreSQL selector labels
|
||||
*/}}
|
||||
{{- define "sim.copilotPostgresql.selectorLabels" -}}
|
||||
{{ include "sim.selectorLabels" . }}
|
||||
app.kubernetes.io/component: copilot-postgresql
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create the name of the service account to use
|
||||
*/}}
|
||||
{{- define "sim.serviceAccountName" -}}
|
||||
{{- if .Values.serviceAccount.create }}
|
||||
{{- default (include "sim.fullname" .) .Values.serviceAccount.name }}
|
||||
{{- else }}
|
||||
{{- default "default" .Values.serviceAccount.name }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Create image name with optional registry and digest pinning.
|
||||
Accepts a context dict with:
|
||||
imageRoot — the image object (repository, optional tag, optional digest, pullPolicy)
|
||||
global — .Values.global (for imageRegistry and useRegistryForAllImages)
|
||||
chartAppVersion — .Chart.AppVersion (used as default tag when imageRoot.tag is empty)
|
||||
|
||||
Resolution order:
|
||||
1. If imageRoot.digest is set, render "<registry?/>repo@<digest>"
|
||||
2. Else render "<registry?/>repo:<tag>" where tag defaults to chartAppVersion
|
||||
Usage: {{ include "sim.image" (dict "imageRoot" .Values.app.image "global" .Values.global "chartAppVersion" .Chart.AppVersion) }}
|
||||
*/}}
|
||||
{{- define "sim.image" -}}
|
||||
{{- $imageRoot := .imageRoot -}}
|
||||
{{- $global := .global -}}
|
||||
{{- $repository := $imageRoot.repository -}}
|
||||
{{- $digest := $imageRoot.digest | default "" -}}
|
||||
{{- $tag := $imageRoot.tag | default "" | toString -}}
|
||||
{{- if and (eq $tag "") (eq $digest "") -}}
|
||||
{{- $tag = .chartAppVersion | default "" | toString -}}
|
||||
{{- end -}}
|
||||
{{- $registry := "" -}}
|
||||
{{- if and $global $global.imageRegistry -}}
|
||||
{{- if or (hasPrefix "simstudioai/" $repository) $global.useRegistryForAllImages -}}
|
||||
{{- $registry = $global.imageRegistry -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- $repoPath := $repository -}}
|
||||
{{- if $registry -}}
|
||||
{{- $repoPath = printf "%s/%s" $registry $repository -}}
|
||||
{{- end -}}
|
||||
{{- if ne $digest "" -}}
|
||||
{{- printf "%s@%s" $repoPath $digest }}
|
||||
{{- else -}}
|
||||
{{- $resolvedTag := required (printf "sim.image: no tag or digest resolvable for %q (set imageRoot.tag, imageRoot.digest, or Chart.AppVersion)" $repository) $tag -}}
|
||||
{{- printf "%s:%s" $repoPath $resolvedTag }}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Database URL for internal PostgreSQL
|
||||
*/}}
|
||||
{{- define "sim.databaseUrl" -}}
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
{{- $host := printf "%s-postgresql" (include "sim.fullname" .) }}
|
||||
{{- $port := .Values.postgresql.service.port }}
|
||||
{{- $username := .Values.postgresql.auth.username }}
|
||||
{{- $database := .Values.postgresql.auth.database }}
|
||||
{{- $sslMode := ternary "require" "disable" .Values.postgresql.tls.enabled }}
|
||||
{{- printf "postgresql://%s:$(POSTGRES_PASSWORD)@%s:%v/%s?sslmode=%s" $username $host $port $database $sslMode }}
|
||||
{{- else if .Values.externalDatabase.enabled }}
|
||||
{{- $host := .Values.externalDatabase.host }}
|
||||
{{- $port := .Values.externalDatabase.port }}
|
||||
{{- $username := .Values.externalDatabase.username }}
|
||||
{{- $database := .Values.externalDatabase.database }}
|
||||
{{- $sslMode := .Values.externalDatabase.sslMode }}
|
||||
{{- printf "postgresql://%s:$(EXTERNAL_DB_PASSWORD)@%s:%v/%s?sslmode=%s" $username $host $port $database $sslMode }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Validate required secrets and reject default placeholder values
|
||||
Skip validation when using existing secrets or External Secrets Operator
|
||||
*/}}
|
||||
{{- define "sim.validateSecrets" -}}
|
||||
{{- $useExistingAppSecret := and .Values.app.secrets .Values.app.secrets.existingSecret .Values.app.secrets.existingSecret.enabled }}
|
||||
{{- $useExternalSecrets := and .Values.externalSecrets .Values.externalSecrets.enabled }}
|
||||
{{- $useExistingPostgresSecret := and .Values.postgresql.auth.existingSecret .Values.postgresql.auth.existingSecret.enabled }}
|
||||
{{- $useExistingExternalDbSecret := and .Values.externalDatabase.existingSecret .Values.externalDatabase.existingSecret.enabled }}
|
||||
{{- /* App secrets validation - skip if using existing secret or ESO */ -}}
|
||||
{{- if not (or $useExistingAppSecret $useExternalSecrets) }}
|
||||
{{- if and .Values.app.enabled (not .Values.app.env.BETTER_AUTH_SECRET) }}
|
||||
{{- fail "app.env.BETTER_AUTH_SECRET is required for production deployment" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.app.enabled (eq .Values.app.env.BETTER_AUTH_SECRET "CHANGE-ME-32-CHAR-SECRET-FOR-PRODUCTION-USE") }}
|
||||
{{- fail "app.env.BETTER_AUTH_SECRET must not use the default placeholder value. Generate a secure secret with: openssl rand -hex 32" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.app.enabled (not .Values.app.env.ENCRYPTION_KEY) }}
|
||||
{{- fail "app.env.ENCRYPTION_KEY is required for production deployment" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.app.enabled (eq .Values.app.env.ENCRYPTION_KEY "CHANGE-ME-32-CHAR-ENCRYPTION-KEY-FOR-PROD") }}
|
||||
{{- fail "app.env.ENCRYPTION_KEY must not use the default placeholder value. Generate a secure key with: openssl rand -hex 32" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.app.enabled (not .Values.app.env.INTERNAL_API_SECRET) }}
|
||||
{{- fail "app.env.INTERNAL_API_SECRET is required for production deployment (shared auth between sim-app and sim-realtime pods). Generate one with: openssl rand -hex 32" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.realtime.enabled (eq .Values.realtime.env.BETTER_AUTH_SECRET "CHANGE-ME-32-CHAR-SECRET-FOR-PRODUCTION-USE") }}
|
||||
{{- fail "realtime.env.BETTER_AUTH_SECRET must not use the default placeholder value. Generate a secure secret with: openssl rand -hex 32" }}
|
||||
{{- end }}
|
||||
{{- /* CRON_SECRET is required when cronjobs are enabled — pods reference it via secretKeyRef and would fail to start if the key is missing from the Secret. */ -}}
|
||||
{{- if and .Values.cronjobs.enabled (not .Values.app.env.CRON_SECRET) }}
|
||||
{{- fail "app.env.CRON_SECRET is required when cronjobs.enabled=true (every cron pod authenticates with this token). Generate one with: openssl rand -hex 32, or set cronjobs.enabled=false." }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- /* PostgreSQL password validation - skip if using existing secret or ESO */ -}}
|
||||
{{- if not (or $useExistingPostgresSecret $useExternalSecrets) }}
|
||||
{{- if and .Values.postgresql.enabled (not .Values.postgresql.auth.password) }}
|
||||
{{- fail "postgresql.auth.password is required when using internal PostgreSQL" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.postgresql.enabled (eq .Values.postgresql.auth.password "CHANGE-ME-SECURE-PASSWORD") }}
|
||||
{{- fail "postgresql.auth.password must not use the default placeholder value. Set a secure password for production" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.postgresql.enabled .Values.postgresql.auth.password (not (regexMatch "^[a-zA-Z0-9._-]+$" .Values.postgresql.auth.password)) }}
|
||||
{{- fail "postgresql.auth.password must only contain alphanumeric characters, hyphens, underscores, or periods to ensure DATABASE_URL compatibility. Generate with: openssl rand -base64 16 | tr -d '/+='" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- /* External database password validation - skip if using existing secret or ESO */ -}}
|
||||
{{- if not (or $useExistingExternalDbSecret $useExternalSecrets) }}
|
||||
{{- if and .Values.externalDatabase.enabled (not .Values.externalDatabase.password) }}
|
||||
{{- fail "externalDatabase.password is required when using external database" }}
|
||||
{{- end }}
|
||||
{{- if and .Values.externalDatabase.enabled .Values.externalDatabase.password (not (regexMatch "^[a-zA-Z0-9._-]+$" .Values.externalDatabase.password)) }}
|
||||
{{- fail "externalDatabase.password must only contain alphanumeric characters, hyphens, underscores, or periods to ensure DATABASE_URL compatibility." }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- /* ESO coverage validation - every key set in app.env / realtime.env must be mapped in externalSecrets.remoteRefs.app */ -}}
|
||||
{{- include "sim.validateExternalSecretCoverage" . }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Validate that every key set in app.env / realtime.env is also mapped in
|
||||
externalSecrets.remoteRefs.app when ESO is enabled. When ESO is on, the
|
||||
chart-managed Secret is not rendered — anything not mapped via ESO would
|
||||
be silently missing at runtime.
|
||||
|
||||
Chart-computed keys (DATABASE_URL, SOCKET_SERVER_URL, OLLAMA_URL, PII_URL)
|
||||
are exempt because they're inlined on the container, not sourced from the
|
||||
Secret.
|
||||
|
||||
Fail-fast is only safe for ESO because we can introspect remoteRefs at
|
||||
template time. For existingSecret we cannot read the user's pre-created
|
||||
Secret, so coverage there is documented (values.yaml + README) rather
|
||||
than enforced.
|
||||
*/}}
|
||||
{{- define "sim.validateExternalSecretCoverage" -}}
|
||||
{{- if and .Values.externalSecrets .Values.externalSecrets.enabled -}}
|
||||
{{- $remoteRefs := default (dict) (default (dict) .Values.externalSecrets.remoteRefs).app -}}
|
||||
{{- $chartComputed := list "DATABASE_URL" "SOCKET_SERVER_URL" "OLLAMA_URL" "PII_URL" -}}
|
||||
{{- $appEnv := default (dict) .Values.app.env -}}
|
||||
{{/*
|
||||
Required-key coverage: these are non-optional at runtime. With ESO enabled
|
||||
the chart-managed Secret is not rendered, so a missing key surfaces as a
|
||||
runtime CrashLoopBackOff with cryptic env errors. Fail at template time
|
||||
if the key is neither set in app.env nor mapped via remoteRefs.app.
|
||||
*/}}
|
||||
{{- if .Values.app.enabled -}}
|
||||
{{- $required := list "BETTER_AUTH_SECRET" "ENCRYPTION_KEY" "INTERNAL_API_SECRET" -}}
|
||||
{{- if .Values.cronjobs.enabled -}}
|
||||
{{- $required = append $required "CRON_SECRET" -}}
|
||||
{{- end -}}
|
||||
{{- range $key := $required -}}
|
||||
{{- $inEnv := index $appEnv $key -}}
|
||||
{{- $mapped := index $remoteRefs $key -}}
|
||||
{{- if and (or (not $inEnv) (eq (toString $inEnv) "") (eq (toString $inEnv) "<nil>")) (not $mapped) -}}
|
||||
{{- fail (printf "Required key '%s' is missing: externalSecrets.enabled=true but the key is neither set in app.env nor mapped in externalSecrets.remoteRefs.app. Map it via externalSecrets.remoteRefs.app.%s='path/in/store' so it is synced into the app Secret." $key $key) }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- if .Values.app.enabled -}}
|
||||
{{- range $key, $value := default (dict) .Values.app.env -}}
|
||||
{{- if not (has $key $chartComputed) -}}
|
||||
{{- if and (ne (toString $value) "") (ne (toString $value) "<nil>") -}}
|
||||
{{- $mapped := index $remoteRefs $key -}}
|
||||
{{- if not $mapped -}}
|
||||
{{- fail (printf "Key '%s' is set in app.env but externalSecrets.enabled=true and externalSecrets.remoteRefs.app.%s is not configured. When ESO is enabled the chart-managed app Secret is not rendered, so the container would start with no value. Either map it via externalSecrets.remoteRefs.app.%s='path/in/store' or remove it from app.env." $key $key $key) }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- if .Values.realtime.enabled -}}
|
||||
{{- range $key, $value := default (dict) .Values.realtime.env -}}
|
||||
{{- if not (has $key $chartComputed) -}}
|
||||
{{- if and (ne (toString $value) "") (ne (toString $value) "<nil>") -}}
|
||||
{{- $mapped := index $remoteRefs $key -}}
|
||||
{{- if not $mapped -}}
|
||||
{{- fail (printf "Key '%s' is set in realtime.env but externalSecrets.enabled=true and externalSecrets.remoteRefs.app.%s is not configured. Either map it via externalSecrets.remoteRefs.app.%s='path/in/store' or remove it from realtime.env." $key $key $key) }}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Get the app secrets name
|
||||
Returns the name of the secret containing app credentials (auth, encryption keys)
|
||||
*/}}
|
||||
{{- define "sim.appSecretName" -}}
|
||||
{{- if and .Values.app.secrets .Values.app.secrets.existingSecret .Values.app.secrets.existingSecret.enabled -}}
|
||||
{{- .Values.app.secrets.existingSecret.name -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-app-secrets" (include "sim.fullname" .) -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Get the PostgreSQL secret name
|
||||
Returns the name of the secret containing PostgreSQL password
|
||||
*/}}
|
||||
{{- define "sim.postgresqlSecretName" -}}
|
||||
{{- if and .Values.postgresql.auth.existingSecret .Values.postgresql.auth.existingSecret.enabled -}}
|
||||
{{- .Values.postgresql.auth.existingSecret.name -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-postgresql-secret" (include "sim.fullname" .) -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Get the PostgreSQL password key name
|
||||
Returns the key name in the secret that contains the password
|
||||
*/}}
|
||||
{{- define "sim.postgresqlPasswordKey" -}}
|
||||
{{- if and .Values.postgresql.auth.existingSecret .Values.postgresql.auth.existingSecret.enabled -}}
|
||||
{{- .Values.postgresql.auth.existingSecret.passwordKey | default "POSTGRES_PASSWORD" -}}
|
||||
{{- else -}}
|
||||
{{- print "POSTGRES_PASSWORD" -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Get the external database secret name
|
||||
Returns the name of the secret containing external database password
|
||||
*/}}
|
||||
{{- define "sim.externalDbSecretName" -}}
|
||||
{{- if and .Values.externalDatabase.existingSecret .Values.externalDatabase.existingSecret.enabled -}}
|
||||
{{- .Values.externalDatabase.existingSecret.name -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-external-db-secret" (include "sim.fullname" .) -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Get the external database password key name
|
||||
Returns the key name in the secret that contains the password
|
||||
*/}}
|
||||
{{- define "sim.externalDbPasswordKey" -}}
|
||||
{{- if and .Values.externalDatabase.existingSecret .Values.externalDatabase.existingSecret.enabled -}}
|
||||
{{- .Values.externalDatabase.existingSecret.passwordKey | default "EXTERNAL_DB_PASSWORD" -}}
|
||||
{{- else -}}
|
||||
{{- print "EXTERNAL_DB_PASSWORD" -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Check if app secrets should be created by the chart
|
||||
Returns true if we should create the app secrets (not using existing or ESO)
|
||||
*/}}
|
||||
{{- define "sim.createAppSecrets" -}}
|
||||
{{- $useExistingAppSecret := and .Values.app.secrets .Values.app.secrets.existingSecret .Values.app.secrets.existingSecret.enabled }}
|
||||
{{- $useExternalSecrets := and .Values.externalSecrets .Values.externalSecrets.enabled }}
|
||||
{{- if not (or $useExistingAppSecret $useExternalSecrets) -}}
|
||||
true
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Check if PostgreSQL secret should be created by the chart
|
||||
Returns true if we should create the PostgreSQL secret (not using existing or ESO)
|
||||
*/}}
|
||||
{{- define "sim.createPostgresqlSecret" -}}
|
||||
{{- $useExistingSecret := and .Values.postgresql.auth.existingSecret .Values.postgresql.auth.existingSecret.enabled }}
|
||||
{{- $useExternalSecrets := and .Values.externalSecrets .Values.externalSecrets.enabled }}
|
||||
{{- if not (or $useExistingSecret $useExternalSecrets) -}}
|
||||
true
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Check if external database secret should be created by the chart
|
||||
Returns true if we should create the external database secret (not using existing or ESO)
|
||||
*/}}
|
||||
{{- define "sim.createExternalDbSecret" -}}
|
||||
{{- $useExistingSecret := and .Values.externalDatabase.existingSecret .Values.externalDatabase.existingSecret.enabled }}
|
||||
{{- $useExternalSecrets := and .Values.externalSecrets .Values.externalSecrets.enabled }}
|
||||
{{- if not (or $useExistingSecret $useExternalSecrets) -}}
|
||||
true
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Ollama URL
|
||||
*/}}
|
||||
{{- define "sim.ollamaUrl" -}}
|
||||
{{- if .Values.ollama.enabled }}
|
||||
{{- $serviceName := printf "%s-ollama" (include "sim.fullname" .) }}
|
||||
{{- $port := .Values.ollama.service.port }}
|
||||
{{- printf "http://%s:%v" $serviceName $port }}
|
||||
{{- else }}
|
||||
{{- .Values.app.env.OLLAMA_URL | default "http://localhost:11434" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
PII (Presidio) service URL
|
||||
*/}}
|
||||
{{- define "sim.piiUrl" -}}
|
||||
{{- if .Values.pii.enabled }}
|
||||
{{- $serviceName := printf "%s-pii" (include "sim.fullname" .) }}
|
||||
{{- $port := .Values.pii.service.port }}
|
||||
{{- printf "http://%s:%v" $serviceName $port }}
|
||||
{{- else }}
|
||||
{{- .Values.app.env.PII_URL | default "http://localhost:5001" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Socket Server URL (internal)
|
||||
*/}}
|
||||
{{- define "sim.socketServerUrl" -}}
|
||||
{{- if .Values.realtime.enabled }}
|
||||
{{- $serviceName := printf "%s-realtime" (include "sim.fullname" .) }}
|
||||
{{- $port := .Values.realtime.service.port }}
|
||||
{{- printf "http://%s:%v" $serviceName $port }}
|
||||
{{- else }}
|
||||
{{- .Values.app.env.SOCKET_SERVER_URL | default "http://localhost:3002" }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Resource limits and requests
|
||||
*/}}
|
||||
{{- define "sim.resources" -}}
|
||||
{{- if .resources }}
|
||||
resources:
|
||||
{{- if .resources.limits }}
|
||||
limits:
|
||||
{{- toYaml .resources.limits | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if .resources.requests }}
|
||||
requests:
|
||||
{{- toYaml .resources.requests | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Pod-level security context with Pod Security Standards "restricted" defaults.
|
||||
User-supplied `.podSecurityContext` values override defaults (user wins).
|
||||
Usage: {{ include "sim.podSecurityContext" .Values.app | nindent 6 }}
|
||||
*/}}
|
||||
{{- define "sim.podSecurityContext" -}}
|
||||
{{- $defaults := dict "runAsNonRoot" true "runAsUser" 1001 "runAsGroup" 1001 "fsGroup" 1001 "seccompProfile" (dict "type" "RuntimeDefault") -}}
|
||||
{{- $user := default (dict) .podSecurityContext -}}
|
||||
{{- $merged := mergeOverwrite (deepCopy $defaults) $user -}}
|
||||
securityContext:
|
||||
{{- toYaml $merged | nindent 2 }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Container-level security context with Pod Security Standards "restricted" defaults.
|
||||
User-supplied `.securityContext` values override defaults (user wins).
|
||||
`readOnlyRootFilesystem` is intentionally NOT defaulted — set it per-workload in values
|
||||
when the container can tolerate a read-only root (Next.js writes to `.next/cache`,
|
||||
Postgres writes to `/var/lib/postgresql/data`, so they're left writable by default).
|
||||
Usage: {{ include "sim.containerSecurityContext" .Values.app | nindent 10 }}
|
||||
*/}}
|
||||
{{- define "sim.containerSecurityContext" -}}
|
||||
{{- $defaults := dict "runAsNonRoot" true "allowPrivilegeEscalation" false "capabilities" (dict "drop" (list "ALL")) "seccompProfile" (dict "type" "RuntimeDefault") -}}
|
||||
{{- $user := default (dict) .securityContext -}}
|
||||
{{- $merged := mergeOverwrite (deepCopy $defaults) $user -}}
|
||||
securityContext:
|
||||
{{- toYaml $merged | nindent 2 }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Backwards-compatible alias for container security context.
|
||||
*/}}
|
||||
{{- define "sim.securityContext" -}}
|
||||
{{- include "sim.containerSecurityContext" . }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Node selector
|
||||
*/}}
|
||||
{{- define "sim.nodeSelector" -}}
|
||||
{{- if .nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml .nodeSelector | nindent 2 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Tolerations
|
||||
*/}}
|
||||
{{- define "sim.tolerations" -}}
|
||||
{{- if .tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml .tolerations | nindent 2 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Affinity
|
||||
*/}}
|
||||
{{- define "sim.affinity" -}}
|
||||
{{- if .affinity }}
|
||||
affinity:
|
||||
{{- toYaml .affinity | nindent 2 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Topology spread constraints — spreads pods across failure domains.
|
||||
Pass the per-component spec (.Values.app, .Values.realtime, ...). Users supply
|
||||
the full constraint list including labelSelector; pattern mirrors affinity.
|
||||
Usage: {{ include "sim.topologySpreadConstraints" .Values.app | nindent 6 }}
|
||||
*/}}
|
||||
{{- define "sim.topologySpreadConstraints" -}}
|
||||
{{- if .topologySpreadConstraints }}
|
||||
topologySpreadConstraints:
|
||||
{{- toYaml .topologySpreadConstraints | nindent 2 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Copilot environment secret name
|
||||
*/}}
|
||||
{{- define "sim.copilot.envSecretName" -}}
|
||||
{{- if and .Values.copilot.server.secret.name (ne .Values.copilot.server.secret.name "") -}}
|
||||
{{- .Values.copilot.server.secret.name -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-copilot-env" (include "sim.fullname" .) -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Copilot database secret name
|
||||
*/}}
|
||||
{{- define "sim.copilot.databaseSecretName" -}}
|
||||
{{- if .Values.copilot.postgresql.enabled -}}
|
||||
{{- printf "%s-copilot-postgresql-secret" (include "sim.fullname" .) -}}
|
||||
{{- else if and .Values.copilot.database.existingSecretName (ne .Values.copilot.database.existingSecretName "") -}}
|
||||
{{- .Values.copilot.database.existingSecretName -}}
|
||||
{{- else -}}
|
||||
{{- printf "%s-copilot-database-secret" (include "sim.fullname" .) -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Copilot database secret key
|
||||
*/}}
|
||||
{{- define "sim.copilot.databaseSecretKey" -}}
|
||||
{{- default "DATABASE_URL" .Values.copilot.database.secretKey -}}
|
||||
{{- end }}
|
||||
|
||||
{{/*
|
||||
Validate Copilot configuration
|
||||
*/}}
|
||||
{{- define "sim.copilot.validate" -}}
|
||||
{{- if .Values.copilot.enabled -}}
|
||||
{{- if and (not .Values.copilot.server.secret.create) (or (not .Values.copilot.server.secret.name) (eq .Values.copilot.server.secret.name "")) -}}
|
||||
{{- fail "copilot.server.secret.name must be provided when copilot.server.secret.create=false" -}}
|
||||
{{- end -}}
|
||||
{{- if .Values.copilot.server.secret.create -}}
|
||||
{{- $env := .Values.copilot.server.env -}}
|
||||
{{- $useExternalSecrets := and .Values.externalSecrets .Values.externalSecrets.enabled -}}
|
||||
{{- $remoteRefs := default (dict) (default (dict) .Values.externalSecrets.remoteRefs).copilot -}}
|
||||
{{- $required := list "AGENT_API_DB_ENCRYPTION_KEY" "INTERNAL_API_SECRET" "LICENSE_KEY" "SIM_BASE_URL" "SIM_AGENT_API_KEY" "REDIS_URL" -}}
|
||||
{{- range $key := $required -}}
|
||||
{{- $inEnv := and $env (index $env $key) (ne (index $env $key) "") -}}
|
||||
{{- $mapped := index $remoteRefs $key -}}
|
||||
{{- if not (or $inEnv (and $useExternalSecrets $mapped)) -}}
|
||||
{{- if $useExternalSecrets -}}
|
||||
{{- fail (printf "Required key '%s' is missing: externalSecrets.enabled=true but the key is neither set in copilot.server.env nor mapped in externalSecrets.remoteRefs.copilot. Map it via externalSecrets.remoteRefs.copilot.%s='path/in/store' so it is synced into the copilot Secret." $key $key) -}}
|
||||
{{- else -}}
|
||||
{{- fail (printf "copilot.server.env.%s is required when copilot is enabled" $key) -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- if $useExternalSecrets -}}
|
||||
{{- range $key, $value := $env -}}
|
||||
{{- if and (ne (toString $value) "") (ne (toString $value) "<nil>") -}}
|
||||
{{- if not (index $remoteRefs $key) -}}
|
||||
{{- fail (printf "Key '%s' is set in copilot.server.env but externalSecrets.enabled=true and externalSecrets.remoteRefs.copilot.%s is not configured. When ESO is enabled the chart-managed copilot Secret is not rendered, so the container would start with no value. Either map it via externalSecrets.remoteRefs.copilot.%s='path/in/store' or remove it from copilot.server.env." $key $key $key) -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- $hasOpenAI := or (and $env (ne (default "" (index $env "OPENAI_API_KEY_1")) "")) (and $useExternalSecrets (index $remoteRefs "OPENAI_API_KEY_1")) -}}
|
||||
{{- $hasAnthropic := or (and $env (ne (default "" (index $env "ANTHROPIC_API_KEY_1")) "")) (and $useExternalSecrets (index $remoteRefs "ANTHROPIC_API_KEY_1")) -}}
|
||||
{{- if not (or $hasOpenAI $hasAnthropic) -}}
|
||||
{{- fail "Set at least one of copilot.server.env.OPENAI_API_KEY_1 or copilot.server.env.ANTHROPIC_API_KEY_1 (or map one via externalSecrets.remoteRefs.copilot when externalSecrets.enabled=true)" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- if .Values.copilot.postgresql.enabled -}}
|
||||
{{- if or (not .Values.copilot.postgresql.auth.password) (eq .Values.copilot.postgresql.auth.password "") -}}
|
||||
{{- fail "copilot.postgresql.auth.password is required when copilot.postgresql.enabled=true" -}}
|
||||
{{- end -}}
|
||||
{{- else -}}
|
||||
{{- if and (or (not .Values.copilot.database.existingSecretName) (eq .Values.copilot.database.existingSecretName "")) (or (not .Values.copilot.database.url) (eq .Values.copilot.database.url "")) -}}
|
||||
{{- fail "Provide copilot.database.existingSecretName or copilot.database.url when copilot.postgresql.enabled=false" -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end -}}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,84 @@
|
||||
{{- if .Values.certManager.enabled }}
|
||||
{{- /*
|
||||
cert-manager Issuer Bootstrap Pattern
|
||||
|
||||
PREREQUISITE: cert-manager must be installed in your cluster before enabling this.
|
||||
The root CA Certificate is created in the namespace specified by certManager.rootCA.namespace
|
||||
(defaults to "cert-manager"). Ensure this namespace exists and cert-manager is running there.
|
||||
|
||||
Install cert-manager: https://cert-manager.io/docs/installation/
|
||||
|
||||
This implements the recommended pattern from cert-manager documentation:
|
||||
1. A self-signed ClusterIssuer (for bootstrapping the root CA only)
|
||||
2. A root CA Certificate (self-signed, used to sign other certificates)
|
||||
3. A CA ClusterIssuer (uses the root CA to sign certificates)
|
||||
|
||||
Reference: https://cert-manager.io/docs/configuration/selfsigned/
|
||||
*/ -}}
|
||||
|
||||
---
|
||||
# 1. Self-Signed ClusterIssuer (Bootstrap Only)
|
||||
# This issuer is used ONLY to create the root CA certificate.
|
||||
# It should NOT be used directly for application certificates.
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: ClusterIssuer
|
||||
metadata:
|
||||
name: {{ .Values.certManager.selfSignedIssuer.name }}
|
||||
labels:
|
||||
{{- include "sim.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: cert-manager
|
||||
spec:
|
||||
selfSigned: {}
|
||||
|
||||
---
|
||||
# 2. Root CA Certificate
|
||||
# This certificate is signed by the self-signed issuer and becomes the root of trust.
|
||||
# The secret created here will be used by the CA issuer to sign certificates.
|
||||
# NOTE: This must be created in the cert-manager namespace (or the namespace specified
|
||||
# in certManager.rootCA.namespace). Ensure cert-manager is installed there first.
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: {{ .Values.certManager.rootCA.certificateName }}
|
||||
namespace: {{ .Values.certManager.rootCA.namespace | default "cert-manager" }} # Must match cert-manager's cluster-resource-namespace
|
||||
labels:
|
||||
{{- include "sim.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: cert-manager
|
||||
spec:
|
||||
isCA: true
|
||||
commonName: {{ .Values.certManager.rootCA.commonName }}
|
||||
secretName: {{ .Values.certManager.rootCA.secretName }}
|
||||
duration: {{ .Values.certManager.rootCA.duration | default "87600h" }}
|
||||
renewBefore: {{ .Values.certManager.rootCA.renewBefore | default "2160h" }}
|
||||
privateKey:
|
||||
algorithm: {{ .Values.certManager.rootCA.privateKey.algorithm | default "RSA" }}
|
||||
size: {{ .Values.certManager.rootCA.privateKey.size | default 4096 }}
|
||||
subject:
|
||||
organizations:
|
||||
{{- if .Values.certManager.rootCA.subject.organizations }}
|
||||
{{- toYaml .Values.certManager.rootCA.subject.organizations | nindent 6 }}
|
||||
{{- else }}
|
||||
- {{ .Release.Name }}
|
||||
{{- end }}
|
||||
issuerRef:
|
||||
name: {{ .Values.certManager.selfSignedIssuer.name }}
|
||||
kind: ClusterIssuer
|
||||
group: cert-manager.io
|
||||
|
||||
---
|
||||
# 3. CA ClusterIssuer
|
||||
# This is the issuer that should be used by applications to obtain certificates.
|
||||
# It signs certificates using the root CA created above.
|
||||
# NOTE: This issuer may briefly show "not ready" on first install while cert-manager
|
||||
# processes the Certificate above and creates the secret. It will auto-reconcile.
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: ClusterIssuer
|
||||
metadata:
|
||||
name: {{ .Values.certManager.caIssuer.name }}
|
||||
labels:
|
||||
{{- include "sim.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: cert-manager
|
||||
spec:
|
||||
ca:
|
||||
secretName: {{ .Values.certManager.rootCA.secretName }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,35 @@
|
||||
{{- if and .Values.postgresql.enabled .Values.postgresql.tls.enabled }}
|
||||
apiVersion: cert-manager.io/v1
|
||||
kind: Certificate
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-postgresql-tls-certificate
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.postgresql.labels" . | nindent 4 }}
|
||||
spec:
|
||||
secretName: {{ .Values.postgresql.tls.certificatesSecret }}
|
||||
duration: {{ .Values.postgresql.tls.duration | default "87600h" }} # Default: 10 years
|
||||
renewBefore: {{ .Values.postgresql.tls.renewBefore | default "2160h" }} # Default: 90 days before expiry
|
||||
isCA: false
|
||||
privateKey:
|
||||
algorithm: {{ .Values.postgresql.tls.privateKey.algorithm | default "RSA" }}
|
||||
size: {{ .Values.postgresql.tls.privateKey.size | default 4096 }}
|
||||
{{- if .Values.postgresql.tls.rotationPolicy }}
|
||||
rotationPolicy: {{ .Values.postgresql.tls.rotationPolicy }}
|
||||
{{- end }}
|
||||
usages:
|
||||
- server auth
|
||||
- client auth
|
||||
dnsNames:
|
||||
- {{ include "sim.fullname" . }}-postgresql
|
||||
- {{ include "sim.fullname" . }}-postgresql.{{ .Release.Namespace }}.svc.cluster.local
|
||||
{{- with .Values.postgresql.tls.additionalDnsNames }}
|
||||
{{- toYaml . | nindent 2 }}
|
||||
{{- end }}
|
||||
issuerRef:
|
||||
name: {{ .Values.postgresql.tls.issuerRef.name }}
|
||||
kind: {{ .Values.postgresql.tls.issuerRef.kind | default "ClusterIssuer" }}
|
||||
{{- if .Values.postgresql.tls.issuerRef.group }}
|
||||
group: {{ .Values.postgresql.tls.issuerRef.group }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,25 @@
|
||||
{{- if and .Values.branding.enabled (or .Values.branding.files .Values.branding.binaryFiles) }}
|
||||
---
|
||||
# Branding ConfigMap
|
||||
# Mounts custom branding assets (logos, CSS, etc.) into the application
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-branding
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: branding
|
||||
{{- if .Values.branding.files }}
|
||||
data:
|
||||
{{- range $key, $value := .Values.branding.files }}
|
||||
{{ $key }}: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.branding.binaryFiles }}
|
||||
binaryData:
|
||||
{{- range $key, $value := .Values.branding.binaryFiles }}
|
||||
{{ $key }}: {{ $value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,98 @@
|
||||
{{- if .Values.cronjobs.enabled }}
|
||||
{{- range $jobKey, $jobConfig := .Values.cronjobs.jobs }}
|
||||
{{- if $jobConfig.enabled }}
|
||||
---
|
||||
apiVersion: batch/v1
|
||||
kind: CronJob
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" $ }}-{{ $jobConfig.name }}
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.labels" $ | nindent 4 }}
|
||||
app.kubernetes.io/component: cronjob-{{ $jobConfig.name }}
|
||||
spec:
|
||||
schedule: {{ $jobConfig.schedule | quote }}
|
||||
concurrencyPolicy: {{ $jobConfig.concurrencyPolicy | default "Forbid" }}
|
||||
successfulJobsHistoryLimit: {{ $jobConfig.successfulJobsHistoryLimit | default 3 }}
|
||||
failedJobsHistoryLimit: {{ $jobConfig.failedJobsHistoryLimit | default 1 }}
|
||||
{{- with $.Values.cronjobs.startingDeadlineSeconds }}
|
||||
startingDeadlineSeconds: {{ . }}
|
||||
{{- end }}
|
||||
jobTemplate:
|
||||
spec:
|
||||
ttlSecondsAfterFinished: {{ $.Values.cronjobs.ttlSecondsAfterFinished | default 600 }}
|
||||
{{- with $.Values.cronjobs.activeDeadlineSeconds }}
|
||||
activeDeadlineSeconds: {{ . }}
|
||||
{{- end }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "sim.selectorLabels" $ | nindent 12 }}
|
||||
app.kubernetes.io/component: cronjob-{{ $jobConfig.name }}
|
||||
# Stable group label so NetworkPolicy can allow all cron pods → app
|
||||
# without enumerating each job's component value.
|
||||
simstudio.ai/component-group: cronjob
|
||||
spec:
|
||||
serviceAccountName: {{ include "sim.serviceAccountName" $ }}
|
||||
automountServiceAccountToken: false
|
||||
restartPolicy: {{ $.Values.cronjobs.restartPolicy | default "OnFailure" }}
|
||||
{{- include "sim.podSecurityContext" $.Values.cronjobs | nindent 10 }}
|
||||
containers:
|
||||
- name: {{ $jobConfig.name }}
|
||||
image: {{ include "sim.image" (dict "imageRoot" $.Values.cronjobs.image "global" $.Values.global "chartAppVersion" $.Chart.AppVersion) }}
|
||||
imagePullPolicy: {{ $.Values.cronjobs.image.pullPolicy }}
|
||||
{{- include "sim.containerSecurityContext" $.Values.cronjobs | nindent 12 }}
|
||||
env:
|
||||
- name: CRON_SECRET
|
||||
valueFrom:
|
||||
secretKeyRef:
|
||||
name: {{ include "sim.appSecretName" $ }}
|
||||
key: CRON_SECRET
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
args:
|
||||
- |
|
||||
echo "Starting cron job: {{ $jobConfig.name }}"
|
||||
echo "Making HTTP request to {{ $jobConfig.path }}"
|
||||
|
||||
# Determine the service URL (use internal service regardless of ingress)
|
||||
SERVICE_URL="http://{{ include "sim.fullname" $ }}-app:{{ $.Values.app.service.port }}"
|
||||
|
||||
# Make the HTTP request with timeout and retry logic
|
||||
for i in $(seq 1 3); do
|
||||
echo "Attempt $i/3"
|
||||
if curl -f -s -S --max-time 60 --retry 2 --retry-delay 5 \
|
||||
-H "Content-Type: application/json" \
|
||||
-H "User-Agent: Kubernetes-CronJob/{{ $jobConfig.name }}" \
|
||||
-H "Authorization: Bearer ${CRON_SECRET}" \
|
||||
"$SERVICE_URL{{ $jobConfig.path }}"; then
|
||||
echo "Success: HTTP request completed"
|
||||
exit 0
|
||||
fi
|
||||
echo "Attempt $i failed, retrying..."
|
||||
sleep 10
|
||||
done
|
||||
echo "Error: All attempts failed"
|
||||
exit 1
|
||||
resources:
|
||||
{{- toYaml $.Values.cronjobs.resources | nindent 14 }}
|
||||
{{- with $.Values.global.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with $.Values.app.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with $.Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with $.Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,196 @@
|
||||
{{- if .Values.app.enabled }}
|
||||
{{- include "sim.validateSecrets" . }}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-app
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.app.labels" . | nindent 4 }}
|
||||
spec:
|
||||
{{- if not .Values.autoscaling.enabled }}
|
||||
replicas: {{ .Values.app.replicaCount }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "sim.app.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/secret: {{ include (print $.Template.BasePath "/secrets-app.yaml") . | sha256sum }}
|
||||
{{- if .Values.branding.enabled }}
|
||||
checksum/config: {{ include (print $.Template.BasePath "/configmap-branding.yaml") . | sha256sum }}
|
||||
{{- end }}
|
||||
{{- with .Values.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "sim.app.selectorLabels" . | nindent 8 }}
|
||||
{{- with .Values.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.global.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "sim.serviceAccountName" . }}
|
||||
automountServiceAccountToken: false
|
||||
{{- include "sim.podSecurityContext" .Values.app | nindent 6 }}
|
||||
{{- include "sim.nodeSelector" .Values.app | nindent 6 }}
|
||||
{{- include "sim.tolerations" .Values | nindent 6 }}
|
||||
{{- include "sim.affinity" .Values | nindent 6 }}
|
||||
{{- include "sim.topologySpreadConstraints" .Values.app | nindent 6 }}
|
||||
{{- if .Values.migrations.enabled }}
|
||||
initContainers:
|
||||
- name: migrations
|
||||
image: {{ include "sim.image" (dict "imageRoot" .Values.migrations.image "global" .Values.global "chartAppVersion" .Chart.AppVersion) }}
|
||||
imagePullPolicy: {{ .Values.migrations.image.pullPolicy }}
|
||||
command: ["/bin/sh", "-c"]
|
||||
args:
|
||||
- |
|
||||
cd /app/packages/db
|
||||
export DATABASE_URL="{{ include "sim.databaseUrl" . }}"
|
||||
bun run db:migrate
|
||||
envFrom:
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
- secretRef:
|
||||
name: {{ include "sim.postgresqlSecretName" . }}
|
||||
{{- else if .Values.externalDatabase.enabled }}
|
||||
- secretRef:
|
||||
name: {{ include "sim.externalDbSecretName" . }}
|
||||
{{- end }}
|
||||
{{- include "sim.resources" .Values.migrations | nindent 10 }}
|
||||
{{- include "sim.containerSecurityContext" .Values.migrations | nindent 10 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: app
|
||||
image: {{ include "sim.image" (dict "imageRoot" .Values.app.image "global" .Values.global "chartAppVersion" .Chart.AppVersion) }}
|
||||
imagePullPolicy: {{ .Values.app.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.app.service.targetPort }}
|
||||
protocol: TCP
|
||||
{{- /*
|
||||
All keys from .Values.app.env are mounted via envFrom (see below).
|
||||
Chart-computed values and operational tunables (.Values.app.envDefaults)
|
||||
are inlined here so they don't leak into the chart-managed Secret and
|
||||
don't need to be mapped when externalSecrets.enabled=true.
|
||||
*/}}
|
||||
env:
|
||||
- name: DATABASE_URL
|
||||
value: {{ include "sim.databaseUrl" . | quote }}
|
||||
- name: SOCKET_SERVER_URL
|
||||
value: {{ include "sim.socketServerUrl" . | quote }}
|
||||
- name: OLLAMA_URL
|
||||
value: {{ include "sim.ollamaUrl" . | quote }}
|
||||
- name: PII_URL
|
||||
value: {{ include "sim.piiUrl" . | quote }}
|
||||
{{- /*
|
||||
Skip envDefaults keys that the user has explicitly overridden in app.env
|
||||
with a non-empty value. K8s `env` takes precedence over `envFrom`, so an
|
||||
inline default would otherwise mask the user's Secret-bound value.
|
||||
Also skip envDefaults entirely in existingSecret mode: the pre-existing
|
||||
Secret is the source of truth, and inlining localhost URL defaults would
|
||||
silently shadow keys (NEXT_PUBLIC_APP_URL, BETTER_AUTH_URL, etc.) the
|
||||
user stored in their Secret but left empty in app.env.
|
||||
*/}}
|
||||
{{- $appEnv := .Values.app.env | default dict }}
|
||||
{{- $useExistingSecret := and .Values.app.secrets.existingSecret.enabled (not .Values.externalSecrets.enabled) }}
|
||||
{{- if not $useExistingSecret }}
|
||||
{{- range $key, $value := .Values.app.envDefaults | default dict }}
|
||||
{{- $override := index $appEnv $key }}
|
||||
{{- if and (ne (toString $value) "") (ne (toString $value) "<nil>") (or (not $override) (eq (toString $override) "") (eq (toString $override) "<nil>")) }}
|
||||
- name: {{ $key }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- /*
|
||||
In existingSecret mode the chart-managed Secret is not rendered, so
|
||||
non-empty values in app.env would otherwise go nowhere — inline them
|
||||
here so the user's overrides actually reach the pod. Skipped in ESO
|
||||
mode (ESO is the source of truth; inlining would mask the synced value)
|
||||
and in inline mode (values flow through the chart-managed Secret).
|
||||
*/}}
|
||||
{{- if and .Values.app.secrets.existingSecret.enabled (not .Values.externalSecrets.enabled) }}
|
||||
{{- $chartComputed := list "DATABASE_URL" "SOCKET_SERVER_URL" "OLLAMA_URL" "PII_URL" }}
|
||||
{{- range $key, $value := $appEnv }}
|
||||
{{- if and (ne (toString $value) "") (ne (toString $value) "<nil>") (not (has $key $chartComputed)) }}
|
||||
- name: {{ $key }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.telemetry.enabled }}
|
||||
{{- $nodeEnv := default (default "production" (index (.Values.app.envDefaults | default dict) "NODE_ENV")) (index (.Values.app.env | default dict) "NODE_ENV") }}
|
||||
# OpenTelemetry configuration
|
||||
- name: OTEL_EXPORTER_OTLP_ENDPOINT
|
||||
value: "http://{{ include "sim.fullname" . }}-otel-collector:4318"
|
||||
- name: OTEL_SERVICE_NAME
|
||||
value: sim-app
|
||||
- name: OTEL_SERVICE_VERSION
|
||||
value: {{ .Chart.AppVersion | quote }}
|
||||
- name: OTEL_RESOURCE_ATTRIBUTES
|
||||
value: "service.name=sim-app,service.version={{ .Chart.AppVersion }},deployment.environment={{ $nodeEnv }}"
|
||||
{{- end }}
|
||||
{{- with .Values.extraEnvVars }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
envFrom:
|
||||
# App secrets (authentication, encryption keys)
|
||||
- secretRef:
|
||||
name: {{ include "sim.appSecretName" . }}
|
||||
# Database secrets
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
- secretRef:
|
||||
name: {{ include "sim.postgresqlSecretName" . }}
|
||||
{{- else if .Values.externalDatabase.enabled }}
|
||||
- secretRef:
|
||||
name: {{ include "sim.externalDbSecretName" . }}
|
||||
{{- end }}
|
||||
{{- if .Values.app.startupProbe }}
|
||||
startupProbe:
|
||||
{{- toYaml .Values.app.startupProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.app.livenessProbe }}
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.app.livenessProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.app.readinessProbe }}
|
||||
readinessProbe:
|
||||
{{- toYaml .Values.app.readinessProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- include "sim.resources" .Values.app | nindent 10 }}
|
||||
{{- include "sim.containerSecurityContext" .Values.app | nindent 10 }}
|
||||
{{- $hasBranding := and .Values.branding.enabled (or .Values.branding.files .Values.branding.binaryFiles) }}
|
||||
{{- if or $hasBranding .Values.extraVolumeMounts .Values.app.extraVolumeMounts }}
|
||||
volumeMounts:
|
||||
{{- if $hasBranding }}
|
||||
- name: branding
|
||||
mountPath: {{ .Values.branding.mountPath | default "/app/public/branding" }}
|
||||
readOnly: true
|
||||
{{- end }}
|
||||
{{- with .Values.extraVolumeMounts }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.app.extraVolumeMounts }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- $hasBranding := and .Values.branding.enabled (or .Values.branding.files .Values.branding.binaryFiles) }}
|
||||
{{- if or $hasBranding .Values.extraVolumes .Values.app.extraVolumes }}
|
||||
volumes:
|
||||
{{- if $hasBranding }}
|
||||
- name: branding
|
||||
configMap:
|
||||
name: {{ include "sim.fullname" . }}-branding
|
||||
{{- end }}
|
||||
{{- with .Values.extraVolumes }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.app.extraVolumes }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,155 @@
|
||||
{{- if .Values.copilot.enabled }}
|
||||
{{- include "sim.copilot.validate" . }}
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-copilot
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.copilot.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.copilot.server.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.copilot.server.service.port }}
|
||||
targetPort: {{ .Values.copilot.server.service.targetPort }}
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{- include "sim.copilot.selectorLabels" . | nindent 4 }}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-copilot
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.copilot.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.copilot.server.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "sim.copilot.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
{{- /*
|
||||
Hash both the inline Secret and the ExternalSecret template — whichever mode is
|
||||
active, only one renders non-empty content, but concatenating both means a mode
|
||||
switch or a remoteRefs.copilot mapping change still changes the checksum and
|
||||
forces a rollout. This can't see the live value ESO syncs from the external
|
||||
store (Helm only has the ExternalSecret manifest at render time, not the
|
||||
store's payload) — that's an inherent ESO limitation, not something a Helm
|
||||
checksum can close; ESO's own reconciliation handles picking up rotated values.
|
||||
*/}}
|
||||
checksum/secret: {{ printf "%s%s" (include (print $.Template.BasePath "/secrets-copilot.yaml") .) (include (print $.Template.BasePath "/external-secret-copilot.yaml") .) | sha256sum }}
|
||||
{{- with .Values.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "sim.copilot.selectorLabels" . | nindent 8 }}
|
||||
{{- with .Values.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.global.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "sim.serviceAccountName" . }}
|
||||
automountServiceAccountToken: false
|
||||
{{- include "sim.podSecurityContext" .Values.copilot.server | nindent 6 }}
|
||||
{{- with .Values.copilot.server.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: copilot
|
||||
image: {{ include "sim.image" (dict "imageRoot" .Values.copilot.server.image "global" .Values.global "chartAppVersion" .Chart.AppVersion) }}
|
||||
imagePullPolicy: {{ .Values.copilot.server.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.copilot.server.service.targetPort }}
|
||||
protocol: TCP
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: {{ include "sim.copilot.envSecretName" . }}
|
||||
- secretRef:
|
||||
name: {{ include "sim.copilot.databaseSecretName" . }}
|
||||
{{- with .Values.copilot.server.extraEnvFrom }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- /*
|
||||
copilot.server.env flows through envFrom (the Secret/ExternalSecret) above.
|
||||
copilot.server.envDefaults are inlined here so they don't leak into the
|
||||
chart-managed Secret and don't need to be mapped when
|
||||
externalSecrets.enabled=true — same rationale as app.envDefaults. Skipped
|
||||
entirely in existingSecret mode: the pre-created Secret is the source of
|
||||
truth, and inlining defaults would silently shadow keys (PORT, LOG_LEVEL,
|
||||
etc.) the user stored there via envFrom, since explicit env wins over
|
||||
envFrom. Keyed purely on copilot.server.secret.create, NOT the global
|
||||
externalSecrets.enabled flag — envFrom always points at the user-provided
|
||||
Secret name whenever secret.create=false, regardless of whether ESO is used
|
||||
for other components, so the global flag is irrelevant here.
|
||||
*/}}
|
||||
{{- $useExistingSecret := not .Values.copilot.server.secret.create }}
|
||||
{{- if or (not $useExistingSecret) .Values.copilot.server.extraEnv }}
|
||||
env:
|
||||
{{- $copilotEnv := .Values.copilot.server.env | default dict }}
|
||||
{{- if not $useExistingSecret }}
|
||||
{{- range $key, $value := .Values.copilot.server.envDefaults | default dict }}
|
||||
{{- $override := index $copilotEnv $key }}
|
||||
{{- if and (ne (toString $value) "") (ne (toString $value) "<nil>") (or (not $override) (eq (toString $override) "") (eq (toString $override) "<nil>")) }}
|
||||
- name: {{ $key }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Values.copilot.server.extraEnv }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if .Values.copilot.server.startupProbe }}
|
||||
startupProbe:
|
||||
{{- toYaml .Values.copilot.server.startupProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.copilot.server.livenessProbe }}
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.copilot.server.livenessProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.copilot.server.readinessProbe }}
|
||||
readinessProbe:
|
||||
{{- toYaml .Values.copilot.server.readinessProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.copilot.server.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- include "sim.containerSecurityContext" .Values.copilot.server | nindent 10 }}
|
||||
{{- if or .Values.extraVolumeMounts .Values.copilot.server.extraVolumeMounts }}
|
||||
volumeMounts:
|
||||
{{- with .Values.extraVolumeMounts }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.copilot.server.extraVolumeMounts }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if or .Values.extraVolumes .Values.copilot.server.extraVolumes }}
|
||||
volumes:
|
||||
{{- with .Values.extraVolumes }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.copilot.server.extraVolumes }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -0,0 +1,125 @@
|
||||
{{- if .Values.ollama.enabled }}
|
||||
---
|
||||
# PersistentVolumeClaim for Ollama data
|
||||
{{- if .Values.ollama.persistence.enabled }}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-ollama-data
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.ollama.labels" . | nindent 4 }}
|
||||
spec:
|
||||
{{- if .Values.ollama.persistence.storageClass }}
|
||||
{{- if (eq "-" .Values.ollama.persistence.storageClass) }}
|
||||
storageClassName: ""
|
||||
{{- else }}
|
||||
storageClassName: {{ .Values.ollama.persistence.storageClass | quote }}
|
||||
{{- end }}
|
||||
{{- else if .Values.global.storageClass }}
|
||||
storageClassName: {{ .Values.global.storageClass | quote }}
|
||||
{{- end }}
|
||||
accessModes:
|
||||
{{- range .Values.ollama.persistence.accessModes }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.ollama.persistence.size | quote }}
|
||||
{{- end }}
|
||||
|
||||
---
|
||||
# Deployment for Ollama
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-ollama
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.ollama.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.ollama.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "sim.ollama.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
{{- with .Values.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "sim.ollama.selectorLabels" . | nindent 8 }}
|
||||
{{- with .Values.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.global.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "sim.serviceAccountName" . }}
|
||||
automountServiceAccountToken: false
|
||||
{{- include "sim.podSecurityContext" .Values.ollama | nindent 6 }}
|
||||
{{- include "sim.nodeSelector" .Values.ollama | nindent 6 }}
|
||||
{{- include "sim.tolerations" .Values.ollama | nindent 6 }}
|
||||
{{- include "sim.affinity" .Values | nindent 6 }}
|
||||
containers:
|
||||
- name: ollama
|
||||
image: {{ include "sim.image" (dict "imageRoot" .Values.ollama.image "global" .Values.global "chartAppVersion" .Chart.AppVersion) }}
|
||||
imagePullPolicy: {{ .Values.ollama.image.pullPolicy }}
|
||||
command: ["ollama", "serve"]
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.ollama.service.targetPort }}
|
||||
protocol: TCP
|
||||
env:
|
||||
{{- range $key, $value := .Values.ollama.env }}
|
||||
- name: {{ $key }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- with .Values.extraEnvVars }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.ollama.startupProbe }}
|
||||
startupProbe:
|
||||
{{- toYaml .Values.ollama.startupProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.ollama.livenessProbe }}
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.ollama.livenessProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.ollama.readinessProbe }}
|
||||
readinessProbe:
|
||||
{{- toYaml .Values.ollama.readinessProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- include "sim.resources" .Values.ollama | nindent 10 }}
|
||||
{{- include "sim.containerSecurityContext" .Values.ollama | nindent 10 }}
|
||||
{{- if or .Values.ollama.persistence.enabled .Values.extraVolumeMounts .Values.ollama.extraVolumeMounts }}
|
||||
volumeMounts:
|
||||
{{- if .Values.ollama.persistence.enabled }}
|
||||
- name: ollama-data
|
||||
mountPath: /data
|
||||
{{- end }}
|
||||
{{- with .Values.extraVolumeMounts }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.ollama.extraVolumeMounts }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if or .Values.ollama.persistence.enabled .Values.extraVolumes .Values.ollama.extraVolumes }}
|
||||
volumes:
|
||||
{{- if .Values.ollama.persistence.enabled }}
|
||||
- name: ollama-data
|
||||
persistentVolumeClaim:
|
||||
claimName: {{ include "sim.fullname" . }}-ollama-data
|
||||
{{- end }}
|
||||
{{- with .Values.extraVolumes }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.ollama.extraVolumes }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,93 @@
|
||||
{{- if .Values.pii.enabled }}
|
||||
---
|
||||
# Deployment for the Presidio PII redaction service (analyzer + anonymizer combined)
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-pii
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.pii.labels" . | nindent 4 }}
|
||||
spec:
|
||||
replicas: {{ .Values.pii.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "sim.pii.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
{{- with .Values.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "sim.pii.selectorLabels" . | nindent 8 }}
|
||||
{{- with .Values.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.global.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "sim.serviceAccountName" . }}
|
||||
automountServiceAccountToken: false
|
||||
{{- include "sim.podSecurityContext" .Values.pii | nindent 6 }}
|
||||
{{- include "sim.nodeSelector" .Values.pii | nindent 6 }}
|
||||
{{- include "sim.tolerations" .Values | nindent 6 }}
|
||||
{{- include "sim.affinity" .Values | nindent 6 }}
|
||||
{{- include "sim.topologySpreadConstraints" .Values.pii | nindent 6 }}
|
||||
containers:
|
||||
- name: pii
|
||||
image: {{ include "sim.image" (dict "imageRoot" .Values.pii.image "global" .Values.global "chartAppVersion" .Chart.AppVersion) }}
|
||||
imagePullPolicy: {{ .Values.pii.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.pii.service.targetPort }}
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: PII_ENGINE
|
||||
value: {{ .Values.pii.engine | quote }}
|
||||
{{- if .Values.pii.device }}
|
||||
- name: PII_DEVICE
|
||||
value: {{ .Values.pii.device | quote }}
|
||||
{{- end }}
|
||||
{{- range $key, $value := omit (.Values.pii.env | default dict) "PII_ENGINE" "PII_DEVICE" }}
|
||||
- name: {{ $key }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- with .Values.extraEnvVars }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.pii.startupProbe }}
|
||||
startupProbe:
|
||||
{{- toYaml .Values.pii.startupProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.pii.livenessProbe }}
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.pii.livenessProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.pii.readinessProbe }}
|
||||
readinessProbe:
|
||||
{{- toYaml .Values.pii.readinessProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- include "sim.resources" .Values.pii | nindent 10 }}
|
||||
{{- include "sim.containerSecurityContext" .Values.pii | nindent 10 }}
|
||||
{{- if or .Values.extraVolumeMounts .Values.pii.extraVolumeMounts }}
|
||||
volumeMounts:
|
||||
{{- with .Values.extraVolumeMounts }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.pii.extraVolumeMounts }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if or .Values.extraVolumes .Values.pii.extraVolumes }}
|
||||
volumes:
|
||||
{{- with .Values.extraVolumes }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.pii.extraVolumes }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,176 @@
|
||||
{{- if .Values.realtime.enabled }}
|
||||
{{- include "sim.validateSecrets" . }}
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-realtime
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.realtime.labels" . | nindent 4 }}
|
||||
spec:
|
||||
{{- if not .Values.autoscaling.enabled }}
|
||||
replicas: {{ .Values.realtime.replicaCount }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "sim.realtime.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
checksum/secret: {{ include (print $.Template.BasePath "/secrets-app.yaml") . | sha256sum }}
|
||||
{{- with .Values.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "sim.realtime.selectorLabels" . | nindent 8 }}
|
||||
{{- with .Values.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.global.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "sim.serviceAccountName" . }}
|
||||
automountServiceAccountToken: false
|
||||
{{- include "sim.podSecurityContext" .Values.realtime | nindent 6 }}
|
||||
{{- include "sim.nodeSelector" .Values.realtime | nindent 6 }}
|
||||
{{- include "sim.tolerations" .Values | nindent 6 }}
|
||||
{{- include "sim.affinity" .Values | nindent 6 }}
|
||||
{{- include "sim.topologySpreadConstraints" .Values.realtime | nindent 6 }}
|
||||
containers:
|
||||
- name: realtime
|
||||
image: {{ include "sim.image" (dict "imageRoot" .Values.realtime.image "global" .Values.global "chartAppVersion" .Chart.AppVersion) }}
|
||||
imagePullPolicy: {{ .Values.realtime.image.pullPolicy }}
|
||||
ports:
|
||||
- name: http
|
||||
containerPort: {{ .Values.realtime.service.targetPort }}
|
||||
protocol: TCP
|
||||
{{- /*
|
||||
All keys from .Values.realtime.env are mounted via envFrom (see below).
|
||||
Chart-computed values and operational tunables (.Values.realtime.envDefaults)
|
||||
are inlined here so they don't leak into the chart-managed Secret and don't
|
||||
need to be mapped when externalSecrets.enabled=true.
|
||||
*/}}
|
||||
env:
|
||||
- name: DATABASE_URL
|
||||
value: {{ include "sim.databaseUrl" . | quote }}
|
||||
{{- if .Values.telemetry.enabled }}
|
||||
{{- $nodeEnv := default (default "production" (index (.Values.realtime.envDefaults | default dict) "NODE_ENV")) (index (.Values.realtime.env | default dict) "NODE_ENV") }}
|
||||
# OpenTelemetry configuration
|
||||
- name: OTEL_EXPORTER_OTLP_ENDPOINT
|
||||
value: "http://{{ include "sim.fullname" . }}-otel-collector:4318"
|
||||
- name: OTEL_SERVICE_NAME
|
||||
value: sim-realtime
|
||||
- name: OTEL_SERVICE_VERSION
|
||||
value: {{ .Chart.AppVersion | quote }}
|
||||
- name: OTEL_RESOURCE_ATTRIBUTES
|
||||
value: "service.name=sim-realtime,service.version={{ .Chart.AppVersion }},deployment.environment={{ $nodeEnv }}"
|
||||
{{- end }}
|
||||
{{- /*
|
||||
Inline realtime.envDefaults, skipping keys explicitly set in realtime.env
|
||||
OR app.env (K8s `env` overrides `envFrom`, so an inline default would
|
||||
otherwise mask a Secret-bound value). The chart-managed Secret is shared
|
||||
between app and realtime via envFrom, so a key set in app.env (e.g.
|
||||
NEXT_PUBLIC_APP_URL=https://prod.example.com) lands on the realtime pod
|
||||
too — inlining the localhost envDefault here would mask it.
|
||||
*/}}
|
||||
{{- $rtEnv := .Values.realtime.env | default dict }}
|
||||
{{- $appEnv := .Values.app.env | default dict }}
|
||||
{{- $useExistingSecret := and .Values.app.secrets.existingSecret.enabled (not .Values.externalSecrets.enabled) }}
|
||||
{{- /*
|
||||
Skip envDefaults entirely in existingSecret mode — same rationale as
|
||||
deployment-app.yaml: the pre-existing Secret is the source of truth,
|
||||
and inlining localhost defaults would shadow URL keys (BETTER_AUTH_URL,
|
||||
ALLOWED_ORIGINS, NEXT_PUBLIC_APP_URL, etc.) stored in the Secret.
|
||||
*/}}
|
||||
{{- if not $useExistingSecret }}
|
||||
{{- range $key, $value := .Values.realtime.envDefaults | default dict }}
|
||||
{{- $rtOverride := index $rtEnv $key }}
|
||||
{{- $appOverride := index $appEnv $key }}
|
||||
{{- $hasRt := and $rtOverride (ne (toString $rtOverride) "") (ne (toString $rtOverride) "<nil>") }}
|
||||
{{- $hasApp := and $appOverride (ne (toString $appOverride) "") (ne (toString $appOverride) "<nil>") }}
|
||||
{{- if and (ne (toString $value) "") (ne (toString $value) "<nil>") (not $hasRt) (not $hasApp) }}
|
||||
- name: {{ $key }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- /*
|
||||
In existingSecret mode the chart-managed Secret is not rendered, so
|
||||
non-empty values in realtime.env / app.env would otherwise go nowhere
|
||||
— inline them here so the user's overrides actually reach the pod.
|
||||
realtime.env wins over app.env on collision (realtime-specific intent).
|
||||
Skipped in ESO mode and inline mode for the same reasons as the app
|
||||
deployment.
|
||||
*/}}
|
||||
{{- if and .Values.app.secrets.existingSecret.enabled (not .Values.externalSecrets.enabled) }}
|
||||
{{- $chartComputed := list "DATABASE_URL" "SOCKET_SERVER_URL" "OLLAMA_URL" "PII_URL" }}
|
||||
{{- /*
|
||||
Build the effective realtime env from app.env as the base, then
|
||||
overlay non-empty realtime.env values. Sprig's `merge` keeps the
|
||||
first source on collision and treats "" as a real value, which
|
||||
would shadow non-empty app.env entries — so do the overlay
|
||||
manually with an explicit empty-string check.
|
||||
*/}}
|
||||
{{- $effective := deepCopy $appEnv }}
|
||||
{{- range $key, $value := $rtEnv }}
|
||||
{{- if and (ne (toString $value) "") (ne (toString $value) "<nil>") }}
|
||||
{{- $_ := set $effective $key $value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- range $key, $value := $effective }}
|
||||
{{- if and (ne (toString $value) "") (ne (toString $value) "<nil>") (not (has $key $chartComputed)) }}
|
||||
- name: {{ $key }}
|
||||
value: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- with .Values.extraEnvVars }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
envFrom:
|
||||
# App secrets (authentication keys shared with main app)
|
||||
- secretRef:
|
||||
name: {{ include "sim.appSecretName" . }}
|
||||
# Database secrets
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
- secretRef:
|
||||
name: {{ include "sim.postgresqlSecretName" . }}
|
||||
{{- else if .Values.externalDatabase.enabled }}
|
||||
- secretRef:
|
||||
name: {{ include "sim.externalDbSecretName" . }}
|
||||
{{- end }}
|
||||
{{- if .Values.realtime.startupProbe }}
|
||||
startupProbe:
|
||||
{{- toYaml .Values.realtime.startupProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.realtime.livenessProbe }}
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.realtime.livenessProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.realtime.readinessProbe }}
|
||||
readinessProbe:
|
||||
{{- toYaml .Values.realtime.readinessProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- include "sim.resources" .Values.realtime | nindent 10 }}
|
||||
{{- include "sim.containerSecurityContext" .Values.realtime | nindent 10 }}
|
||||
{{- if or .Values.extraVolumeMounts .Values.realtime.extraVolumeMounts }}
|
||||
volumeMounts:
|
||||
{{- with .Values.extraVolumeMounts }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.realtime.extraVolumeMounts }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if or .Values.extraVolumes .Values.realtime.extraVolumes }}
|
||||
volumes:
|
||||
{{- with .Values.extraVolumes }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.realtime.extraVolumes }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,14 @@
|
||||
{{- if and .Values.externalDatabase.enabled (include "sim.createExternalDbSecret" .) }}
|
||||
---
|
||||
# Secret for external database credentials
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-external-db-secret
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
data:
|
||||
EXTERNAL_DB_PASSWORD: {{ .Values.externalDatabase.password | b64enc }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,41 @@
|
||||
{{- if and .Values.externalSecrets.enabled .Values.app.enabled }}
|
||||
# ExternalSecret for app credentials (syncs from external secret managers)
|
||||
#
|
||||
# The data list is generated by iterating every non-empty entry in
|
||||
# externalSecrets.remoteRefs.app. This lets users sync arbitrary sensitive
|
||||
# keys (OPENAI_API_KEY, AWS_SECRET_ACCESS_KEY, ...) — not just the legacy
|
||||
# six (BETTER_AUTH_SECRET, ENCRYPTION_KEY, INTERNAL_API_SECRET, CRON_SECRET,
|
||||
# API_ENCRYPTION_KEY, REDIS_URL). Each entry's value may be either:
|
||||
# - a string: treated as the remoteRef.key (legacy form)
|
||||
# - a map: passed through as the remoteRef block (e.g. {key, property,
|
||||
# version, decodingStrategy, conversionStrategy, metadataPolicy})
|
||||
apiVersion: external-secrets.io/{{ .Values.externalSecrets.apiVersion | default "v1beta1" }}
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-app-secrets
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.app.labels" . | nindent 4 }}
|
||||
spec:
|
||||
refreshInterval: {{ .Values.externalSecrets.refreshInterval | quote }}
|
||||
secretStoreRef:
|
||||
name: {{ required "externalSecrets.secretStoreRef.name is required when externalSecrets.enabled=true" .Values.externalSecrets.secretStoreRef.name }}
|
||||
kind: {{ .Values.externalSecrets.secretStoreRef.kind | default "ClusterSecretStore" }}
|
||||
target:
|
||||
name: {{ include "sim.fullname" . }}-app-secrets
|
||||
creationPolicy: Owner
|
||||
data:
|
||||
{{- range $secretKey, $ref := .Values.externalSecrets.remoteRefs.app }}
|
||||
{{- if $ref }}
|
||||
{{- if kindIs "string" $ref }}
|
||||
- secretKey: {{ $secretKey }}
|
||||
remoteRef:
|
||||
key: {{ $ref }}
|
||||
{{- else if kindIs "map" $ref }}
|
||||
- secretKey: {{ $secretKey }}
|
||||
remoteRef:
|
||||
{{- toYaml $ref | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,38 @@
|
||||
{{- if and .Values.externalSecrets.enabled .Values.copilot.enabled .Values.copilot.server.secret.create }}
|
||||
# ExternalSecret for copilot server credentials (syncs from external secret managers)
|
||||
#
|
||||
# Mirrors external-secret-app.yaml: the data list is generated by iterating every
|
||||
# non-empty entry in externalSecrets.remoteRefs.copilot. sim.copilot.validate fails
|
||||
# template rendering if a required key (or any non-empty copilot.server.env key) is
|
||||
# missing a matching remoteRefs.copilot entry, so a misconfiguration surfaces at
|
||||
# `helm template` time instead of a container starting with an empty value.
|
||||
apiVersion: external-secrets.io/{{ .Values.externalSecrets.apiVersion | default "v1beta1" }}
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: {{ include "sim.copilot.envSecretName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.copilot.labels" . | nindent 4 }}
|
||||
spec:
|
||||
refreshInterval: {{ .Values.externalSecrets.refreshInterval | quote }}
|
||||
secretStoreRef:
|
||||
name: {{ required "externalSecrets.secretStoreRef.name is required when externalSecrets.enabled=true" .Values.externalSecrets.secretStoreRef.name }}
|
||||
kind: {{ .Values.externalSecrets.secretStoreRef.kind | default "ClusterSecretStore" }}
|
||||
target:
|
||||
name: {{ include "sim.copilot.envSecretName" . }}
|
||||
creationPolicy: Owner
|
||||
data:
|
||||
{{- range $secretKey, $ref := .Values.externalSecrets.remoteRefs.copilot }}
|
||||
{{- if $ref }}
|
||||
{{- if kindIs "string" $ref }}
|
||||
- secretKey: {{ $secretKey }}
|
||||
remoteRef:
|
||||
key: {{ $ref }}
|
||||
{{- else if kindIs "map" $ref }}
|
||||
- secretKey: {{ $secretKey }}
|
||||
remoteRef:
|
||||
{{- toYaml $ref | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,23 @@
|
||||
{{- if and .Values.externalSecrets.enabled .Values.externalDatabase.enabled .Values.externalSecrets.remoteRefs.externalDatabase.password }}
|
||||
# ExternalSecret for external database password (syncs from external secret managers)
|
||||
apiVersion: external-secrets.io/{{ .Values.externalSecrets.apiVersion | default "v1beta1" }}
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-external-db-secret
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: external-database
|
||||
spec:
|
||||
refreshInterval: {{ .Values.externalSecrets.refreshInterval | quote }}
|
||||
secretStoreRef:
|
||||
name: {{ required "externalSecrets.secretStoreRef.name is required when externalSecrets.enabled=true" .Values.externalSecrets.secretStoreRef.name }}
|
||||
kind: {{ .Values.externalSecrets.secretStoreRef.kind | default "ClusterSecretStore" }}
|
||||
target:
|
||||
name: {{ include "sim.fullname" . }}-external-db-secret
|
||||
creationPolicy: Owner
|
||||
data:
|
||||
- secretKey: EXTERNAL_DB_PASSWORD
|
||||
remoteRef:
|
||||
key: {{ .Values.externalSecrets.remoteRefs.externalDatabase.password }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,22 @@
|
||||
{{- if and .Values.externalSecrets.enabled .Values.postgresql.enabled .Values.externalSecrets.remoteRefs.postgresql.password }}
|
||||
# ExternalSecret for PostgreSQL password (syncs from external secret managers)
|
||||
apiVersion: external-secrets.io/{{ .Values.externalSecrets.apiVersion | default "v1beta1" }}
|
||||
kind: ExternalSecret
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-postgresql-secret
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.postgresql.labels" . | nindent 4 }}
|
||||
spec:
|
||||
refreshInterval: {{ .Values.externalSecrets.refreshInterval | quote }}
|
||||
secretStoreRef:
|
||||
name: {{ required "externalSecrets.secretStoreRef.name is required when externalSecrets.enabled=true" .Values.externalSecrets.secretStoreRef.name }}
|
||||
kind: {{ .Values.externalSecrets.secretStoreRef.kind | default "ClusterSecretStore" }}
|
||||
target:
|
||||
name: {{ include "sim.fullname" . }}-postgresql-secret
|
||||
creationPolicy: Owner
|
||||
data:
|
||||
- secretKey: POSTGRES_PASSWORD
|
||||
remoteRef:
|
||||
key: {{ .Values.externalSecrets.remoteRefs.postgresql.password }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,115 @@
|
||||
{{- if and .Values.ollama.enabled .Values.ollama.gpu.enabled }}
|
||||
---
|
||||
# 1. ConfigMap for NVIDIA Device Plugin Configuration
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-nvidia-device-plugin-config
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: nvidia-device-plugin
|
||||
data:
|
||||
config.yaml: |
|
||||
version: v1
|
||||
flags:
|
||||
{{- if eq .Values.ollama.gpu.strategy "mig" }}
|
||||
migStrategy: "single"
|
||||
{{- else }}
|
||||
migStrategy: "none"
|
||||
{{- end }}
|
||||
failOnInitError: false
|
||||
plugin:
|
||||
passDeviceSpecs: true
|
||||
deviceListStrategy: envvar
|
||||
{{- if eq .Values.ollama.gpu.strategy "time-slicing" }}
|
||||
sharing:
|
||||
timeSlicing:
|
||||
resources:
|
||||
- name: nvidia.com/gpu
|
||||
replicas: {{ .Values.ollama.gpu.timeSlicingReplicas | default 5 }}
|
||||
{{- end }}
|
||||
---
|
||||
# 2. NVIDIA Device Plugin DaemonSet for GPU support
|
||||
apiVersion: apps/v1
|
||||
kind: DaemonSet
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-nvidia-device-plugin
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: nvidia-device-plugin
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "sim.selectorLabels" . | nindent 6 }}
|
||||
app.kubernetes.io/component: nvidia-device-plugin
|
||||
updateStrategy:
|
||||
type: RollingUpdate
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "sim.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: nvidia-device-plugin
|
||||
spec:
|
||||
tolerations:
|
||||
# Allow scheduling on GPU nodes
|
||||
- key: nvidia.com/gpu
|
||||
operator: Exists
|
||||
effect: NoSchedule
|
||||
- key: sku
|
||||
operator: Equal
|
||||
value: gpu
|
||||
effect: NoSchedule
|
||||
nodeSelector:
|
||||
# Only schedule on nodes with NVIDIA GPUs
|
||||
accelerator: nvidia
|
||||
priorityClassName: system-node-critical
|
||||
volumes:
|
||||
- name: device-plugin
|
||||
hostPath:
|
||||
path: /var/lib/kubelet/device-plugins
|
||||
- name: dev
|
||||
hostPath:
|
||||
path: /dev
|
||||
- name: sys
|
||||
hostPath:
|
||||
path: /sys
|
||||
# Volume to mount the ConfigMap
|
||||
- name: nvidia-device-plugin-config
|
||||
configMap:
|
||||
name: {{ include "sim.fullname" . }}-nvidia-device-plugin-config
|
||||
containers:
|
||||
- name: nvidia-device-plugin
|
||||
image: nvcr.io/nvidia/k8s-device-plugin:v0.18.2
|
||||
imagePullPolicy: Always
|
||||
args:
|
||||
- "--config-file=/etc/device-plugin/config.yaml"
|
||||
{{- if eq .Values.ollama.gpu.strategy "mig" }}
|
||||
env:
|
||||
- name: NVIDIA_MIG_MONITOR_DEVICES
|
||||
value: all
|
||||
{{- end }}
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
capabilities:
|
||||
drop: ["ALL"]
|
||||
volumeMounts:
|
||||
- name: device-plugin
|
||||
mountPath: /var/lib/kubelet/device-plugins
|
||||
- name: dev
|
||||
mountPath: /dev
|
||||
- name: sys
|
||||
mountPath: /sys
|
||||
readOnly: true
|
||||
- name: nvidia-device-plugin-config
|
||||
mountPath: /etc/device-plugin/
|
||||
readOnly: true
|
||||
resources:
|
||||
requests:
|
||||
cpu: 50m
|
||||
memory: 20Mi
|
||||
limits:
|
||||
cpu: 50m
|
||||
memory: 50Mi
|
||||
{{- end }}
|
||||
@@ -0,0 +1,85 @@
|
||||
{{- if .Values.autoscaling.enabled }}
|
||||
---
|
||||
# HorizontalPodAutoscaler for main application
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-app
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.app.labels" . | nindent 4 }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{ include "sim.fullname" . }}-app
|
||||
minReplicas: {{ .Values.autoscaling.minReplicas }}
|
||||
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
|
||||
metrics:
|
||||
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- with .Values.autoscaling.customMetrics }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if .Values.autoscaling.behavior }}
|
||||
behavior:
|
||||
{{- toYaml .Values.autoscaling.behavior | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- if and .Values.autoscaling.enabled .Values.realtime.enabled }}
|
||||
---
|
||||
# HorizontalPodAutoscaler for realtime service
|
||||
apiVersion: autoscaling/v2
|
||||
kind: HorizontalPodAutoscaler
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-realtime
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.realtime.labels" . | nindent 4 }}
|
||||
spec:
|
||||
scaleTargetRef:
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
name: {{ include "sim.fullname" . }}-realtime
|
||||
minReplicas: {{ .Values.autoscaling.minReplicas }}
|
||||
maxReplicas: {{ .Values.autoscaling.maxReplicas }}
|
||||
metrics:
|
||||
{{- if .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: cpu
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.autoscaling.targetCPUUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- if .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
- type: Resource
|
||||
resource:
|
||||
name: memory
|
||||
target:
|
||||
type: Utilization
|
||||
averageUtilization: {{ .Values.autoscaling.targetMemoryUtilizationPercentage }}
|
||||
{{- end }}
|
||||
{{- with .Values.autoscaling.customMetrics }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- if .Values.autoscaling.behavior }}
|
||||
behavior:
|
||||
{{- toYaml .Values.autoscaling.behavior | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,129 @@
|
||||
{{- if .Values.ingressInternal.enabled }}
|
||||
{{- $appActive := .Values.app.enabled -}}
|
||||
{{- $realtimeActive := .Values.realtime.enabled -}}
|
||||
{{- $hasCopilotIngress := and .Values.copilot.enabled .Values.ingressInternal.copilot -}}
|
||||
{{- $realtimeHasOwnRule := and $realtimeActive (or (not $appActive) (ne .Values.ingressInternal.realtime.host .Values.ingressInternal.app.host)) -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-ingress-internal
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.labels" . | nindent 4 }}
|
||||
{{- with .Values.ingressInternal.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingressInternal.className }}
|
||||
ingressClassName: {{ .Values.ingressInternal.className }}
|
||||
{{- end }}
|
||||
{{- if .Values.ingressInternal.tls.enabled }}
|
||||
tls:
|
||||
- hosts:
|
||||
{{- if $appActive }}
|
||||
- {{ .Values.ingressInternal.app.host | quote }}
|
||||
{{- end }}
|
||||
{{- if $realtimeHasOwnRule }}
|
||||
- {{ .Values.ingressInternal.realtime.host | quote }}
|
||||
{{- end }}
|
||||
{{- if $hasCopilotIngress }}
|
||||
{{- $copilotHostCovered := false }}
|
||||
{{- if and $appActive (eq .Values.ingressInternal.copilot.host .Values.ingressInternal.app.host) }}
|
||||
{{- $copilotHostCovered = true }}
|
||||
{{- end }}
|
||||
{{- if and $realtimeHasOwnRule (eq .Values.ingressInternal.copilot.host .Values.ingressInternal.realtime.host) }}
|
||||
{{- $copilotHostCovered = true }}
|
||||
{{- end }}
|
||||
{{- if not $copilotHostCovered }}
|
||||
- {{ .Values.ingressInternal.copilot.host | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
secretName: {{ .Values.ingressInternal.tls.secretName }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- if $appActive }}
|
||||
- host: {{ .Values.ingressInternal.app.host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- if and $realtimeActive (eq .Values.ingressInternal.realtime.host .Values.ingressInternal.app.host) }}
|
||||
{{- range .Values.ingressInternal.realtime.paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "sim.fullname" $ }}-realtime
|
||||
port:
|
||||
number: {{ $.Values.realtime.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if and $hasCopilotIngress (eq .Values.ingressInternal.copilot.host .Values.ingressInternal.app.host) }}
|
||||
{{- range .Values.ingressInternal.copilot.paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "sim.fullname" $ }}-copilot
|
||||
port:
|
||||
number: {{ $.Values.copilot.server.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- range .Values.ingressInternal.app.paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "sim.fullname" $ }}-app
|
||||
port:
|
||||
number: {{ $.Values.app.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if $realtimeHasOwnRule }}
|
||||
- host: {{ .Values.ingressInternal.realtime.host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .Values.ingressInternal.realtime.paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "sim.fullname" $ }}-realtime
|
||||
port:
|
||||
number: {{ $.Values.realtime.service.port }}
|
||||
{{- end }}
|
||||
{{- if and $hasCopilotIngress (eq .Values.ingressInternal.copilot.host .Values.ingressInternal.realtime.host) }}
|
||||
{{- range .Values.ingressInternal.copilot.paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "sim.fullname" $ }}-copilot
|
||||
port:
|
||||
number: {{ $.Values.copilot.server.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if $hasCopilotIngress }}
|
||||
{{- $copilotServed := false }}
|
||||
{{- if and $appActive (eq .Values.ingressInternal.copilot.host .Values.ingressInternal.app.host) }}
|
||||
{{- $copilotServed = true }}
|
||||
{{- end }}
|
||||
{{- if and $realtimeHasOwnRule (eq .Values.ingressInternal.copilot.host .Values.ingressInternal.realtime.host) }}
|
||||
{{- $copilotServed = true }}
|
||||
{{- end }}
|
||||
{{- if not $copilotServed }}
|
||||
- host: {{ .Values.ingressInternal.copilot.host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .Values.ingressInternal.copilot.paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "sim.fullname" $ }}-copilot
|
||||
port:
|
||||
number: {{ $.Values.copilot.server.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,129 @@
|
||||
{{- if .Values.ingress.enabled }}
|
||||
{{- $appActive := .Values.app.enabled -}}
|
||||
{{- $realtimeActive := .Values.realtime.enabled -}}
|
||||
{{- $hasCopilotIngress := and .Values.copilot.enabled .Values.ingress.copilot -}}
|
||||
{{- $realtimeHasOwnRule := and $realtimeActive (or (not $appActive) (ne .Values.ingress.realtime.host .Values.ingress.app.host)) -}}
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: Ingress
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-ingress
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.labels" . | nindent 4 }}
|
||||
{{- with .Values.ingress.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .Values.ingress.className }}
|
||||
ingressClassName: {{ .Values.ingress.className }}
|
||||
{{- end }}
|
||||
{{- if .Values.ingress.tls.enabled }}
|
||||
tls:
|
||||
- hosts:
|
||||
{{- if $appActive }}
|
||||
- {{ .Values.ingress.app.host | quote }}
|
||||
{{- end }}
|
||||
{{- if $realtimeHasOwnRule }}
|
||||
- {{ .Values.ingress.realtime.host | quote }}
|
||||
{{- end }}
|
||||
{{- if $hasCopilotIngress }}
|
||||
{{- $copilotHostCovered := false }}
|
||||
{{- if and $appActive (eq .Values.ingress.copilot.host .Values.ingress.app.host) }}
|
||||
{{- $copilotHostCovered = true }}
|
||||
{{- end }}
|
||||
{{- if and $realtimeHasOwnRule (eq .Values.ingress.copilot.host .Values.ingress.realtime.host) }}
|
||||
{{- $copilotHostCovered = true }}
|
||||
{{- end }}
|
||||
{{- if not $copilotHostCovered }}
|
||||
- {{ .Values.ingress.copilot.host | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
secretName: {{ .Values.ingress.tls.secretName }}
|
||||
{{- end }}
|
||||
rules:
|
||||
{{- if $appActive }}
|
||||
- host: {{ .Values.ingress.app.host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- if and $realtimeActive (eq .Values.ingress.realtime.host .Values.ingress.app.host) }}
|
||||
{{- range .Values.ingress.realtime.paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "sim.fullname" $ }}-realtime
|
||||
port:
|
||||
number: {{ $.Values.realtime.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if and $hasCopilotIngress (eq .Values.ingress.copilot.host .Values.ingress.app.host) }}
|
||||
{{- range .Values.ingress.copilot.paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "sim.fullname" $ }}-copilot
|
||||
port:
|
||||
number: {{ $.Values.copilot.server.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- range .Values.ingress.app.paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "sim.fullname" $ }}-app
|
||||
port:
|
||||
number: {{ $.Values.app.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if $realtimeHasOwnRule }}
|
||||
- host: {{ .Values.ingress.realtime.host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .Values.ingress.realtime.paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "sim.fullname" $ }}-realtime
|
||||
port:
|
||||
number: {{ $.Values.realtime.service.port }}
|
||||
{{- end }}
|
||||
{{- if and $hasCopilotIngress (eq .Values.ingress.copilot.host .Values.ingress.realtime.host) }}
|
||||
{{- range .Values.ingress.copilot.paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "sim.fullname" $ }}-copilot
|
||||
port:
|
||||
number: {{ $.Values.copilot.server.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if $hasCopilotIngress }}
|
||||
{{- $copilotServed := false }}
|
||||
{{- if and $appActive (eq .Values.ingress.copilot.host .Values.ingress.app.host) }}
|
||||
{{- $copilotServed = true }}
|
||||
{{- end }}
|
||||
{{- if and $realtimeHasOwnRule (eq .Values.ingress.copilot.host .Values.ingress.realtime.host) }}
|
||||
{{- $copilotServed = true }}
|
||||
{{- end }}
|
||||
{{- if not $copilotServed }}
|
||||
- host: {{ .Values.ingress.copilot.host | quote }}
|
||||
http:
|
||||
paths:
|
||||
{{- range .Values.ingress.copilot.paths }}
|
||||
- path: {{ .path }}
|
||||
pathType: {{ .pathType }}
|
||||
backend:
|
||||
service:
|
||||
name: {{ include "sim.fullname" $ }}-copilot
|
||||
port:
|
||||
number: {{ $.Values.copilot.server.service.port }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,76 @@
|
||||
{{- if and .Values.copilot.enabled .Values.copilot.migrations.enabled }}
|
||||
apiVersion: batch/v1
|
||||
kind: Job
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-copilot-migrations
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: copilot-migrations
|
||||
annotations:
|
||||
"helm.sh/hook": post-install,post-upgrade
|
||||
"helm.sh/hook-weight": "-5"
|
||||
"helm.sh/hook-delete-policy": before-hook-creation
|
||||
spec:
|
||||
backoffLimit: {{ .Values.copilot.migrations.backoffLimit }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
app.kubernetes.io/name: {{ include "sim.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: copilot-migrations
|
||||
spec:
|
||||
{{- with .Values.global.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "sim.serviceAccountName" . }}
|
||||
automountServiceAccountToken: false
|
||||
restartPolicy: {{ .Values.copilot.migrations.restartPolicy }}
|
||||
{{- include "sim.podSecurityContext" .Values.copilot.migrations | nindent 6 }}
|
||||
{{- with .Values.copilot.server.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.copilot.postgresql.enabled }}
|
||||
initContainers:
|
||||
- name: wait-for-postgres
|
||||
image: {{ include "sim.image" (dict "imageRoot" .Values.copilot.postgresql.image "global" .Values.global "chartAppVersion" .Chart.AppVersion) }}
|
||||
command:
|
||||
- /bin/sh
|
||||
- -c
|
||||
- |
|
||||
until pg_isready -h {{ include "sim.fullname" . }}-copilot-postgresql -p {{ .Values.copilot.postgresql.service.port }} -U {{ .Values.copilot.postgresql.auth.username }}; do
|
||||
echo "Waiting for Copilot PostgreSQL to be ready..."
|
||||
sleep 2
|
||||
done
|
||||
echo "Copilot PostgreSQL is ready!"
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: {{ include "sim.fullname" . }}-copilot-postgresql-secret
|
||||
{{- include "sim.containerSecurityContext" .Values.copilot.migrations | nindent 10 }}
|
||||
{{- end }}
|
||||
containers:
|
||||
- name: migrations
|
||||
image: {{ include "sim.image" (dict "imageRoot" .Values.copilot.migrations.image "global" .Values.global "chartAppVersion" .Chart.AppVersion) }}
|
||||
imagePullPolicy: {{ .Values.copilot.migrations.image.pullPolicy }}
|
||||
command: ["/usr/local/bin/migrate"]
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: {{ include "sim.copilot.envSecretName" . }}
|
||||
- secretRef:
|
||||
name: {{ include "sim.copilot.databaseSecretName" . }}
|
||||
{{- with .Values.copilot.server.extraEnvFrom }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.copilot.server.extraEnv }}
|
||||
env:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.copilot.migrations.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- include "sim.containerSecurityContext" .Values.copilot.migrations | nindent 10 }}
|
||||
{{- end }}
|
||||
|
||||
@@ -0,0 +1,437 @@
|
||||
{{- if .Values.networkPolicy.enabled }}
|
||||
---
|
||||
# Network Policy for main application
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-app
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.app.labels" . | nindent 4 }}
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.app.selectorLabels" . | nindent 6 }}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
# Allow ingress from realtime service
|
||||
{{- if .Values.realtime.enabled }}
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.realtime.selectorLabels" . | nindent 10 }}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.app.service.targetPort }}
|
||||
{{- end }}
|
||||
# Allow ingress from cron pods (every cron job curls /api/schedules/execute,
|
||||
# webhook polls, etc. against the app service)
|
||||
{{- if .Values.cronjobs.enabled }}
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.selectorLabels" . | nindent 10 }}
|
||||
simstudio.ai/component-group: cronjob
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.app.service.targetPort }}
|
||||
{{- end }}
|
||||
# Allow ingress from ingress controller (configurable peers; defaults to any)
|
||||
{{- if .Values.ingress.enabled }}
|
||||
- from:
|
||||
{{- toYaml (default (list (dict)) .Values.networkPolicy.ingressFrom) | nindent 6 }}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.app.service.targetPort }}
|
||||
{{- end }}
|
||||
# Allow custom ingress rules
|
||||
{{- with .Values.networkPolicy.ingress }}
|
||||
{{- toYaml . | nindent 2 }}
|
||||
{{- end }}
|
||||
egress:
|
||||
# Allow egress to PostgreSQL
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.postgresql.selectorLabels" . | nindent 10 }}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.postgresql.service.targetPort }}
|
||||
{{- end }}
|
||||
# Allow egress to realtime service
|
||||
{{- if .Values.realtime.enabled }}
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.realtime.selectorLabels" . | nindent 10 }}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.realtime.service.targetPort }}
|
||||
{{- end }}
|
||||
# Allow egress to Ollama
|
||||
{{- if .Values.ollama.enabled }}
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.ollama.selectorLabels" . | nindent 10 }}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.ollama.service.targetPort }}
|
||||
{{- end }}
|
||||
# Allow egress to the PII (Presidio) service
|
||||
{{- if .Values.pii.enabled }}
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.pii.selectorLabels" . | nindent 10 }}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.pii.service.targetPort }}
|
||||
{{- end }}
|
||||
# Allow egress to OpenTelemetry collector (OTLP gRPC + HTTP)
|
||||
{{- if .Values.telemetry.enabled }}
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "sim.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: telemetry
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 4317
|
||||
- protocol: TCP
|
||||
port: 4318
|
||||
{{- end }}
|
||||
# Allow DNS resolution
|
||||
- to: []
|
||||
ports:
|
||||
- protocol: UDP
|
||||
port: 53
|
||||
- protocol: TCP
|
||||
port: 53
|
||||
# Allow HTTPS egress for external APIs (excludes cloud metadata endpoints)
|
||||
- to:
|
||||
- ipBlock:
|
||||
cidr: 0.0.0.0/0
|
||||
except:
|
||||
{{- range (default (list "169.254.169.254/32" "169.254.170.2/32") .Values.networkPolicy.egressExceptCidrs) }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 443
|
||||
# Allow custom egress rules
|
||||
{{- with .Values.networkPolicy.egress }}
|
||||
{{- toYaml . | nindent 2 }}
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.realtime.enabled }}
|
||||
---
|
||||
# Network Policy for realtime service
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-realtime
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.realtime.labels" . | nindent 4 }}
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.realtime.selectorLabels" . | nindent 6 }}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
# Allow ingress from main application
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.app.selectorLabels" . | nindent 10 }}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.realtime.service.targetPort }}
|
||||
# Allow ingress from ingress controller (configurable peers; defaults to any)
|
||||
{{- if .Values.ingress.enabled }}
|
||||
- from:
|
||||
{{- toYaml (default (list (dict)) .Values.networkPolicy.ingressFrom) | nindent 6 }}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.realtime.service.targetPort }}
|
||||
{{- end }}
|
||||
egress:
|
||||
# Allow egress to PostgreSQL
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.postgresql.selectorLabels" . | nindent 10 }}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.postgresql.service.targetPort }}
|
||||
{{- end }}
|
||||
# Allow egress to OpenTelemetry collector (OTLP gRPC + HTTP)
|
||||
{{- if .Values.telemetry.enabled }}
|
||||
- to:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
app.kubernetes.io/name: {{ include "sim.name" . }}
|
||||
app.kubernetes.io/instance: {{ .Release.Name }}
|
||||
app.kubernetes.io/component: telemetry
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 4317
|
||||
- protocol: TCP
|
||||
port: 4318
|
||||
{{- end }}
|
||||
# Allow DNS resolution
|
||||
- to: []
|
||||
ports:
|
||||
- protocol: UDP
|
||||
port: 53
|
||||
- protocol: TCP
|
||||
port: 53
|
||||
# Allow HTTPS egress for external APIs (excludes cloud metadata endpoints)
|
||||
- to:
|
||||
- ipBlock:
|
||||
cidr: 0.0.0.0/0
|
||||
except:
|
||||
{{- range (default (list "169.254.169.254/32" "169.254.170.2/32") .Values.networkPolicy.egressExceptCidrs) }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 443
|
||||
# Allow custom egress rules
|
||||
{{- with .Values.networkPolicy.egress }}
|
||||
{{- toYaml . | nindent 2 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
---
|
||||
# Network Policy for PostgreSQL
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-postgresql
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.postgresql.labels" . | nindent 4 }}
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.postgresql.selectorLabels" . | nindent 6 }}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
# Allow ingress from main application
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.app.selectorLabels" . | nindent 10 }}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.postgresql.service.targetPort }}
|
||||
# Allow ingress from realtime service
|
||||
{{- if .Values.realtime.enabled }}
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.realtime.selectorLabels" . | nindent 10 }}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.postgresql.service.targetPort }}
|
||||
{{- end }}
|
||||
# Allow ingress from migrations job
|
||||
{{- if .Values.migrations.enabled }}
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.migrations.labels" . | nindent 10 }}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.postgresql.service.targetPort }}
|
||||
{{- end }}
|
||||
egress:
|
||||
# Allow minimal egress (for health checks, etc.)
|
||||
- to: []
|
||||
ports:
|
||||
- protocol: UDP
|
||||
port: 53
|
||||
- protocol: TCP
|
||||
port: 53
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.ollama.enabled }}
|
||||
---
|
||||
# Network Policy for Ollama
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-ollama
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.ollama.labels" . | nindent 4 }}
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.ollama.selectorLabels" . | nindent 6 }}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
# Allow ingress from main application
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.app.selectorLabels" . | nindent 10 }}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.ollama.service.targetPort }}
|
||||
egress:
|
||||
# Allow DNS resolution
|
||||
- to: []
|
||||
ports:
|
||||
- protocol: UDP
|
||||
port: 53
|
||||
- protocol: TCP
|
||||
port: 53
|
||||
# Allow HTTPS egress for model downloads (excludes cloud metadata endpoints)
|
||||
- to:
|
||||
- ipBlock:
|
||||
cidr: 0.0.0.0/0
|
||||
except:
|
||||
{{- range (default (list "169.254.169.254/32" "169.254.170.2/32") .Values.networkPolicy.egressExceptCidrs) }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 443
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.pii.enabled }}
|
||||
---
|
||||
# Network Policy for the PII (Presidio) service
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-pii
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.pii.labels" . | nindent 4 }}
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.pii.selectorLabels" . | nindent 6 }}
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
# Allow ingress from main application
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.app.selectorLabels" . | nindent 10 }}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: {{ .Values.pii.service.targetPort }}
|
||||
egress:
|
||||
# Allow DNS resolution. Models are baked into the image, so no external egress.
|
||||
- to: []
|
||||
ports:
|
||||
- protocol: UDP
|
||||
port: 53
|
||||
- protocol: TCP
|
||||
port: 53
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.telemetry.enabled }}
|
||||
---
|
||||
# Network Policy for OpenTelemetry Collector
|
||||
apiVersion: networking.k8s.io/v1
|
||||
kind: NetworkPolicy
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-otel-collector
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: telemetry
|
||||
spec:
|
||||
podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.selectorLabels" . | nindent 6 }}
|
||||
app.kubernetes.io/component: telemetry
|
||||
policyTypes:
|
||||
- Ingress
|
||||
- Egress
|
||||
ingress:
|
||||
# OTLP from app
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.app.selectorLabels" . | nindent 10 }}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 4317
|
||||
- protocol: TCP
|
||||
port: 4318
|
||||
# OTLP from realtime
|
||||
{{- if .Values.realtime.enabled }}
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.realtime.selectorLabels" . | nindent 10 }}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 4317
|
||||
- protocol: TCP
|
||||
port: 4318
|
||||
{{- end }}
|
||||
# OTLP from copilot
|
||||
{{- if .Values.copilot.enabled }}
|
||||
- from:
|
||||
- podSelector:
|
||||
matchLabels:
|
||||
{{- include "sim.selectorLabels" . | nindent 10 }}
|
||||
app.kubernetes.io/component: copilot
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 4317
|
||||
- protocol: TCP
|
||||
port: 4318
|
||||
{{- end }}
|
||||
egress:
|
||||
# DNS
|
||||
- to: []
|
||||
ports:
|
||||
- protocol: UDP
|
||||
port: 53
|
||||
- protocol: TCP
|
||||
port: 53
|
||||
# HTTPS for forwarding to external observability backends (Datadog, Honeycomb, etc.)
|
||||
- to:
|
||||
- ipBlock:
|
||||
cidr: 0.0.0.0/0
|
||||
except:
|
||||
{{- range (default (list "169.254.169.254/32" "169.254.170.2/32") .Values.networkPolicy.egressExceptCidrs) }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
ports:
|
||||
- protocol: TCP
|
||||
port: 443
|
||||
{{- end }}
|
||||
|
||||
{{- /*
|
||||
Copilot + copilot-postgresql intentionally do NOT ship dedicated NetworkPolicies.
|
||||
Copilot requires REDIS_URL (external Redis on a non-443 port), and the chart
|
||||
cannot know the user's Redis host/port at render time — a default egress rule
|
||||
would silently block Redis on most installs. Users running networkPolicy.enabled=true
|
||||
with copilot enabled should add their own NPs (or extend networkPolicy.egress
|
||||
with the appropriate egress rules).
|
||||
*/}}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,94 @@
|
||||
{{- /*
|
||||
Tri-state activation for the app PDB:
|
||||
- enabled: true → force on
|
||||
- enabled: false → force off (explicit opt-out, even on HA)
|
||||
- enabled: null → auto-enable when the workload is HA — either a static
|
||||
replicaCount > 1, or HPA enabled with minReplicas > 1
|
||||
(HPA owns spec.replicas so replicaCount alone is not
|
||||
authoritative under autoscaling).
|
||||
*/ -}}
|
||||
{{- $pdbEnabled := .Values.podDisruptionBudget.enabled -}}
|
||||
{{- $hpaMin := 0 -}}
|
||||
{{- if .Values.autoscaling.enabled -}}
|
||||
{{- $hpaMin = int (default 1 .Values.autoscaling.minReplicas) -}}
|
||||
{{- end -}}
|
||||
{{- $pdbAuto := and (kindIs "invalid" $pdbEnabled) (or (gt (int .Values.app.replicaCount) 1) (gt $hpaMin 1)) -}}
|
||||
{{- if and .Values.app.enabled (or (eq $pdbEnabled true) $pdbAuto) }}
|
||||
{{- with .Values.podDisruptionBudget }}
|
||||
---
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" $ }}-app-pdb
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.app.labels" $ | nindent 4 }}
|
||||
spec:
|
||||
{{- if .minAvailable }}
|
||||
minAvailable: {{ .minAvailable }}
|
||||
{{- else if .maxUnavailable }}
|
||||
maxUnavailable: {{ .maxUnavailable }}
|
||||
{{- else }}
|
||||
minAvailable: 1
|
||||
{{- end }}
|
||||
{{- if .unhealthyPodEvictionPolicy }}
|
||||
unhealthyPodEvictionPolicy: {{ .unhealthyPodEvictionPolicy }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "sim.app.selectorLabels" $ | nindent 6 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- $rtPdbAuto := and (kindIs "invalid" .Values.podDisruptionBudget.enabled) (or (gt (int .Values.realtime.replicaCount) 1) (gt $hpaMin 1)) -}}
|
||||
{{- if and .Values.realtime.enabled (or (eq .Values.podDisruptionBudget.enabled true) $rtPdbAuto) }}
|
||||
{{- with .Values.podDisruptionBudget }}
|
||||
---
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" $ }}-realtime-pdb
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.realtime.labels" $ | nindent 4 }}
|
||||
spec:
|
||||
{{- if .minAvailable }}
|
||||
minAvailable: {{ .minAvailable }}
|
||||
{{- else if .maxUnavailable }}
|
||||
maxUnavailable: {{ .maxUnavailable }}
|
||||
{{- else }}
|
||||
minAvailable: 1
|
||||
{{- end }}
|
||||
{{- if .unhealthyPodEvictionPolicy }}
|
||||
unhealthyPodEvictionPolicy: {{ .unhealthyPodEvictionPolicy }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "sim.realtime.selectorLabels" $ | nindent 6 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if and .Values.copilot.enabled .Values.copilot.server.podDisruptionBudget.enabled }}
|
||||
{{- with .Values.copilot.server.podDisruptionBudget }}
|
||||
---
|
||||
apiVersion: policy/v1
|
||||
kind: PodDisruptionBudget
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" $ }}-copilot-pdb
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.copilot.labels" $ | nindent 4 }}
|
||||
spec:
|
||||
{{- if .minAvailable }}
|
||||
minAvailable: {{ .minAvailable }}
|
||||
{{- else if .maxUnavailable }}
|
||||
maxUnavailable: {{ .maxUnavailable }}
|
||||
{{- else }}
|
||||
maxUnavailable: 1
|
||||
{{- end }}
|
||||
{{- if .unhealthyPodEvictionPolicy }}
|
||||
unhealthyPodEvictionPolicy: {{ .unhealthyPodEvictionPolicy }}
|
||||
{{- end }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "sim.copilot.selectorLabels" $ | nindent 6 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,51 @@
|
||||
{{- if and .Values.app.enabled (include "sim.createAppSecrets" .) }}
|
||||
{{/*
|
||||
Secret for app + realtime env. Every key in .Values.app.env and
|
||||
.Values.realtime.env is written here and mounted via envFrom on the
|
||||
respective Deployments. Chart-computed values (DATABASE_URL,
|
||||
SOCKET_SERVER_URL, OLLAMA_URL, PII_URL) are omitted — they're injected as
|
||||
inline env on the container so they reflect chart-time resolution.
|
||||
|
||||
Treating all env values as secret-grade avoids maintaining a sensitivity
|
||||
classifier and prevents accidental leaks when new provider keys are added.
|
||||
*/}}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-app-secrets
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.app.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
{{- $chartComputed := list "DATABASE_URL" "SOCKET_SERVER_URL" "OLLAMA_URL" "PII_URL" }}
|
||||
{{- /*
|
||||
Intent: app.env is authoritative for shared keys (both pods envFrom this
|
||||
Secret, so the app container must not be silently overwritten by a
|
||||
realtime-side value), BUT empty strings must never win.
|
||||
|
||||
Sprig `merge` treats "" as a real value, so a default-empty app.env entry
|
||||
would shadow a non-empty realtime.env entry. Build the effective dict
|
||||
manually: start from realtime.env, then overlay non-empty app.env values
|
||||
on top — this gives app.env-wins-on-collision without empty-string
|
||||
shadowing. Mirrors the pattern used in deployment-realtime.yaml.
|
||||
*/}}
|
||||
{{- $appEnv := .Values.app.env | default dict }}
|
||||
{{- $rtEnv := .Values.realtime.env | default dict }}
|
||||
{{- $effective := dict }}
|
||||
{{- range $key, $value := $rtEnv }}
|
||||
{{- if and (ne (toString $value) "") (ne (toString $value) "<nil>") }}
|
||||
{{- $_ := set $effective $key $value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- range $key, $value := $appEnv }}
|
||||
{{- if and (ne (toString $value) "") (ne (toString $value) "<nil>") }}
|
||||
{{- $_ := set $effective $key $value }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- range $key, $value := $effective }}
|
||||
{{- if not (has $key $chartComputed) }}
|
||||
{{ $key }}: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,35 @@
|
||||
{{- if and .Values.copilot.enabled .Values.copilot.server.secret.create (not (and .Values.externalSecrets .Values.externalSecrets.enabled)) }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "sim.copilot.envSecretName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.copilot.labels" . | nindent 4 }}
|
||||
{{- with .Values.copilot.server.secret.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
{{- range $key, $value := .Values.copilot.server.env }}
|
||||
{{ $key }}: {{ $value | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- if and .Values.copilot.enabled (not .Values.copilot.postgresql.enabled) (or (not .Values.copilot.database.existingSecretName) (eq .Values.copilot.database.existingSecretName "")) (ne .Values.copilot.database.url "") }}
|
||||
---
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "sim.copilot.databaseSecretName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.copilot.labels" . | nindent 4 }}
|
||||
{{- with .Values.copilot.server.secret.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
{{ include "sim.copilot.databaseSecretKey" . }}: {{ required "copilot.database.url is required when using an external database" .Values.copilot.database.url | quote }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,14 @@
|
||||
{{- if .Values.serviceAccount.create -}}
|
||||
apiVersion: v1
|
||||
kind: ServiceAccount
|
||||
metadata:
|
||||
name: {{ include "sim.serviceAccountName" . }}
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.labels" . | nindent 4 }}
|
||||
{{- with .Values.serviceAccount.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
automountServiceAccountToken: false
|
||||
{{- end }}
|
||||
@@ -0,0 +1,79 @@
|
||||
{{- if .Values.monitoring.serviceMonitor.enabled }}
|
||||
---
|
||||
# ServiceMonitor for main application
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-app
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.app.labels" . | nindent 4 }}
|
||||
{{- with .Values.monitoring.serviceMonitor.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- with .Values.monitoring.serviceMonitor.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "sim.app.selectorLabels" . | nindent 6 }}
|
||||
endpoints:
|
||||
- port: http
|
||||
path: {{ .Values.monitoring.serviceMonitor.path }}
|
||||
interval: {{ .Values.monitoring.serviceMonitor.interval }}
|
||||
scrapeTimeout: {{ .Values.monitoring.serviceMonitor.scrapeTimeout }}
|
||||
{{- with .Values.monitoring.serviceMonitor.metricRelabelings }}
|
||||
metricRelabelings:
|
||||
{{- toYaml . | nindent 6 }}
|
||||
{{- end }}
|
||||
{{- with .Values.monitoring.serviceMonitor.relabelings }}
|
||||
relabelings:
|
||||
{{- toYaml . | nindent 6 }}
|
||||
{{- end }}
|
||||
{{- if .Values.monitoring.serviceMonitor.targetLabels }}
|
||||
targetLabels:
|
||||
{{- toYaml .Values.monitoring.serviceMonitor.targetLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
{{- if and .Values.monitoring.serviceMonitor.enabled .Values.realtime.enabled }}
|
||||
---
|
||||
# ServiceMonitor for realtime service
|
||||
apiVersion: monitoring.coreos.com/v1
|
||||
kind: ServiceMonitor
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-realtime
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.realtime.labels" . | nindent 4 }}
|
||||
{{- with .Values.monitoring.serviceMonitor.labels }}
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- with .Values.monitoring.serviceMonitor.annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "sim.realtime.selectorLabels" . | nindent 6 }}
|
||||
endpoints:
|
||||
- port: http
|
||||
path: {{ .Values.monitoring.serviceMonitor.path }}
|
||||
interval: {{ .Values.monitoring.serviceMonitor.interval }}
|
||||
scrapeTimeout: {{ .Values.monitoring.serviceMonitor.scrapeTimeout }}
|
||||
{{- with .Values.monitoring.serviceMonitor.metricRelabelings }}
|
||||
metricRelabelings:
|
||||
{{- toYaml . | nindent 6 }}
|
||||
{{- end }}
|
||||
{{- with .Values.monitoring.serviceMonitor.relabelings }}
|
||||
relabelings:
|
||||
{{- toYaml . | nindent 6 }}
|
||||
{{- end }}
|
||||
{{- if .Values.monitoring.serviceMonitor.targetLabels }}
|
||||
targetLabels:
|
||||
{{- toYaml .Values.monitoring.serviceMonitor.targetLabels | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,123 @@
|
||||
{{- if .Values.app.enabled }}
|
||||
---
|
||||
# Service for main application
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-app
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.app.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.app.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.app.service.port }}
|
||||
targetPort: {{ .Values.app.service.targetPort }}
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{- include "sim.app.selectorLabels" . | nindent 4 }}
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.realtime.enabled }}
|
||||
---
|
||||
# Service for realtime server
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-realtime
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.realtime.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.realtime.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.realtime.service.port }}
|
||||
targetPort: {{ .Values.realtime.service.targetPort }}
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{- include "sim.realtime.selectorLabels" . | nindent 4 }}
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
---
|
||||
# Service for PostgreSQL (ClusterIP — used by client workloads)
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-postgresql
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.postgresql.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.postgresql.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.postgresql.service.port }}
|
||||
targetPort: {{ .Values.postgresql.service.targetPort }}
|
||||
protocol: TCP
|
||||
name: postgresql
|
||||
selector:
|
||||
{{- include "sim.postgresql.selectorLabels" . | nindent 4 }}
|
||||
---
|
||||
# Headless Service for PostgreSQL StatefulSet (stable per-pod DNS)
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-postgresql-headless
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.postgresql.labels" . | nindent 4 }}
|
||||
spec:
|
||||
clusterIP: None
|
||||
publishNotReadyAddresses: true
|
||||
ports:
|
||||
- port: {{ .Values.postgresql.service.port }}
|
||||
targetPort: {{ .Values.postgresql.service.targetPort }}
|
||||
protocol: TCP
|
||||
name: postgresql
|
||||
selector:
|
||||
{{- include "sim.postgresql.selectorLabels" . | nindent 4 }}
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.ollama.enabled }}
|
||||
---
|
||||
# Service for Ollama
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-ollama
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.ollama.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.ollama.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.ollama.service.port }}
|
||||
targetPort: {{ .Values.ollama.service.targetPort }}
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{- include "sim.ollama.selectorLabels" . | nindent 4 }}
|
||||
{{- end }}
|
||||
|
||||
{{- if .Values.pii.enabled }}
|
||||
---
|
||||
# Service fronting the Presidio PII redaction deployment
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-pii
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.pii.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.pii.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.pii.service.port }}
|
||||
targetPort: {{ .Values.pii.service.targetPort }}
|
||||
protocol: TCP
|
||||
name: http
|
||||
selector:
|
||||
{{- include "sim.pii.selectorLabels" . | nindent 4 }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,48 @@
|
||||
{{- if .Values.sharedStorage.enabled }}
|
||||
{{- range .Values.sharedStorage.volumes }}
|
||||
---
|
||||
# Shared Storage PVC for {{ .name }}
|
||||
apiVersion: v1
|
||||
kind: PersistentVolumeClaim
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" $ }}-{{ .name }}
|
||||
namespace: {{ $.Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.labels" $ | nindent 4 }}
|
||||
sim.ai/volume-type: shared-storage
|
||||
sim.ai/volume-name: {{ .name }}
|
||||
{{- with .annotations }}
|
||||
annotations:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- if .storageClass }}
|
||||
{{- if (eq "-" .storageClass) }}
|
||||
storageClassName: ""
|
||||
{{- else }}
|
||||
storageClassName: {{ .storageClass | quote }}
|
||||
{{- end }}
|
||||
{{- else if $.Values.sharedStorage.storageClass }}
|
||||
storageClassName: {{ $.Values.sharedStorage.storageClass | quote }}
|
||||
{{- else if $.Values.global.storageClass }}
|
||||
storageClassName: {{ $.Values.global.storageClass | quote }}
|
||||
{{- end }}
|
||||
accessModes:
|
||||
{{- if .accessModes }}
|
||||
{{- range .accessModes }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
{{- else }}
|
||||
{{- range $.Values.sharedStorage.defaultAccessModes }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .size | quote }}
|
||||
{{- if .selector }}
|
||||
selector:
|
||||
{{- toYaml .selector | nindent 4 }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,154 @@
|
||||
{{- if and .Values.copilot.enabled .Values.copilot.postgresql.enabled }}
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-copilot-postgresql-secret
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.copilotPostgresql.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
stringData:
|
||||
POSTGRES_USER: {{ .Values.copilot.postgresql.auth.username | quote }}
|
||||
POSTGRES_PASSWORD: {{ required "copilot.postgresql.auth.password is required when copilot is enabled" .Values.copilot.postgresql.auth.password | quote }}
|
||||
POSTGRES_DB: {{ .Values.copilot.postgresql.auth.database | quote }}
|
||||
DATABASE_URL: "postgresql://{{ .Values.copilot.postgresql.auth.username }}:{{ .Values.copilot.postgresql.auth.password }}@{{ include "sim.fullname" . }}-copilot-postgresql:{{ .Values.copilot.postgresql.service.port }}/{{ .Values.copilot.postgresql.auth.database }}"
|
||||
---
|
||||
# ClusterIP Service used by client workloads
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-copilot-postgresql
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.copilotPostgresql.labels" . | nindent 4 }}
|
||||
spec:
|
||||
type: {{ .Values.copilot.postgresql.service.type }}
|
||||
ports:
|
||||
- port: {{ .Values.copilot.postgresql.service.port }}
|
||||
targetPort: {{ .Values.copilot.postgresql.service.targetPort }}
|
||||
protocol: TCP
|
||||
name: postgresql
|
||||
selector:
|
||||
{{- include "sim.copilotPostgresql.selectorLabels" . | nindent 4 }}
|
||||
---
|
||||
# Headless Service for the StatefulSet (stable per-pod DNS)
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-copilot-postgresql-headless
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.copilotPostgresql.labels" . | nindent 4 }}
|
||||
spec:
|
||||
clusterIP: None
|
||||
publishNotReadyAddresses: true
|
||||
ports:
|
||||
- port: {{ .Values.copilot.postgresql.service.port }}
|
||||
targetPort: {{ .Values.copilot.postgresql.service.targetPort }}
|
||||
protocol: TCP
|
||||
name: postgresql
|
||||
selector:
|
||||
{{- include "sim.copilotPostgresql.selectorLabels" . | nindent 4 }}
|
||||
---
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-copilot-postgresql
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.copilotPostgresql.labels" . | nindent 4 }}
|
||||
spec:
|
||||
# Must remain {{ include "sim.fullname" . }}-copilot-postgresql (not the
|
||||
# -headless name) — spec.serviceName is immutable on a StatefulSet, and
|
||||
# the prior chart shipped with this value. Same rationale as the main
|
||||
# postgresql STS; see statefulset-postgresql.yaml for details.
|
||||
serviceName: {{ include "sim.fullname" . }}-copilot-postgresql
|
||||
replicas: 1
|
||||
podManagementPolicy: OrderedReady
|
||||
updateStrategy:
|
||||
type: RollingUpdate
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "sim.copilotPostgresql.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "sim.copilotPostgresql.selectorLabels" . | nindent 8 }}
|
||||
{{- with .Values.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.global.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "sim.serviceAccountName" . }}
|
||||
automountServiceAccountToken: false
|
||||
{{- with .Values.copilot.postgresql.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- include "sim.podSecurityContext" .Values.copilot.postgresql | nindent 6 }}
|
||||
containers:
|
||||
- name: postgresql
|
||||
image: {{ include "sim.image" (dict "imageRoot" .Values.copilot.postgresql.image "global" .Values.global "chartAppVersion" .Chart.AppVersion) }}
|
||||
imagePullPolicy: {{ .Values.copilot.postgresql.image.pullPolicy }}
|
||||
ports:
|
||||
- name: postgresql
|
||||
containerPort: {{ .Values.copilot.postgresql.service.targetPort }}
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: PGDATA
|
||||
value: /var/lib/postgresql/data/pgdata
|
||||
envFrom:
|
||||
- secretRef:
|
||||
name: {{ include "sim.fullname" . }}-copilot-postgresql-secret
|
||||
{{- if .Values.copilot.postgresql.startupProbe }}
|
||||
startupProbe:
|
||||
{{- toYaml .Values.copilot.postgresql.startupProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.copilot.postgresql.livenessProbe }}
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.copilot.postgresql.livenessProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.copilot.postgresql.readinessProbe }}
|
||||
readinessProbe:
|
||||
{{- toYaml .Values.copilot.postgresql.readinessProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- with .Values.copilot.postgresql.resources }}
|
||||
resources:
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- include "sim.containerSecurityContext" .Values.copilot.postgresql | nindent 10 }}
|
||||
{{- if .Values.copilot.postgresql.persistence.enabled }}
|
||||
volumeMounts:
|
||||
- name: data
|
||||
mountPath: /var/lib/postgresql/data
|
||||
subPath: pgdata
|
||||
{{- end }}
|
||||
{{- if .Values.copilot.postgresql.persistence.enabled }}
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: data
|
||||
labels:
|
||||
{{- include "sim.copilotPostgresql.labels" . | nindent 10 }}
|
||||
spec:
|
||||
accessModes:
|
||||
{{- range .Values.copilot.postgresql.persistence.accessModes }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.copilot.postgresql.persistence.storageClass }}
|
||||
{{- if (eq "-" .Values.copilot.postgresql.persistence.storageClass) }}
|
||||
storageClassName: ""
|
||||
{{- else }}
|
||||
storageClassName: {{ .Values.copilot.postgresql.persistence.storageClass | quote }}
|
||||
{{- end }}
|
||||
{{- else if .Values.global.storageClass }}
|
||||
storageClassName: {{ .Values.global.storageClass | quote }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.copilot.postgresql.persistence.size | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
|
||||
@@ -0,0 +1,210 @@
|
||||
{{- if .Values.postgresql.enabled }}
|
||||
---
|
||||
# ConfigMap for PostgreSQL configuration
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-postgresql-config
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.postgresql.labels" . | nindent 4 }}
|
||||
data:
|
||||
postgresql.conf: |
|
||||
hba_file = '/etc/postgresql/pg_hba.conf'
|
||||
listen_addresses = '0.0.0.0'
|
||||
max_connections = {{ .Values.postgresql.config.maxConnections }}
|
||||
tcp_keepalives_idle = 60
|
||||
tcp_keepalives_interval = 5
|
||||
tcp_keepalives_count = 3
|
||||
authentication_timeout = 1min
|
||||
password_encryption = scram-sha-256
|
||||
{{- if .Values.postgresql.tls.enabled }}
|
||||
ssl = on
|
||||
ssl_cert_file = '/etc/postgresql/tls/tls.crt'
|
||||
ssl_key_file = '/etc/postgresql/tls/tls.key'
|
||||
{{- else }}
|
||||
ssl = off
|
||||
{{- end }}
|
||||
shared_buffers = {{ .Values.postgresql.config.sharedBuffers }}
|
||||
dynamic_shared_memory_type = posix
|
||||
max_wal_size = {{ .Values.postgresql.config.maxWalSize }}
|
||||
min_wal_size = {{ .Values.postgresql.config.minWalSize }}
|
||||
log_timezone = 'Etc/UTC'
|
||||
idle_in_transaction_session_timeout = 50000000
|
||||
datestyle = 'iso, mdy'
|
||||
timezone = 'Etc/UTC'
|
||||
lc_messages = 'en_US.utf8'
|
||||
lc_monetary = 'en_US.utf8'
|
||||
lc_numeric = 'en_US.utf8'
|
||||
lc_time = 'en_US.utf8'
|
||||
default_text_search_config = 'pg_catalog.english'
|
||||
|
||||
pg_hba.conf: |
|
||||
# Secure authentication for all connections
|
||||
local all all scram-sha-256
|
||||
host all all 127.0.0.1/32 scram-sha-256
|
||||
host all all ::1/128 scram-sha-256
|
||||
host all all all scram-sha-256
|
||||
|
||||
# Replication connections also require authentication
|
||||
local replication all scram-sha-256
|
||||
host replication all 127.0.0.1/32 scram-sha-256
|
||||
host replication all ::1/128 scram-sha-256
|
||||
|
||||
---
|
||||
# ConfigMap for PostgreSQL environment variables
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-postgresql-env
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.postgresql.labels" . | nindent 4 }}
|
||||
data:
|
||||
POSTGRES_DB: {{ .Values.postgresql.auth.database | quote }}
|
||||
POSTGRES_USER: {{ .Values.postgresql.auth.username | quote }}
|
||||
PGDATA: "/var/lib/postgresql/data/pgdata"
|
||||
|
||||
{{- if (include "sim.createPostgresqlSecret" .) }}
|
||||
---
|
||||
# Secret for PostgreSQL password
|
||||
apiVersion: v1
|
||||
kind: Secret
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-postgresql-secret
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.postgresql.labels" . | nindent 4 }}
|
||||
type: Opaque
|
||||
data:
|
||||
POSTGRES_PASSWORD: {{ .Values.postgresql.auth.password | b64enc }}
|
||||
{{- end }}
|
||||
|
||||
---
|
||||
# StatefulSet for PostgreSQL
|
||||
apiVersion: apps/v1
|
||||
kind: StatefulSet
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-postgresql
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.postgresql.labels" . | nindent 4 }}
|
||||
spec:
|
||||
# Must remain {{ include "sim.fullname" . }}-postgresql (not the -headless
|
||||
# name) — spec.serviceName is immutable on a StatefulSet, and the prior
|
||||
# chart shipped with this value. Changing it would break `helm upgrade` for
|
||||
# every existing install with `Forbidden: updates to statefulset spec ...`.
|
||||
# The headless Service in services.yaml is added alongside, not as a swap.
|
||||
serviceName: {{ include "sim.fullname" . }}-postgresql
|
||||
replicas: 1
|
||||
minReadySeconds: 10
|
||||
podManagementPolicy: OrderedReady
|
||||
updateStrategy:
|
||||
type: RollingUpdate
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "sim.postgresql.selectorLabels" . | nindent 6 }}
|
||||
template:
|
||||
metadata:
|
||||
annotations:
|
||||
{{- with .Values.podAnnotations }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
labels:
|
||||
{{- include "sim.postgresql.selectorLabels" . | nindent 8 }}
|
||||
{{- with .Values.podLabels }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
spec:
|
||||
{{- with .Values.global.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "sim.serviceAccountName" . }}
|
||||
automountServiceAccountToken: false
|
||||
{{- include "sim.podSecurityContext" .Values.postgresql | nindent 6 }}
|
||||
{{- include "sim.nodeSelector" .Values.postgresql | nindent 6 }}
|
||||
{{- include "sim.tolerations" .Values | nindent 6 }}
|
||||
{{- include "sim.affinity" .Values | nindent 6 }}
|
||||
containers:
|
||||
- name: postgresql
|
||||
image: {{ include "sim.image" (dict "imageRoot" .Values.postgresql.image "global" .Values.global "chartAppVersion" .Chart.AppVersion) }}
|
||||
imagePullPolicy: {{ .Values.postgresql.image.pullPolicy }}
|
||||
args: ["-c", "config_file=/etc/postgresql/postgresql.conf"]
|
||||
ports:
|
||||
- name: postgresql
|
||||
containerPort: {{ .Values.postgresql.service.targetPort }}
|
||||
protocol: TCP
|
||||
envFrom:
|
||||
- configMapRef:
|
||||
name: {{ include "sim.fullname" . }}-postgresql-env
|
||||
- secretRef:
|
||||
name: {{ include "sim.postgresqlSecretName" . }}
|
||||
{{- if .Values.postgresql.startupProbe }}
|
||||
startupProbe:
|
||||
{{- toYaml .Values.postgresql.startupProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.postgresql.livenessProbe }}
|
||||
livenessProbe:
|
||||
{{- toYaml .Values.postgresql.livenessProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- if .Values.postgresql.readinessProbe }}
|
||||
readinessProbe:
|
||||
{{- toYaml .Values.postgresql.readinessProbe | nindent 12 }}
|
||||
{{- end }}
|
||||
{{- include "sim.resources" .Values.postgresql | nindent 10 }}
|
||||
{{- include "sim.containerSecurityContext" .Values.postgresql | nindent 10 }}
|
||||
volumeMounts:
|
||||
{{- if .Values.postgresql.persistence.enabled }}
|
||||
- name: postgresql-data
|
||||
mountPath: /var/lib/postgresql/data
|
||||
subPath: pgdata
|
||||
{{- end }}
|
||||
- name: postgresql-config
|
||||
mountPath: "/etc/postgresql"
|
||||
{{- if .Values.postgresql.tls.enabled }}
|
||||
- name: postgresql-tls
|
||||
mountPath: "/etc/postgresql/tls"
|
||||
readOnly: true
|
||||
{{- end }}
|
||||
{{- with .Values.extraVolumeMounts }}
|
||||
{{- toYaml . | nindent 12 }}
|
||||
{{- end }}
|
||||
volumes:
|
||||
- name: postgresql-config
|
||||
configMap:
|
||||
name: {{ include "sim.fullname" . }}-postgresql-config
|
||||
{{- if .Values.postgresql.tls.enabled }}
|
||||
- name: postgresql-tls
|
||||
secret:
|
||||
secretName: {{ .Values.postgresql.tls.certificatesSecret }}
|
||||
defaultMode: 0600
|
||||
{{- end }}
|
||||
{{- with .Values.extraVolumes }}
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- if .Values.postgresql.persistence.enabled }}
|
||||
volumeClaimTemplates:
|
||||
- metadata:
|
||||
name: postgresql-data
|
||||
labels:
|
||||
{{- include "sim.postgresql.labels" . | nindent 10 }}
|
||||
spec:
|
||||
{{- if .Values.postgresql.persistence.storageClass }}
|
||||
{{- if (eq "-" .Values.postgresql.persistence.storageClass) }}
|
||||
storageClassName: ""
|
||||
{{- else }}
|
||||
storageClassName: {{ .Values.postgresql.persistence.storageClass | quote }}
|
||||
{{- end }}
|
||||
{{- else if .Values.global.storageClass }}
|
||||
storageClassName: {{ .Values.global.storageClass | quote }}
|
||||
{{- end }}
|
||||
accessModes:
|
||||
{{- range .Values.postgresql.persistence.accessModes }}
|
||||
- {{ . | quote }}
|
||||
{{- end }}
|
||||
resources:
|
||||
requests:
|
||||
storage: {{ .Values.postgresql.persistence.size | quote }}
|
||||
{{- end }}
|
||||
{{- end }}
|
||||
@@ -0,0 +1,223 @@
|
||||
{{- if .Values.telemetry.enabled }}
|
||||
---
|
||||
# OpenTelemetry Collector Configuration
|
||||
apiVersion: v1
|
||||
kind: ConfigMap
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-otel-config
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: telemetry
|
||||
data:
|
||||
otel-config.yaml: |
|
||||
receivers:
|
||||
otlp:
|
||||
protocols:
|
||||
grpc:
|
||||
endpoint: 0.0.0.0:4317
|
||||
http:
|
||||
endpoint: 0.0.0.0:4318
|
||||
prometheus:
|
||||
config:
|
||||
scrape_configs:
|
||||
- job_name: 'sim-app'
|
||||
static_configs:
|
||||
- targets: ['{{ include "sim.fullname" . }}-app:{{ .Values.app.service.port }}']
|
||||
- job_name: 'sim-realtime'
|
||||
static_configs:
|
||||
- targets: ['{{ include "sim.fullname" . }}-realtime:{{ .Values.realtime.service.port }}']
|
||||
|
||||
processors:
|
||||
batch:
|
||||
timeout: 1s
|
||||
send_batch_size: 1024
|
||||
memory_limiter:
|
||||
limit_mib: 512
|
||||
|
||||
exporters:
|
||||
{{- if .Values.telemetry.jaeger.enabled }}
|
||||
jaeger:
|
||||
endpoint: {{ .Values.telemetry.jaeger.endpoint }}
|
||||
tls:
|
||||
insecure: {{ not .Values.telemetry.jaeger.tls.enabled }}
|
||||
{{- end }}
|
||||
{{- if .Values.telemetry.prometheus.enabled }}
|
||||
prometheusremotewrite:
|
||||
endpoint: {{ .Values.telemetry.prometheus.endpoint }}
|
||||
headers:
|
||||
Authorization: {{ .Values.telemetry.prometheus.auth | quote }}
|
||||
{{- end }}
|
||||
{{- if .Values.telemetry.otlp.enabled }}
|
||||
otlp:
|
||||
endpoint: {{ .Values.telemetry.otlp.endpoint }}
|
||||
tls:
|
||||
insecure: {{ not .Values.telemetry.otlp.tls.enabled }}
|
||||
{{- end }}
|
||||
logging:
|
||||
loglevel: info
|
||||
|
||||
extensions:
|
||||
health_check:
|
||||
endpoint: 0.0.0.0:13133
|
||||
pprof:
|
||||
endpoint: 0.0.0.0:1777
|
||||
zpages:
|
||||
endpoint: 0.0.0.0:55679
|
||||
|
||||
service:
|
||||
extensions: [health_check, pprof, zpages]
|
||||
pipelines:
|
||||
traces:
|
||||
receivers: [otlp]
|
||||
processors: [memory_limiter, batch]
|
||||
exporters:
|
||||
- logging
|
||||
{{- if .Values.telemetry.jaeger.enabled }}
|
||||
- jaeger
|
||||
{{- end }}
|
||||
{{- if .Values.telemetry.otlp.enabled }}
|
||||
- otlp
|
||||
{{- end }}
|
||||
metrics:
|
||||
receivers: [otlp, prometheus]
|
||||
processors: [memory_limiter, batch]
|
||||
exporters:
|
||||
- logging
|
||||
{{- if .Values.telemetry.prometheus.enabled }}
|
||||
- prometheusremotewrite
|
||||
{{- end }}
|
||||
{{- if .Values.telemetry.otlp.enabled }}
|
||||
- otlp
|
||||
{{- end }}
|
||||
logs:
|
||||
receivers: [otlp]
|
||||
processors: [memory_limiter, batch]
|
||||
exporters:
|
||||
- logging
|
||||
{{- if .Values.telemetry.otlp.enabled }}
|
||||
- otlp
|
||||
{{- end }}
|
||||
---
|
||||
# OpenTelemetry Collector Deployment
|
||||
apiVersion: apps/v1
|
||||
kind: Deployment
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-otel-collector
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: telemetry
|
||||
spec:
|
||||
replicas: {{ .Values.telemetry.replicaCount }}
|
||||
selector:
|
||||
matchLabels:
|
||||
{{- include "sim.selectorLabels" . | nindent 6 }}
|
||||
app.kubernetes.io/component: telemetry
|
||||
template:
|
||||
metadata:
|
||||
labels:
|
||||
{{- include "sim.selectorLabels" . | nindent 8 }}
|
||||
app.kubernetes.io/component: telemetry
|
||||
spec:
|
||||
{{- with .Values.global.imagePullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
serviceAccountName: {{ include "sim.serviceAccountName" . }}
|
||||
automountServiceAccountToken: false
|
||||
{{- include "sim.podSecurityContext" .Values.telemetry | nindent 6 }}
|
||||
containers:
|
||||
- name: otel-collector
|
||||
image: {{ include "sim.image" (dict "imageRoot" .Values.telemetry.image "global" .Values.global "chartAppVersion" .Chart.AppVersion) }}
|
||||
imagePullPolicy: {{ .Values.telemetry.image.pullPolicy }}
|
||||
command:
|
||||
- /otelcol-contrib
|
||||
- --config=/etc/otel-collector-config/otel-config.yaml
|
||||
ports:
|
||||
- name: otlp-grpc
|
||||
containerPort: 4317
|
||||
protocol: TCP
|
||||
- name: otlp-http
|
||||
containerPort: 4318
|
||||
protocol: TCP
|
||||
- name: health
|
||||
containerPort: 13133
|
||||
protocol: TCP
|
||||
- name: pprof
|
||||
containerPort: 1777
|
||||
protocol: TCP
|
||||
- name: zpages
|
||||
containerPort: 55679
|
||||
protocol: TCP
|
||||
env:
|
||||
- name: GOGC
|
||||
value: "80"
|
||||
volumeMounts:
|
||||
- name: otel-config
|
||||
mountPath: /etc/otel-collector-config
|
||||
readOnly: true
|
||||
livenessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: health
|
||||
initialDelaySeconds: 10
|
||||
periodSeconds: 30
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
readinessProbe:
|
||||
httpGet:
|
||||
path: /
|
||||
port: health
|
||||
initialDelaySeconds: 5
|
||||
periodSeconds: 10
|
||||
timeoutSeconds: 5
|
||||
failureThreshold: 3
|
||||
resources:
|
||||
{{- toYaml .Values.telemetry.resources | nindent 12 }}
|
||||
{{- include "sim.containerSecurityContext" .Values.telemetry | nindent 10 }}
|
||||
volumes:
|
||||
- name: otel-config
|
||||
configMap:
|
||||
name: {{ include "sim.fullname" . }}-otel-config
|
||||
{{- with .Values.telemetry.nodeSelector }}
|
||||
nodeSelector:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.telemetry.tolerations }}
|
||||
tolerations:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
{{- with .Values.telemetry.affinity }}
|
||||
affinity:
|
||||
{{- toYaml . | nindent 8 }}
|
||||
{{- end }}
|
||||
---
|
||||
# OpenTelemetry Collector Service
|
||||
apiVersion: v1
|
||||
kind: Service
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-otel-collector
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: telemetry
|
||||
spec:
|
||||
type: {{ .Values.telemetry.service.type }}
|
||||
ports:
|
||||
- name: otlp-grpc
|
||||
port: 4317
|
||||
targetPort: otlp-grpc
|
||||
protocol: TCP
|
||||
- name: otlp-http
|
||||
port: 4318
|
||||
targetPort: otlp-http
|
||||
protocol: TCP
|
||||
- name: health
|
||||
port: 13133
|
||||
targetPort: health
|
||||
protocol: TCP
|
||||
selector:
|
||||
{{- include "sim.selectorLabels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: telemetry
|
||||
{{- end }}
|
||||
@@ -0,0 +1,54 @@
|
||||
{{- if .Values.tests.enabled }}
|
||||
apiVersion: v1
|
||||
kind: Pod
|
||||
metadata:
|
||||
name: {{ include "sim.fullname" . }}-test-connection
|
||||
namespace: {{ .Release.Namespace }}
|
||||
labels:
|
||||
{{- include "sim.labels" . | nindent 4 }}
|
||||
app.kubernetes.io/component: test
|
||||
annotations:
|
||||
"helm.sh/hook": test
|
||||
"helm.sh/hook-delete-policy": before-hook-creation,hook-succeeded
|
||||
spec:
|
||||
restartPolicy: Never
|
||||
{{- with .Values.tests.image.pullSecrets }}
|
||||
imagePullSecrets:
|
||||
{{- toYaml . | nindent 4 }}
|
||||
{{- end }}
|
||||
securityContext:
|
||||
runAsNonRoot: true
|
||||
runAsUser: 65534
|
||||
runAsGroup: 65534
|
||||
fsGroup: 65534
|
||||
seccompProfile:
|
||||
type: RuntimeDefault
|
||||
containers:
|
||||
- name: probe
|
||||
image: "{{ .Values.tests.image.repository }}:{{ .Values.tests.image.tag }}"
|
||||
imagePullPolicy: {{ .Values.tests.image.pullPolicy }}
|
||||
securityContext:
|
||||
allowPrivilegeEscalation: false
|
||||
readOnlyRootFilesystem: true
|
||||
runAsNonRoot: true
|
||||
runAsUser: 65534
|
||||
capabilities:
|
||||
drop:
|
||||
- ALL
|
||||
command:
|
||||
- sh
|
||||
- -c
|
||||
- |
|
||||
set -eu
|
||||
APP_URL="http://{{ include "sim.fullname" . }}-app:{{ .Values.app.service.port }}/"
|
||||
echo "Probing $APP_URL"
|
||||
wget -q -T {{ .Values.tests.timeoutSeconds }} --tries=1 --spider "$APP_URL"
|
||||
{{- if .Values.realtime.enabled }}
|
||||
RT_URL="http://{{ include "sim.fullname" . }}-realtime:{{ .Values.realtime.service.port }}/health"
|
||||
echo "Probing $RT_URL"
|
||||
wget -q -T {{ .Values.tests.timeoutSeconds }} --tries=1 --spider "$RT_URL"
|
||||
{{- end }}
|
||||
echo "OK"
|
||||
resources:
|
||||
{{- toYaml .Values.tests.resources | nindent 8 }}
|
||||
{{- end }}
|
||||
Reference in New Issue
Block a user