From e4d1bb539a8776f400aac7c0d538787b9aee6a39 Mon Sep 17 00:00:00 2001
From: Janne Mareike Koschinski <janne@kuschku.de>
Date: Sun, 26 Mar 2023 16:41:34 +0200
Subject: [PATCH] feat: add postgresql chart

---
 .gitlab-ci.yml                        |   1 +
 postgresql/Chart.yaml                 |   6 ++
 postgresql/pipeline.yml               |  21 ++++++
 postgresql/templates/_helpers.tpl     |  56 ++++++++++++++
 postgresql/templates/configmap.yaml   |  43 +++++++++++
 postgresql/templates/secret.yaml      |  21 ++++++
 postgresql/templates/service.yaml     |  15 ++++
 postgresql/templates/statefulset.yaml | 101 ++++++++++++++++++++++++++
 postgresql/values.yaml                |  51 +++++++++++++
 9 files changed, 315 insertions(+)
 create mode 100644 postgresql/Chart.yaml
 create mode 100644 postgresql/pipeline.yml
 create mode 100644 postgresql/templates/_helpers.tpl
 create mode 100644 postgresql/templates/configmap.yaml
 create mode 100644 postgresql/templates/secret.yaml
 create mode 100644 postgresql/templates/service.yaml
 create mode 100644 postgresql/templates/statefulset.yaml
 create mode 100644 postgresql/values.yaml

diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml
index 8b29408..51452b9 100644
--- a/.gitlab-ci.yml
+++ b/.gitlab-ci.yml
@@ -16,6 +16,7 @@ include:
 - /mastodon/pipeline.yml
 - /oauth2-proxy/pipeline.yml
 - /powerdns/pipeline.yml
+- /postgresql/pipeline.yml
 - /quassel/pipeline.yml
 - /restic/pipeline.yml
 - /rtorrent/pipeline.yml
