Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
24 commits
Select commit Hold shift + click to select a range
77459ed
PgAdmin4 k8s helm chart initialization
KorenP1 Aug 31, 2025
1cd8d10
Updated helm/README.md and helm/Chart.yaml
KorenP1 Aug 31, 2025
14cf642
Merge branch 'master' into master
KorenP1 Sep 3, 2025
85aba51
Update helm appVersion to 9.8.0
KorenP1 Sep 4, 2025
859514a
Merge branch 'master' of https://github.com/KorenP1/pgadmin4
KorenP1 Sep 4, 2025
a5e4283
Added appArmor support, accessMode fix
KorenP1 Sep 4, 2025
a2dc3bb
Added config_local.py support, helm/README.md Update, Changed default…
KorenP1 Sep 4, 2025
7f5b7b9
Updated helm/README.md
KorenP1 Sep 4, 2025
d50acc1
PgAdmin4 k8s helm chart initialization
KorenP1 Aug 31, 2025
f9ff7ce
Updated helm/README.md and helm/Chart.yaml
KorenP1 Aug 31, 2025
ee59b0e
Update helm appVersion to 9.8.0
KorenP1 Sep 4, 2025
94c4b30
Added appArmor support, accessMode fix
KorenP1 Sep 4, 2025
fd9f8fa
Added config_local.py support, helm/README.md Update, Changed default…
KorenP1 Sep 4, 2025
e8e657f
Updated helm/README.md
KorenP1 Sep 4, 2025
286c9eb
Merge branch 'master' of https://github.com/KorenP1/pgadmin4
KorenP1 Sep 16, 2025
80121cd
Added enableServiceLinks field
KorenP1 Sep 16, 2025
10e619a
Merge branch 'master' into master
KorenP1 Sep 17, 2025
12697bf
Moved directory to pkg/
KorenP1 Sep 23, 2025
bac1dc5
Helm pkg: Added readability for packaging, updated version
KorenP1 Sep 23, 2025
7fee9cb
Merge branch 'master' into master
KorenP1 Sep 24, 2025
4551f51
Merge branch 'master' into master
KorenP1 Sep 26, 2025
1bb665c
Merge branch 'master' into master
KorenP1 Oct 4, 2025
e8a45a6
Merge branch 'master' into master
KorenP1 Oct 6, 2025
2d45132
Merge branch 'master' into master
KorenP1 Oct 7, 2025
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
11 changes: 11 additions & 0 deletions pkg/helm/Chart.yaml

Large diffs are not rendered by default.

41 changes: 41 additions & 0 deletions pkg/helm/README.md
Original file line number Diff line number Diff line change
@@ -0,0 +1,41 @@
# PgAdmin4 K8S Helm Chart

Its been a struggle to deploy pgadmin4 container on different restricted k8s distributions for example openshift, gke or vanilla k8s pod security standards.
This helm chart follows best security measures and practices and compatible with all different security contexts and restrictions.
Further explanation about the security implementation can be read here: https://korenp1.github.io

The helm chart also implements most pgadmin4 features, for instance, config_local.py, predefined server definitions or preferences.

The majority of features and values are covered in the helm chart but always can be more customable or tpl'able, open for contributions.

### Package && Push
The chart should dump its version and appVersion in the Chart.yaml file every release and pushed to docker.io/dpage repository.
`helm package . && helm push pgadmin4-helm-<VERSION>.tgz oci://docker.io/dpage`

### Installation Example:
`helm install mypgadmin4 oci://docker.io/dpage/pgadmin4-helm --set ingress.enabled=true`

### Important Values
| Value | Description | Default |
| --------- | ----------- | ------- |
| `containerPort` | Internal PgAdmin4 Port | `5050` |
| `image.registry` | Image registry | `"docker.io"` |
| `image.repository` | Image Repository | `"dpage/pgadmin4"` |
| `image.tag` | Image tag (If empty, will use .Chart.AppVersion) | `""` |
| `auth.email` | Admin Email | `"[email protected]"` |
| `auth.password` | Admin password (If both auth.password and auth.existingSecret are empty, the password will be randomly generated) | `""` |
| `auth.existingSecret` | Existing secret name for admin password (If both auth.password and auth.existingSecret are empty, the password will be randomly generated) | `""` |
| `extraEnvVars` | Extra environment variables | `[]` |
| `config_local.enabled` | Whether to mount config_local.py file | `false` |
| `config_local.data` | config_local.py configuration content | `""` |
| `config_local.existingSecret` | Existing secret name containing config_local.py file | `""` |
| `serverDefinitions.enabled` | Whether to mount servers.json | `false` |
| `serverDefinitions.data` | Server definitions to import | `{}` |
| `preferences.enabled` | Whether to mount preferences.json | `false` |
| `preferences.data` | Preferences to load | `{}` |
| `resources.*` | Allocated requests and limits resources | `{"requests": {...}, "limits": {...}}` |
| `persistence.enabled` | PVC resource creation | `false` |
| `service.type` | Service type | `"ClusterIP"` |
| `service.loadBalancerIP` | Load balancer IP (Only if service.type is LoadBalancer) | `""` |
| `ingress.enabled` | Ingress resource creation | `false` |
| `ingress.hostname` | Ingress resource hostname | `"pgadmin4.local"` |
11 changes: 11 additions & 0 deletions pkg/helm/templates/NOTES.txt
Original file line number Diff line number Diff line change
@@ -0,0 +1,11 @@
Thanks for using PgAdmin4 Helm Chart :)

