diff --git a/.gitlab-ci.yml b/.gitlab-ci.yml index 8b29408ba408358cf7f39d2866a921b57e17c66d..51452b9ffad1051ae211505a790df608311f8941 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 0000000000000000000000000000000000000000..6c3abdfac624997ee96659fe5813dfa5c7d06df5 --- /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 0000000000000000000000000000000000000000..dd418b096eedbf35735351422b5688e93e28d9b2 --- /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 0000000000000000000000000000000000000000..22d8660dea8230f0277b2cb72ff6c8bddca7a335 --- /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 0000000000000000000000000000000000000000..90f07cbfb89933c7dac4c233b4e52efaaf3fe524 --- /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 0000000000000000000000000000000000000000..8902daac9e2009e7d92e2ba2919cf557e2864e75 --- /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 0000000000000000000000000000000000000000..fd327079367e868b5a8dc5623c67d844372569da --- /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 0000000000000000000000000000000000000000..94afc71153d4947565d0f114e259432289729ba0 --- /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 0000000000000000000000000000000000000000..31a606da379bb88c360f20716ea90d01e5b849ec --- /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: { }