diff --git a/postgresql/Chart.yaml b/postgresql/Chart.yaml
new file mode 100644
index 0000000..6c3abdf
--- /dev/null
+++ b/postgresql/Chart.yaml
@@ -0,0 +1,6 @@
+apiVersion: v2
+name: postgresql
+description: Helm Chart for postgresql
+type: application
+version: 1.0.0
+appVersion: "14.7-alpine"
diff --git a/postgresql/pipeline.yml b/postgresql/pipeline.yml
new file mode 100644
index 0000000..dd418b0
--- /dev/null
+++ b/postgresql/pipeline.yml
@@ -0,0 +1,21 @@
+lint-postgresql:
+  stage: lint
+  rules:
+    - changes:
+        - postgresql/**/*
+  script:
+    - helm lint postgresql
+
+release-postgresql:
+  stage: release
+  needs:
+    - lint-postgresql
+  rules:
+    - if: '$CI_COMMIT_BRANCH == $CI_DEFAULT_BRANCH'
+      changes:
+        - postgresql/**/*
+  script:
+    - apk add --no-cache git
+    - helm plugin install https://github.com/chartmuseum/helm-push.git
+    - helm repo add --username gitlab-ci-token --password $CI_JOB_TOKEN repo ${CI_API_V4_URL}/projects/${CI_PROJECT_ID}/packages/helm/stable
+    - helm cm-push postgresql repo
diff --git a/postgresql/templates/_helpers.tpl b/postgresql/templates/_helpers.tpl
new file mode 100644
index 0000000..22d8660
--- /dev/null
+++ b/postgresql/templates/_helpers.tpl
@@ -0,0 +1,56 @@
+{{/*
+Expand the name of the chart.
+*/}}
+{{- define "postgresql-helm.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 "postgresql-helm.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 "postgresql-helm.chart" -}}
+{{- printf "%s-%s" .Chart.Name .Chart.Version | replace "+" "_" | trunc 63 | trimSuffix "-" }}
+{{- end }}
+
+{{/*
+Common labels
+*/}}
+{{- define "postgresql-helm.labels" -}}
+helm.sh/chart: {{ include "postgresql-helm.chart" . }}
+{{ include "postgresql-helm.selectorLabels" . }}
+{{- if .Chart.AppVersion }}
+app.kubernetes.io/version: {{ .Chart.AppVersion | quote }}
+{{- end }}
+app.kubernetes.io/managed-by: {{ .Release.Service }}
+{{- end }}
+
+{{/*
+Selector labels
+*/}}
+{{- define "postgresql-helm.selectorLabels" -}}
+app.kubernetes.io/name: {{ include "postgresql-helm.name" . }}
+app.kubernetes.io/instance: {{ .Release.Name }}
+{{- end }}
+
+
+{{- define "postgresql-helm.sslPath" -}}
+/certs
+{{- end }}
diff --git a/postgresql/templates/configmap.yaml b/postgresql/templates/configmap.yaml
new file mode 100644
index 0000000..90f07cb
--- /dev/null
+++ b/postgresql/templates/configmap.yaml
@@ -0,0 +1,43 @@
+apiVersion: v1
+kind: ConfigMap
+metadata:
+  name: {{ include "postgresql-helm.fullname" . }}
+  labels:
+    {{- include "postgresql-helm.labels" . | nindent 4 }}
+data:
+  performance.conf: |-
+    # DB Version: 12
+    # OS Type: linux
+    # DB Type: mixed
+    # Total Memory (RAM): 16 GB
+    # CPUs num: 8
+    # Connections num: 64
+    # Data Storage: ssd
+
+    max_connections = 128
+    shared_buffers = 4GB
+    effective_cache_size = 12GB
+    maintenance_work_mem = 1GB
+    checkpoint_completion_target = 0.9
+    wal_buffers = 16MB
+    default_statistics_target = 100
+    random_page_cost = 1.1
+    effective_io_concurrency = 200
+    work_mem = 8MB
+    min_wal_size = 1GB
+    max_wal_size = 4GB
+    max_worker_processes = 8
+    max_parallel_workers_per_gather = 4
+    max_parallel_workers = 8
+    max_parallel_maintenance_workers = 4
+  {{ if .Values.tls.enabled -}}
+  ssl.conf: |-
+    ssl = true
+    ssl_ciphers = 'AES256+EECDH:AES256+EDH:AES128+EECDH:AES128+EDH!aNULL'
+    ssl_ecdh_curve = 'secp384r1'
+    ssl_cert_file = '/certs/{{ .Values.tls.certFilename }}'
+    ssl_key_file = '/certs/{{ .Values.tls.certKeyFilename }}'
+  {{- end }}
+  stat.conf: |-
+    shared_preload_libraries = 'pg_stat_statements'
+    pg_stat_statements.track = all
diff --git a/postgresql/templates/secret.yaml b/postgresql/templates/secret.yaml
new file mode 100644
index 0000000..8902daa
--- /dev/null
+++ b/postgresql/templates/secret.yaml
@@ -0,0 +1,21 @@
+{{- $fullname := include "postgresql-helm.fullname" . -}}
+apiVersion: v1
+kind: Secret
+metadata:
+  name: {{ $fullname }}
+  annotations:
+    "helm.sh/resource-policy": "keep"
+  labels:
+    {{- include "postgresql-helm.labels" . | nindent 4 }}
+type: Opaque
+data:
+  {{ if empty .Values.postgresqlPassword }}
+  # retrieve the secret data using lookup function and when not exists, return an empty dictionary / map as result
+  {{- $secretObj := (lookup "v1" "Secret" .Release.Namespace $fullname) | default dict }}
+  {{- $secretData := (get $secretObj "data") | default dict }}
+  # set $secret to existing secret data or generate a random one when not exists
+  {{- $secretValue := (get $secretData $fullname) | default (randAlphaNum 48 | b64enc) }}
+  postgresql-password: {{ $secretValue | quote }}
+  {{ else }}
+  postgresql-password: "{{ .Values.postgresqlPassword }}"
+  {{ end }}
\ No newline at end of file
diff --git a/postgresql/templates/service.yaml b/postgresql/templates/service.yaml
new file mode 100644
index 0000000..fd32707
--- /dev/null
+++ b/postgresql/templates/service.yaml
@@ -0,0 +1,15 @@
+apiVersion: v1
+kind: Service
+metadata:
+  name: {{ include "postgresql-helm.fullname" . }}
+  labels:
+    {{- include "postgresql-helm.labels" . | nindent 4 }}
+spec:
+  type: "ClusterIP"
+  ports:
+    - port: 5432
+      targetPort: sql
+      protocol: TCP
+      name: sql
+  selector:
+    {{- include "postgresql-helm.selectorLabels" . | nindent 4 }}
diff --git a/postgresql/templates/statefulset.yaml b/postgresql/templates/statefulset.yaml
new file mode 100644
index 0000000..94afc71
--- /dev/null
+++ b/postgresql/templates/statefulset.yaml
@@ -0,0 +1,101 @@
+apiVersion: apps/v1
+kind: StatefulSet
+metadata:
+  name: {{ include "postgresql-helm.fullname" . }}
+  labels:
+    {{- include "postgresql-helm.labels" . | nindent 4 }}
+spec:
+  replicas: {{ .Values.replicaCount }}
+  serviceName: {{ include "postgresql-helm.fullname" . }}
+  selector:
+    matchLabels:
+      {{- include "postgresql-helm.selectorLabels" . | nindent 6 }}
+  template:
+    metadata:
+      {{- with .Values.podAnnotations }}
+      annotations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      labels:
+        {{- include "postgresql-helm.selectorLabels" . | nindent 8 }}
+    spec:
+      {{- with .Values.imagePullSecrets }}
+      imagePullSecrets:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      securityContext:
+        {{- toYaml .Values.podSecurityContext | nindent 8 }}
+      volumes:
+        {{ if .Values.tls.enabled -}}
+        - name: certs
+          secret:
+            secretName: {{ .Values.tls.certificatesSecret }}
+        {{- end }}
+        - configMap:
+            defaultMode: 420
+            name: {{ include "postgresql-helm.fullname" . }}
+          name: config
+        - name: data
+          {{- .Values.volume | nindent 10 }}
+        - emptyDir:
+            medium: Memory
+          name: shm
+      containers:
+        - name: postgresql
+          securityContext:
+            {{- toYaml .Values.securityContext | nindent 12 }}
+          image: "{{ .Values.image.repository }}:{{ .Values.image.tag | default .Chart.AppVersion }}"
+          imagePullPolicy: {{ .Values.image.pullPolicy }}
+          env:
+            - name: postgresql_PASSWORD
+              valueFrom:
+                secretKeyRef:
+                  key: "postgresql-password"
+                  name: {{ include "postgresql-helm.fullname" . }}
+          ports:
+            - name: sql
+              containerPort: 5432
+              protocol: TCP
+          startupProbe:
+            exec:
+              command:
+                - sh
+                - -c
+                - exec pg_isready --host localhost
+          livenessProbe:
+            exec:
+              command:
+                - sh
+                - -c
+                - exec pg_isready --host localhost
+          readinessProbe:
+            exec:
+              command:
+                - sh
+                - -c
+                - exec pg_isready --host localhost
+          resources:
+            {{- toYaml .Values.resources | nindent 12 }}
+          volumeMounts:
+            - mountPath: "/var/lib/postgresqlql/data"
+              name: data
+            - mountPath: "/configs"
+              name: config
+            - mountPath: "/dev/shm"
+              name: shm
+            {{ if .Values.tls.enabled -}}
+            - mountPath: "/certs"
+              name: certs
+            {{- end }}
+      {{- with .Values.nodeSelector }}
+      nodeSelector:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.affinity }}
+      affinity:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
+      {{- with .Values.tolerations }}
+      tolerations:
+        {{- toYaml . | nindent 8 }}
+      {{- end }}
diff --git a/postgresql/values.yaml b/postgresql/values.yaml
new file mode 100644
index 0000000..31a606d
--- /dev/null
+++ b/postgresql/values.yaml
@@ -0,0 +1,51 @@
+replicaCount: 1
+
+image:
+  repository: postgresql
+  pullPolicy: IfNotPresent
+  tag: ""
+
+imagePullSecrets: [ ]
+nameOverride: ""
+fullnameOverride: ""
+
+volume: |-
+  emptyDir: {}
+
+# if left empty, one will be auto-generated
+postgresqlPassword: ""
+
+tls:
+  enabled: false
+  certificatesSecret: ""
+  certFilename: "tls.crt"
+  certKeyFilename: "tls.key"
+
+securityContext:
+  capabilities:
+    drop:
+      - ALL
+  runAsNonRoot: true
+  runAsUser: 70
+  runAsGroup: 70
+
+resources: {}
+#  limits:
+#    cpu: 500m
+#    memory: 2Gi
+#  requests:
+#    cpu: 200m
+#    memory: 500Mi
+
+jobAnnotations: { }
+
+podAnnotations: { }
+
+podSecurityContext:
+  fsGroup: 70
+
+nodeSelector: { }
+
+tolerations: [ ]
+
+affinity: { }
-- 
GitLab