├── README.md ├── client ├── client-pod.yaml └── psql-client.yaml ├── pgpool ├── nginx.yaml ├── pgpool-deployment.yaml ├── pgpool-secret.yaml ├── pgpool-svc-nodeport.yaml └── pgpool-svc.yaml └── postgresql ├── postgres-configmap.yaml ├── postgres-headless-svc.yaml ├── postgres-secrets.yaml └── postgres-statefulset.yaml /README.md: -------------------------------------------------------------------------------- 1 | # kubernetes-postgresql 2 | Kubernetes Statefullset manifests for PostgreSQL 3 | 4 | For full documentation, refer https://devopscube.com/deploy-postgresql-statefulset/ 5 | -------------------------------------------------------------------------------- /client/client-pod.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: pg-client 6 | spec: 7 | containers: 8 | - image: bitnami/postgresql:11.12.0-debian-10-r13 9 | name: postgresql 10 | env: 11 | - name: ALLOW_EMPTY_PASSWORD 12 | value: "yes" -------------------------------------------------------------------------------- /client/psql-client.yaml: -------------------------------------------------------------------------------- 1 | --- 2 | apiVersion: v1 3 | kind: Pod 4 | metadata: 5 | name: pg-client 6 | spec: 7 | containers: 8 | - image: bitnami/postgresql:11.12.0-debian-10-r13 9 | name: postgresql 10 | env: 11 | - name: ALLOW_EMPTY_PASSWORD 12 | value: "yes" -------------------------------------------------------------------------------- /pgpool/nginx.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: nginx 5 | spec: 6 | type: NodePort 7 | ports: 8 | - name: nginx 9 | port: 80 10 | targetPort: 80 11 | protocol: TCP 12 | nodePort: 32000 13 | selector: 14 | app: nginx -------------------------------------------------------------------------------- /pgpool/pgpool-deployment.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: Deployment 3 | metadata: 4 | name: pgpool-deployment 5 | spec: 6 | replicas: 1 7 | selector: 8 | matchLabels: 9 | app: pgpool 10 | template: 11 | metadata: 12 | labels: 13 | app: pgpool 14 | spec: 15 | securityContext: 16 | fsGroup: 1001 17 | containers: 18 | - name: pgpool 19 | image: docker.io/bitnami/pgpool:4.2.3-debian-10-r38 20 | imagePullPolicy: "IfNotPresent" 21 | securityContext: 22 | runAsUser: 1001 23 | env: 24 | - name: BITNAMI_DEBUG 25 | value: "false" 26 | - name: PGPOOL_BACKEND_NODES 27 | value: 0:postgres-sts-0.postgres-headless-svc:5432,1:postgres-sts-1.postgres-headless-svc:5432,2:postgres-sts-2.postgres-headless-svc:5432 28 | - name: PGPOOL_SR_CHECK_USER 29 | value: "repmgr" 30 | - name: PGPOOL_SR_CHECK_PASSWORD 31 | valueFrom: 32 | secretKeyRef: 33 | name: postgres-secrets 34 | key: repmgr-password 35 | - name: PGPOOL_SR_CHECK_DATABASE 36 | value: "postgres" 37 | - name: PGPOOL_ENABLE_LDAP 38 | value: "no" 39 | - name: PGPOOL_POSTGRES_USERNAME 40 | value: "postgres" 41 | - name: PGPOOL_POSTGRES_PASSWORD 42 | valueFrom: 43 | secretKeyRef: 44 | name: postgres-secrets 45 | key: postgresql-password 46 | - name: PGPOOL_ADMIN_USERNAME 47 | value: "admin" 48 | - name: PGPOOL_ADMIN_PASSWORD 49 | valueFrom: 50 | secretKeyRef: 51 | name: pgpool-secrets 52 | key: admin-password 53 | - name: PGPOOL_ENABLE_LOAD_BALANCING 54 | value: "yes" 55 | - name: PGPOOL_ENABLE_LOG_CONNECTIONS 56 | value: "no" 57 | - name: PGPOOL_ENABLE_LOG_HOSTNAME 58 | value: "yes" 59 | - name: PGPOOL_ENABLE_LOG_PER_NODE_STATEMENT 60 | value: "no" 61 | - name: PGPOOL_CHILD_LIFE_TIME 62 | value: "" 63 | - name: PGPOOL_ENABLE_TLS 64 | value: "no" 65 | ports: 66 | - name: postgresql 67 | containerPort: 5432 68 | protocol: TCP 69 | livenessProbe: 70 | exec: 71 | command: 72 | - /opt/bitnami/scripts/pgpool/healthcheck.sh 73 | initialDelaySeconds: 30 74 | periodSeconds: 10 75 | timeoutSeconds: 5 76 | successThreshold: 1 77 | failureThreshold: 5 78 | readinessProbe: 79 | exec: 80 | command: 81 | - bash 82 | - -ec 83 | - PGPASSWORD=${PGPOOL_POSTGRES_PASSWORD} psql -U "postgres" -d "postgres" -h /opt/bitnami/pgpool/tmp -tA -c "SELECT 1" >/dev/null 84 | initialDelaySeconds: 5 85 | periodSeconds: 5 86 | timeoutSeconds: 5 87 | successThreshold: 1 88 | failureThreshold: 5 -------------------------------------------------------------------------------- /pgpool/pgpool-secret.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: pgpool-secrets 5 | data: 6 | admin-password: "SFRzaVZxYjdSZQ==" 7 | -------------------------------------------------------------------------------- /pgpool/pgpool-svc-nodeport.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: pgpool-svc-external 5 | spec: 6 | type: NodePort 7 | ports: 8 | - name: postgresql 9 | port: 5432 10 | targetPort: postgresql 11 | protocol: TCP 12 | nodePort: 32000 13 | selector: 14 | app: pgpool -------------------------------------------------------------------------------- /pgpool/pgpool-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: pgpool-svc 5 | spec: 6 | type: ClusterIP 7 | sessionAffinity: None 8 | ports: 9 | - name: postgresql 10 | port: 5432 11 | targetPort: postgresql 12 | protocol: TCP 13 | nodePort: null 14 | selector: 15 | app: pgpool -------------------------------------------------------------------------------- /postgresql/postgres-configmap.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: ConfigMap 3 | metadata: 4 | name: postgres-configmap 5 | data: 6 | pre-stop.sh: |- 7 | #!/bin/bash 8 | set -o errexit 9 | set -o pipefail 10 | set -o nounset 11 | 12 | # Debug section 13 | exec 3>&1 14 | exec 4>&2 15 | 16 | # Load Libraries 17 | . /opt/bitnami/scripts/liblog.sh 18 | . /opt/bitnami/scripts/libpostgresql.sh 19 | . /opt/bitnami/scripts/librepmgr.sh 20 | 21 | # Auxiliary functions 22 | is_new_primary_ready() { 23 | return_value=1 24 | currenty_primary_node="$(repmgr_get_primary_node)" 25 | currenty_primary_host="$(echo $currenty_primary_node | awk '{print $1}')" 26 | 27 | info "$currenty_primary_host != $REPMGR_NODE_NETWORK_NAME" 28 | if [[ $(echo $currenty_primary_node | wc -w) -eq 2 ]] && [[ "$currenty_primary_host" != "$REPMGR_NODE_NETWORK_NAME" ]]; then 29 | info "New primary detected, leaving the cluster..." 30 | return_value=0 31 | else 32 | info "Waiting for a new primary to be available..." 33 | fi 34 | return $return_value 35 | } 36 | 37 | export MODULE="pre-stop-hook" 38 | 39 | if [[ "${BITNAMI_DEBUG}" == "true" ]]; then 40 | info "Bash debug is on" 41 | else 42 | info "Bash debug is off" 43 | exec 1>/dev/null 44 | exec 2>/dev/null 45 | fi 46 | 47 | # Load PostgreSQL & repmgr environment variables 48 | . /opt/bitnami/scripts/postgresql-env.sh 49 | 50 | postgresql_enable_nss_wrapper 51 | 52 | # Prepare env vars for managing roles 53 | primary_node="$(repmgr_get_primary_node)" 54 | primary_host="$(echo $primary_node | awk '{print $1}')" 55 | 56 | # Stop postgresql for graceful exit. 57 | postgresql_stop 58 | 59 | if [[ "$primary_host" == "$REPMGR_NODE_NETWORK_NAME" ]]; then 60 | info "Primary node need to wait for a new primary node before leaving the cluster" 61 | retry_while is_new_primary_ready 10 5 62 | else 63 | info "Standby node doesn't need to wait, leaving the cluster." 64 | fi -------------------------------------------------------------------------------- /postgresql/postgres-headless-svc.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Service 3 | metadata: 4 | name: postgres-headless-svc 5 | spec: 6 | type: ClusterIP 7 | clusterIP: None 8 | ports: 9 | - name: postgresql 10 | port: 5432 11 | targetPort: postgresql 12 | protocol: TCP 13 | selector: 14 | app: postgres -------------------------------------------------------------------------------- /postgresql/postgres-secrets.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: v1 2 | kind: Secret 3 | metadata: 4 | name: postgres-secrets 5 | data: 6 | postgresql-password: "V2JyVHBOM2c3cQ==" 7 | repmgr-password: "c1ZwYm90R2d4Nw==" -------------------------------------------------------------------------------- /postgresql/postgres-statefulset.yaml: -------------------------------------------------------------------------------- 1 | apiVersion: apps/v1 2 | kind: StatefulSet 3 | metadata: 4 | name: postgres-sts 5 | spec: 6 | serviceName: postgres-headless-svc 7 | replicas: 3 8 | selector: 9 | matchLabels: 10 | app: postgres 11 | template: 12 | metadata: 13 | labels: 14 | app: postgres 15 | spec: 16 | securityContext: 17 | fsGroup: 1001 18 | containers: 19 | - name: postgresql 20 | lifecycle: 21 | preStop: 22 | exec: 23 | command: 24 | - /pre-stop.sh 25 | image: docker.io/bitnami/postgresql-repmgr:11.12.0-debian-10-r44 26 | imagePullPolicy: "IfNotPresent" 27 | securityContext: 28 | runAsUser: 1001 29 | # Auxiliary vars to populate environment variables 30 | env: 31 | - name: BITNAMI_DEBUG 32 | value: "false" 33 | # PostgreSQL configuration 34 | - name: POSTGRESQL_VOLUME_DIR 35 | value: "/bitnami/postgresql" 36 | - name: PGDATA 37 | value: "/bitnami/postgresql/data" 38 | - name: POSTGRES_USER 39 | value: "postgres" 40 | - name: POSTGRES_PASSWORD 41 | valueFrom: 42 | secretKeyRef: 43 | name: postgres-secrets 44 | key: postgresql-password 45 | - name: POSTGRES_DB 46 | value: "postgres" 47 | - name: POSTGRESQL_LOG_HOSTNAME 48 | value: "true" 49 | - name: POSTGRESQL_LOG_CONNECTIONS 50 | value: "false" 51 | - name: POSTGRESQL_LOG_DISCONNECTIONS 52 | value: "false" 53 | - name: POSTGRESQL_PGAUDIT_LOG_CATALOG 54 | value: "off" 55 | - name: POSTGRESQL_CLIENT_MIN_MESSAGES 56 | value: "error" 57 | - name: POSTGRESQL_SHARED_PRELOAD_LIBRARIES 58 | value: "pgaudit, repmgr" 59 | - name: POSTGRESQL_ENABLE_TLS 60 | value: "no" 61 | # Repmgr configuration 62 | - name: MY_POD_NAME 63 | valueFrom: 64 | fieldRef: 65 | fieldPath: metadata.name 66 | - name: REPMGR_UPGRADE_EXTENSION 67 | value: "no" 68 | - name: REPMGR_PGHBA_TRUST_ALL 69 | value: "no" 70 | - name: REPMGR_MOUNTED_CONF_DIR 71 | value: "/bitnami/repmgr/conf" 72 | - name: REPMGR_NAMESPACE 73 | valueFrom: 74 | fieldRef: 75 | fieldPath: metadata.namespace 76 | - name: REPMGR_PARTNER_NODES 77 | value: postgres-sts-0.postgres-headless-svc.$(REPMGR_NAMESPACE).svc.cluster.local,postgres-sts-1.postgres-headless-svc.$(REPMGR_NAMESPACE).svc.cluster.local,postgres-sts-2.postgres-headless-svc.$(REPMGR_NAMESPACE).svc.cluster.local 78 | - name: REPMGR_PRIMARY_HOST 79 | value: "postgres-sts-0.postgres-headless-svc.$(REPMGR_NAMESPACE).svc.cluster.local" 80 | - name: REPMGR_NODE_NAME 81 | value: "$(MY_POD_NAME)" 82 | - name: REPMGR_NODE_NETWORK_NAME 83 | value: "$(MY_POD_NAME).postgres-headless-svc.$(REPMGR_NAMESPACE).svc.cluster.local" 84 | - name: REPMGR_LOG_LEVEL 85 | value: "NOTICE" 86 | - name: REPMGR_CONNECT_TIMEOUT 87 | value: "5" 88 | - name: REPMGR_RECONNECT_ATTEMPTS 89 | value: "3" 90 | - name: REPMGR_RECONNECT_INTERVAL 91 | value: "5" 92 | - name: REPMGR_USERNAME 93 | value: "repmgr" 94 | - name: REPMGR_PASSWORD 95 | valueFrom: 96 | secretKeyRef: 97 | name: postgres-secrets 98 | key: repmgr-password 99 | - name: REPMGR_DATABASE 100 | value: "repmgr" 101 | ports: 102 | - name: postgresql 103 | containerPort: 5432 104 | protocol: TCP 105 | livenessProbe: 106 | exec: 107 | command: 108 | - bash 109 | - -ec 110 | - 'PGPASSWORD=$POSTGRES_PASSWORD psql -w -U "postgres" -d "postgres" -h 127.0.0.1 -c "SELECT 1"' 111 | initialDelaySeconds: 30 112 | periodSeconds: 10 113 | timeoutSeconds: 5 114 | successThreshold: 1 115 | failureThreshold: 6 116 | readinessProbe: 117 | exec: 118 | command: 119 | - bash 120 | - -ec 121 | - 'PGPASSWORD=$POSTGRES_PASSWORD psql -w -U "postgres" -d "postgres" -h 127.0.0.1 -c "SELECT 1"' 122 | initialDelaySeconds: 5 123 | periodSeconds: 10 124 | timeoutSeconds: 5 125 | successThreshold: 1 126 | failureThreshold: 6 127 | volumeMounts: 128 | - name: data 129 | mountPath: /bitnami/postgresql 130 | - name: hooks-scripts 131 | mountPath: /pre-stop.sh 132 | subPath: pre-stop.sh 133 | volumes: 134 | - name: hooks-scripts 135 | configMap: 136 | name: postgres-configmap 137 | defaultMode: 0755 138 | volumeClaimTemplates: 139 | - metadata: 140 | name: data 141 | spec: 142 | accessModes: 143 | - "ReadWriteOnce" 144 | resources: 145 | requests: 146 | storage: "1Gi" --------------------------------------------------------------------------------