Image: {{ template "pgadmin4.image" . }}

Credentials:
Email: {{ .Values.auth.email }}
Password: {{ printf "kubectl get secret %s -n %s -o jsonpath='{.data.%s}' | base64 -d" (include "pgadmin4.fullname" .) .Release.Namespace .Values.auth.passwordKey }}

Ingress: {{ ternary (tpl .Values.ingress.hostname .) "DISABLED" .Values.ingress.enabled }}

GOOD LUCK!
28 changes: 28 additions & 0 deletions pkg/helm/templates/_helpers.tpl
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
{{- define "pgadmin4.fullname" -}}
{{- tpl .Values.fullname . -}}
{{- end -}}

{{- define "pgadmin4.image" -}}
{{- printf "%s/%s:%s" (default .Values.image.registry .Values.global.imageRegistry) .Values.image.repository (default .Chart.AppVersion .Values.image.tag | toString) -}}
{{- end -}}

{{- define "pgadmin4.serviceAccountName" -}}
{{- default (ternary (include "pgadmin4.fullname" .) "default" .Values.serviceAccount.create) .Values.serviceAccount.name -}}
{{- end -}}

{{- define "renderSecurityContext" -}}
{{- $securityContext := omit .securityContext "enabled" -}}
{{- if or (eq .context.Values.global.compatibility.openshift.adaptSecurityContext "force") (and (eq .context.Values.global.compatibility.openshift.adaptSecurityContext "auto") (ternary "true" "" (.context.Capabilities.APIVersions.Has "security.openshift.io/v1"))) -}}
{{- $securityContext = omit $securityContext "fsGroup" "runAsUser" "runAsGroup" -}}
{{- if not $securityContext.seLinuxOptions }}
{{- $securityContext = omit $securityContext "seLinuxOptions" -}}
{{- end -}}
{{- end -}}
{{- if $securityContext.privileged }}
{{- $securityContext = omit $securityContext "capabilities" -}}
{{- end -}}
{{- if not .context.Values.global.compatibility.appArmor.enabled }}
{{- $securityContext = omit $securityContext "appArmorProfile" -}}
{{- end -}}
{{- $securityContext | toYaml -}}
{{- end -}}
14 changes: 14 additions & 0 deletions pkg/helm/templates/configmap-preferences.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{{- if .Values.preferences.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "pgadmin4.fullname" . }}-preferences
{{- with .Values.commonLabels }}
labels: {{ . | toYaml | nindent 4 }}
{{- end }}
{{- with .Values.commonAnnotations }}
annotations: {{ . | toYaml | nindent 4 }}
{{- end }}
data:
preferences.json: | {{ dict "preferences" .Values.preferences.data | toPrettyJson | nindent 4 }}
{{- end }}
14 changes: 14 additions & 0 deletions pkg/helm/templates/configmap-serverDefinitions.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,14 @@
{{- if .Values.serverDefinitions.enabled }}
apiVersion: v1
kind: ConfigMap
metadata:
name: {{ template "pgadmin4.fullname" . }}-server-definitions
{{- with .Values.commonLabels }}
labels: {{ . | toYaml | nindent 4 }}
{{- end }}
{{- with .Values.commonAnnotations }}
annotations: {{ . | toYaml | nindent 4 }}
{{- end }}
data:
servers.json: | {{ tpl (dict "Servers" .Values.serverDefinitions.data | toYaml) . | fromYaml | toPrettyJson | nindent 4 }}
{{- end }}
237 changes: 237 additions & 0 deletions pkg/helm/templates/deployment.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,237 @@
apiVersion: apps/v1
kind: Deployment
metadata:
name: {{ template "pgadmin4.fullname" . }}
{{- with .Values.commonLabels }}
labels: {{ . | toYaml | nindent 4 }}
{{- end }}
{{- with .Values.commonAnnotations }}
annotations: {{ . | toYaml | nindent 4 }}
{{- end }}
spec:
replicas: {{ .Values.replicas }}
selector:
matchLabels:
app: {{ default "pgadmin4" .Values.commonLabels.app }}
{{- with omit .Values.commonLabels "app" }}
{{- . | toYaml | nindent 6 }}
{{- end }}
template:
metadata:
labels:
app: {{ default "pgadmin4" .Values.commonLabels.app }}
{{- with omit .Values.commonLabels "app" }}
{{- . | toYaml | nindent 8 }}
{{- end }}
{{- if or (not (empty .Values.commonAnnotations)) (not .Values.existingSecret) .Values.preferences.enabled .Values.serverDefinitions.enabled }}
annotations:
{{- with .Values.commonAnnotations }}
{{- . | toYaml | nindent 8 }}
{{- end }}
{{- if not .Values.existingSecret }}
checksum/secret: {{ include (print $.Template.BasePath "/secret.yaml") . | sha256sum }}
{{- end }}
{{- if and .Values.config_local.enabled (empty .Values.config_local.existingSecret) }}
checksum/secret-config: {{ include (print $.Template.BasePath "/secret-config.yaml") . | sha256sum }}
{{- end }}
{{- if .Values.serverDefinitions.enabled }}
checksum/configmap-server-definitions: {{ include (print $.Template.BasePath "/configmap-serverDefinitions.yaml") . | sha256sum }}
{{- end }}
{{- if .Values.preferences.enabled }}
checksum/configmap-preferences: {{ include (print $.Template.BasePath "/configmap-preferences.yaml") . | sha256sum }}
{{- end }}
{{- end }}
spec:
{{- if or .Values.global.imagePullSecrets .Values.image.pullSecrets }}
imagePullSecrets: {{- concat .Values.global.imagePullSecrets .Values.image.pullSecrets | toYaml | nindent 8 }}
{{- end }}
serviceAccountName: {{ template "pgadmin4.serviceAccountName" . }}
automountServiceAccountToken: {{ .Values.serviceAccount.automountServiceAccountToken }}
{{- if .Values.podSecurityContext.enabled }}
securityContext: {{- include "renderSecurityContext" (dict "securityContext" .Values.podSecurityContext "context" .) | nindent 8 }}
enableServiceLinks: {{ .Values.enableServiceLinks }}
{{- end }}
volumes:
- name: empty-dir
emptyDir: {}
{{- if .Values.persistence.enabled }}
- name: data
persistentVolumeClaim:
claimName: {{ template "pgadmin4.fullname" . }}
{{- end }}
{{- if .Values.config_local.enabled }}
- name: config-local
secret:
secretName: {{ default (printf "%s-config" (include "pgadmin4.fullname" .)) .Values.config_local.existingSecret }}
items:
- key: {{ .Values.config_local.configKey }}
path: {{ .Values.config_local.configKey }}
{{- end }}
{{- if .Values.serverDefinitions.enabled }}
- name: server-definitions
configMap:
name: {{ template "pgadmin4.fullname" . }}-server-definitions
items:
- key: servers.json
path: servers.json
{{- end }}
{{- if .Values.preferences.enabled }}
- name: preferences
configMap:
name: {{ template "pgadmin4.fullname" . }}-preferences
items:
- key: preferences.json
path: preferences.json
{{- end }}
{{- with .Values.extraVolumes }}
{{- . | toYaml | nindent 8 }}
{{- end }}
containers:
- name: pgadmin4
{{- if .Values.containerSecurityContext.enabled }}
securityContext: {{- include "renderSecurityContext" (dict "securityContext" .Values.containerSecurityContext "context" .) | nindent 12 }}
{{- end }}
image: {{ template "pgadmin4.image" . }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
ports:
- name: http
protocol: TCP
containerPort: {{ .Values.containerPort }}
resources:
requests:
cpu: {{ .Values.resources.requests.cpu }}
memory: {{ .Values.resources.requests.memory }}
limits:
cpu: {{ .Values.resources.limits.cpu }}
memory: {{ .Values.resources.limits.memory }}
env:
- name: PGADMIN_DEFAULT_EMAIL
value: {{ .Values.auth.email }}
- name: PGADMIN_DEFAULT_PASSWORD
valueFrom:
secretKeyRef:
name: {{ default (include "pgadmin4.fullname" .) .Values.auth.existingSecret }}
key: {{ .Values.auth.passwordKey }}
- name: PGADMIN_LISTEN_PORT
value: {{ .Values.containerPort | quote }}
- name: PGADMIN_DISABLE_POSTFIX
value: {{ .Values.disablePostfix | quote }}
{{- with .Values.extraEnvVars }}
{{- tpl (. | toYaml) $ | nindent 14 }}
{{- end }}
volumeMounts:
- mountPath: /var/lib/pgadmin
{{- if .Values.persistence.enabled }}
name: data
{{- else }}
name: empty-dir
subPath: data
{{- end }}
- name: empty-dir
mountPath: /pgadmin4/config_distro.py
subPath: config_distro.py
- name: empty-dir
mountPath: /usr/bin/python3
subPath: python3
- name: empty-dir
mountPath: /tmp
subPath: tmp
- name: empty-dir
mountPath: /var/log/pgadmin
subPath: logs
{{- if .Values.config_local.enabled }}
- name: config-local
mountPath: /pgadmin4/config_local.py
subPath: {{ .Values.config_local.configKey }}
{{- end }}
{{- if .Values.serverDefinitions.enabled }}
- name: server-definitions
mountPath: /pgadmin4/servers.json
subPath: servers.json
{{- end }}
{{- if .Values.preferences.enabled }}
- name: preferences
mountPath: /pgadmin4/preferences.json
subPath: preferences.json
{{- end }}
{{- with .Values.extraVolumes }}
{{- . | toYaml | nindent 12 }}
{{- end }}
{{- if .Values.startupProbe.enabled }}
startupProbe: {{- omit .Values.startupProbe "enabled" | toYaml | nindent 12 }}
{{- end }}
{{- if .Values.readinessProbe.enabled }}
readinessProbe: {{- omit .Values.readinessProbe "enabled" | toYaml | nindent 12 }}
{{- end }}
{{- if .Values.livenessProbe.enabled }}
livenessProbe: {{- omit .Values.livenessProbe "enabled" | toYaml | nindent 12 }}
{{- end }}
initContainers:
- name: modify-config-distro-py-permissions
image: {{ template "pgadmin4.image" . }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
command: ["sh", "-x", "-c"]
args: ['cp /pgadmin4/config_distro.py . && chmod 777 config_distro.py']
workingDir: /emptyDir
volumeMounts:
- name: empty-dir
mountPath: /emptyDir
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 50m
memory: 64Mi
securityContext:
seLinuxOptions: {}
runAsUser: 1001
runAsGroup: 1001
runAsNonRoot: true
privileged: false
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
{{- if .Values.global.compatibility.appArmor.enabled }}
appArmorProfile:
type: RuntimeDefault
{{- end }}
windowsOptions:
hostProcess: false
- name: unset-python3-cli-net-cap
image: {{ template "pgadmin4.image" . }}
imagePullPolicy: {{ .Values.image.pullPolicy }}
command: ["sh", "-x", "-c"]
args: ['ls /usr/bin/python3.* | sort -V -r | head -n 1 | xargs -I {} cp {} python3']
workingDir: /emptyDir
volumeMounts:
- name: empty-dir
mountPath: /emptyDir
resources:
requests:
cpu: 50m
memory: 64Mi
limits:
cpu: 50m
memory: 64Mi
securityContext:
seLinuxOptions: {}
runAsUser: 1001
runAsGroup: 1001
runAsNonRoot: true
privileged: false
readOnlyRootFilesystem: true
allowPrivilegeEscalation: false
capabilities:
drop: ["ALL"]
seccompProfile:
type: RuntimeDefault
{{- if .Values.global.compatibility.appArmor.enabled }}
appArmorProfile:
type: RuntimeDefault
{{- end }}
windowsOptions:
hostProcess: false
4 changes: 4 additions & 0 deletions pkg/helm/templates/extra-list.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,4 @@
{{- range .Values.extraDeploy }}
---
{{ tpl (. | toYaml) $ }}
{{- end }}
24 changes: 24 additions & 0 deletions pkg/helm/templates/ingress.yaml
Original file line number Diff line number Diff line change
@@ -0,0 +1,24 @@
{{- if .Values.ingress.enabled }}
apiVersion: networking.k8s.io/v1
kind: Ingress
metadata:
name: {{ template "pgadmin4.fullname" . }}
{{- with .Values.commonLabels }}
labels: {{ . | toYaml | nindent 4 }}
{{- end }}
{{- if or .Values.ingress.annotations .Values.commonAnnotations }}
annotations: {{ merge .Values.ingress.annotations .Values.commonAnnotations | toYaml | nindent 4 }}
{{- end }}
spec:
rules:
- host: {{ tpl .Values.ingress.hostname . }}
http:
paths:
- backend:
service:
name: {{ template "pgadmin4.fullname" . }}
port:
name: http
path: /
pathType: Prefix
{{- end }}
Loading
Loading