diff --git a/Charts/tiled/templates/_helpers.tpl b/Charts/tiled/templates/_helpers.tpl index b3ee1b7..3188c93 100644 --- a/Charts/tiled/templates/_helpers.tpl +++ b/Charts/tiled/templates/_helpers.tpl @@ -72,3 +72,20 @@ Fails rather than truncates, so two beamlines can never collide on one name. {{- end }} {{- $name }} {{- end }} + +{{/* +libpq-style connection env for the bundled postgres, used by the init container +and the tiled config, e.g. postgresql://$PGUSER:$PGPASSWORD@$PGHOST/$PGDATABASE +*/}} +{{- define "tiled.postgresqlEnv" -}} +- name: PGHOST + value: {{ include "tiled.fullname" . }}-postgresql +- name: PGUSER + value: {{ .Values.postgresql.user | quote }} +- name: PGDATABASE + value: {{ .Values.postgresql.database | quote }} +- name: PGPASSWORD + valueFrom: + secretKeyRef: + {{- toYaml .Values.postgresql.passwordSecret | nindent 6 }} +{{- end }} diff --git a/Charts/tiled/templates/deployment.yaml b/Charts/tiled/templates/deployment.yaml index 82ce563..d5e37a8 100644 --- a/Charts/tiled/templates/deployment.yaml +++ b/Charts/tiled/templates/deployment.yaml @@ -39,6 +39,23 @@ spec: {{- $beamlineSC := .securityContext | default dict }} securityContext: {{- toYaml (merge (pick $beamlineSC "supplementalGroups") $.Values.podSecurityContext) | nindent 8 }} + {{- if $.Values.postgresql.enabled }} + # All beamlines share one catalog database, which postgres creates on + # first start. Make its tables, retrying until postgres is up and if + # another beamline's pod is doing the same. A no-op once done. + initContainers: + - name: init-catalog + image: "{{ $.Values.image.repository }}:{{ $.Values.image.tag | default $.Chart.AppVersion }}" + imagePullPolicy: {{ $.Values.image.pullPolicy }} + securityContext: + {{- toYaml (merge (omit $beamlineSC "supplementalGroups") $.Values.securityContext) | nindent 12 }} + command: + - sh + - -c + - until tiled catalog init --if-not-exists "postgresql://$PGUSER:$PGPASSWORD@$PGHOST/$PGDATABASE"; do sleep 2; done + env: + {{- include "tiled.postgresqlEnv" $ | nindent 12 }} + {{- end }} containers: - name: {{ $.Chart.Name }} securityContext: @@ -67,9 +84,15 @@ spec: volumeMounts: {{- toYaml . | nindent 12 }} {{- end }} - {{- with concat $.Values.extraEnvVars (.extraEnvVars | default list) }} + {{- $env := concat $.Values.extraEnvVars (.extraEnvVars | default list) }} + {{- if or $env $.Values.postgresql.enabled }} env: + {{- if $.Values.postgresql.enabled }} + {{- include "tiled.postgresqlEnv" $ | nindent 12 }} + {{- end }} + {{- with $env }} {{- toYaml . | nindent 12 }} + {{- end }} {{- end }} volumes: - name: config diff --git a/Charts/tiled/templates/postgresql.yaml b/Charts/tiled/templates/postgresql.yaml new file mode 100644 index 0000000..6f59bc4 --- /dev/null +++ b/Charts/tiled/templates/postgresql.yaml @@ -0,0 +1,82 @@ +{{- with .Values.postgresql }} +{{- if .enabled }} +apiVersion: v1 +kind: Service +metadata: + name: {{ include "tiled.fullname" $ }}-postgresql + labels: + {{- include "tiled.labels" $ | nindent 4 }} + app.kubernetes.io/component: postgresql +spec: + clusterIP: None + ports: + - port: 5432 + targetPort: postgresql + name: postgresql + selector: + {{- include "tiled.selectorLabels" $ | nindent 4 }} + app.kubernetes.io/component: postgresql +--- +apiVersion: apps/v1 +kind: StatefulSet +metadata: + name: {{ include "tiled.fullname" $ }}-postgresql + labels: + {{- include "tiled.labels" $ | nindent 4 }} + app.kubernetes.io/component: postgresql +spec: + replicas: 1 + serviceName: {{ include "tiled.fullname" $ }}-postgresql + selector: + matchLabels: + {{- include "tiled.selectorLabels" $ | nindent 6 }} + app.kubernetes.io/component: postgresql + template: + metadata: + labels: + {{- include "tiled.labels" $ | nindent 8 }} + app.kubernetes.io/component: postgresql + spec: + securityContext: + {{- toYaml .podSecurityContext | nindent 8 }} + containers: + - name: postgresql + image: "{{ .image.repository }}:{{ .image.tag }}" + imagePullPolicy: {{ .image.pullPolicy }} + securityContext: + {{- toYaml .securityContext | nindent 12 }} + env: + # The image's entrypoint creates this superuser and database on first start + - name: POSTGRES_USER + value: {{ .user | quote }} + - name: POSTGRES_DB + value: {{ .database | quote }} + - name: POSTGRES_PASSWORD + valueFrom: + secretKeyRef: + {{- toYaml .passwordSecret | nindent 18 }} + ports: + - name: postgresql + containerPort: 5432 + readinessProbe: + exec: + command: [pg_isready, -U, {{ .user | quote }}] + resources: + {{- toYaml .resources | nindent 12 }} + volumeMounts: + # postgres 18+ keeps PGDATA in a versioned subdirectory of this + - name: data + mountPath: /var/lib/postgresql + volumeClaimTemplates: + - metadata: + name: data + spec: + accessModes: [ReadWriteOnce] + {{- with .storageClassName }} + storageClassName: {{ . }} + {{- end }} + resources: + requests: + storage: {{ .storage }} +{{- end }} +{{- end }} diff --git a/Charts/tiled/values.yaml b/Charts/tiled/values.yaml index 56104b4..967e396 100644 --- a/Charts/tiled/values.yaml +++ b/Charts/tiled/values.yaml @@ -39,6 +39,39 @@ config: writable_storage: "/storage/data" init_if_not_exists: true +# A postgres holding one catalog database shared by every beamline. The tiled +# pods initialize it on first start, and get PGHOST, PGUSER, PGPASSWORD and +# PGDATABASE, so point the trees at it with +# uri: "postgresql://$PGUSER:$PGPASSWORD@$PGHOST/$PGDATABASE" +# in place of the default sqlite one. +# The password must be URL-safe, as it is put into the uri as is. +postgresql: + enabled: false + image: + repository: postgres + tag: "18" + pullPolicy: IfNotPresent + user: tiled + database: tiled + # Only read when the data volume is empty; changing it later needs ALTER USER + passwordSecret: + name: tiled-secrets + key: POSTGRES_PASSWORD + storage: 10Gi + storageClassName: "" + resources: {} + # The postgres user of the image, which owns the data directory + podSecurityContext: + runAsNonRoot: true + runAsUser: 999 + runAsGroup: 999 + fsGroup: 999 + securityContext: + allowPrivilegeEscalation: false + capabilities: + drop: + - ALL + # Restart the tiled and envoy pods when their ConfigMap changes, by putting a # checksum of it in a pod annotation. See # https://helm.sh/docs/howto/charts_tips_and_tricks/#automatically-roll-deployments