https://hub.helm.sh/charts/cetic/pgadmin
helm repo add cetic https://cetic.github.io/helm-charts helm repo update helm install cetic/pgadmin --name pgadmin --namespace pgadmin --set image.repository=dpage/pgadmin4:4.15 --set service.type=ClusterIP --set image.pullPolicy=IfNotPresent
PersistentVolume
apiVersion: v1 kind: PersistentVolume metadata: name: pgadmin-pv namespace: pgadmin labels: app: pgadmin spec: capacity: storage: 4Gi accessModes: - ReadWriteOnce hostPath: path: "/kubernetes_volumes/pgadmin-data" type: Directory persistentVolumeReclaimPolicy: Retain
Ingress
apiVersion: extensions/v1beta1 kind: Ingress metadata: annotations: kubernetes.io/ingress.class: nginx cert-manager.io/cluster-issuer: letsencrypt name: pgadmin-ingress namespace: pgadmin spec: rules: - host: pgadmin.autosys.tk http: paths: - backend: serviceName: pgadmin servicePort: 80 path: / tls: - hosts: - pgadmin.autosys.tk secretName: pgadmin-autosys-tk-tls
Ошибки
После апгрейда docker-образа с версии 4.15 до 4.17 под не смог запуститься с ошибкой:
WARNING: Failed to set ACL on the directory containing the configuration database: [Errno 1] Operation not permitted: '/var/lib/pgadmin' PermissionError: [Errno 1] Operation not permitted: '/var/lib/pgadmin/sessions'
Это произошло потому, что у пользователь, от имени которого исполняется pgadmin, не является владельцем директории, которая смонтирована как persistentVolume. Поэтому, когда контейнер запускается (но еще не упал с Error) нужно найти процесс pgadmin:
#ps -aux | grep pgadmin 5050 16492 0.0 0.1 24720 22892 ? Ss 16:07 0:00 /usr/local/bin/python /usr/local/bin/gunicorn --timeout 86400 --bind [::]:80 -w 1 --threads 25 --access-logfile - run_pgadmin:app
И сделать owner'ом папки пользователя с указанным id. В хостовой системе, на которой исполняется контейнер, такого пользователя может и не быть. Главное, чтобы в ACL директории был прописан правильный id:
sudo chown 5050:5050 /kubernetes_volumes/pgadmin-data/ -R
Проблемы
Если нужно, чтобы при входе в PGAdmin сразу подключался сервер, то нужно сделать две вещи - заполнить файл с определениями серверов /pgadmin4/servers.json и заполнить файл pgpass, который хранит пароли для заданных серверов/бд/пользовтелей.
Если с заполнением файла /pgadmin4/servers.json всё более-менее понятно (за исключением того, что путь PassFile задается относительно директории пользователя, что само по себе нетривиально), то вот с файлом pgpass всё не очень просто.
В документации написано, что права на этот файл должны быть строго не шире, чем 0600, то есть права на чтение должен иметь только владелец файла.
Однако, если pgadmin работает в кластере kubernetes, содержимое файла pgpass монтируется из секрета а для пода задан securityContext, то defaultMod для файла смонтированного из секрета не применяется (так написано тут: https://github.com/kubernetes/kubernetes/issues/89153 и тут: https://github.com/kubernetes/kubernetes/issues/57923).
В итоге - всё оказывается сложнее, но выход есть!
Итак, я использую чарт pgadmin в качестве сабчарта (наряду с чартом postgresql) и хочу, чтобы в конфиг PGAdmin автоматически попадали параметры развернутого postgresql.
Для этого мне понадобилось
- Секрет с содержимым файла pgpass
{{- if .Values.pgadmin4.enabled -}} apiVersion: v1 kind: Secret metadata: name: pgpassfile labels: data: pgpassfile: {{ include "pgadmin4.pgpassfile" . | b64enc | quote }} {{- end}}
- Содержимое файла pgpass формируется хелпером
{{- define "pgadmin4.pgpassfile" -}} {{ .Values.global.postgresql.fullnameOverride }}:{{ .Values.global.postgresql.service.port }}:*:{{ .Values.global.postgresql.postgresqlUsername }}:{{ .Values.global.postgresql.postgresqlPassword }} {{ end }}
- Хелпер для формирования файла /pgadmin4/servers.json (хелпер родительского чарта переопределяет хелпер сабчарта pgadmin4)
{{/* Определение сервера для PGAdmin */}} {{- define "pgadmin.serverDefinitions" }} { "Servers": { "1": { "Name": "PostgeSql-{{ .Values.global.environment }}", "Group": "Servers", "Host": "{{ .Values.global.postgresql.fullnameOverride }}", "Port": "{{ .Values.global.postgresql.service.port }}", "MaintenanceDB": "{{ .Values.global.postgresql.postgresqlDatabase }}", "Username": "{{ .Values.global.postgresql.postgresqlUsername }}", "SSLMode": "prefer", "Comment": "Preconfigured PostgreSQL Server", "DBRestriction": "{{ .Values.global.postgresql.postgresqlDatabase }}", "PassFile": "/pgpass" } } } {{- end -}}
- Проблему с правами на файл pgpass решаем с помощью init-контейнера, который монтирует секрет в файл, а затем - копирует этот файл в нужную папку и задает ему нужные права:
extraSecretMounts: - name: pgpassfile secret: pgpassfile subPath: pgpassfile mountPath: "/pgpass" readOnly: true extraInitContainers: | - name: pgpass-permissions-init image: "docker.rdleas.ru/dpage/pgadmin4:4.29" command: - "/bin/ash" - "-c" - "/bin/mkdir -p /var/lib/pgadmin/storage/pgadmin && /bin/cp /pgpass /var/lib/pgadmin/storage/pgadmin/pgpass && /bin/chmod 0600 /var/lib/pgadmin/storage/pgadmin/pgpass" securityContext: runAsUser: 0 volumeMounts: - mountPath: /pgpass name: pgpassfile readOnly: false subPath: pgpassfile - mountPath: /var/lib/pgadmin name: pgadmin-data
- В файле values родительского чарта записи такие:
global: environment: dev postgresql: fullnameOverride: postgresql postgresqlUsername: api-user postgresqlPassword: tvJk3XrqM3d7xX6b postgresqlDatabase: sbl-mobile-api service: port: 5432 ... postgresql: enabled: true fullnameOverride: postgresq ... pgadmin4: serverDefinitions: #defined in _helpers.tpl - "pgadmin.serverDefinitions" enabled: true extraSecretMounts: - name: pgpassfile secret: pgpassfile subPath: pgpassfile mountPath: "/pgpass" readOnly: true extraInitContainers: | - name: pgpass-permissions-init image: "docker.rdleas.ru/dpage/pgadmin4:4.29" command: - "/bin/ash" - "-c" - "/bin/mkdir -p /var/lib/pgadmin/storage/pgadmin && /bin/cp /pgpass /var/lib/pgadmin/storage/pgadmin/pgpass && /bin/chmod 0600 /var/lib/pgadmin/storage/pgadmin/pgpass" securityContext: runAsUser: 0 volumeMounts: - mountPath: /pgpass name: pgpassfile readOnly: false subPath: pgpassfile - mountPath: /var/lib/pgadmin name: pgadmin-data persistentVolume: enabled: false securityContext: runAsUser: 0 runAsGroup: 0 fsGroup: 0
Discussion