PostgressHA in Kubernetes
Use 'helm' to install the configuration. 'helm'uses charts for this and I'll create a chart for the PostgressHA cluster.
Steps
- Do the steps in https://docs.helm.sh/using-helm/#quick-start to get helm up and running
Create the Chart
- helm create postgresha
- cd postgresha
- edit files
- helm dependency update
- helm install -n postgresha .
Info
- https://docs.helm.sh/using-helm/#quick-start
- http://blog.lwolf.org/post/how-to-deploy-ha-postgressql-cluster-on-kubernetes/
- https://docs.helm.sh/developing-charts/#
- http://blog.kubernetes.io/2016/10/helm-charts-making-it-simple-to-package-and-deploy-apps-on-kubernetes.html
Commands
helm list --all |
list all charts |
helm install -n <name> <chart name> |
install the chart and give it a specific name |
helm delete --purge <name> |
delete the chart and also purge any storage |
kubectl get pv |
list the Persistent Volumes |
kubectl get pvc |
list the Persistent Volume Claims |
kubectl apply -f <yaml file> |
apply the yaml file |
kubectl delete pod <podname> |
delete pod |
vSphere
Links:
govc (https://github.com/vmware/govmomi/tree/master/govc) | Use govc to configure the vSphere Cloud Provider |
|
Set some environment variables used by govc |
|
Enable UUID for a VM |
Files
postgresha/install.sh
export NAME=$1
if [ -z $NAME ]; then
echo "usage: $0 <name>"
exit
fi
helm install -n $NAME .
postgresha/delete.sh
export NAME=$1
if [ -z $NAME ]; then
echo "usage: $0 <name>"
exit
fi
helm delete $NAME --purge
kubectl delete pvc data-master-$NAME-master-0
kubectl delete pvc data-slave-$NAME-slave-0
kubectl delete pvc data-slave-$NAME-slave-1
postgresha/Chart.yaml
apiVersion: v1
description: postgresha cluster
name: postgresha
version: 0.1.0
maintainers:
- name: Milo van der Zee
email: <email>
postgresha/requirements.yaml
<empty file>
postgresha/values.yaml
persistence:
size: 20Gi
iscsi:
- name: master
usage: master
target: <target ip>:3260
iqn: <iqn>
- name: slave1
usage: slave
target: <target ip>:3260
iqn: <iqn>
- name: slave2
usage: slave
target: <target ip>:3260
iqn: <iqn>
statefulsets:
- name: postgresha-master
replicas: 1
usage: master
- name: postgresha-slave
replicas: 2
usage: slave
postgres:
image: postgres:9.6.2
user: postgres
password: <postgres password>
repuser: repuser
reppassword: <replication user password>
pgdata: /var/lib/postgresql/data/pgdata
postgresha/templates/persistentvolume.yaml
{{- $values := .Values -}}
{{ range $k, $v := .Values.persistence.iscsi }}
apiVersion: v1
kind: PersistentVolume
metadata:
labels:
type: iSCSI
usage: {{ $v.usage }}
name: {{ $v.name }}
spec:
accessModes:
- ReadWriteOnce
capacity:
storage: {{ $values.persistence.size }}
iscsi:
fsType: ext4
iqn: {{ $v.iqn }}
iscsiInterface: default
lun: 0
targetPortal: {{ $v.target }}
persistentVolumeReclaimPolicy: Retain
---
{{ end }}
postgresha/templates/statefulset.yaml
{{- $values := .Values -}}
{{ range $k, $v := .Values.statefulsets }}
apiVersion: apps/v1beta1
kind: StatefulSet
metadata:
labels:
app: {{ $v.name }}
name: {{ $v.name }}
namespace: default
spec:
replicas: {{ $v.replicas }}
selector:
matchLabels:
app: {{ $v.name }}
serviceName: postgres
template:
metadata:
labels:
app: {{ $v.name }}
function: postgresha
spec:
containers:
- command:
- bash
- -c
- su $PGUSER -c "bash /postgresha/start.sh"
env:
- name: PGDATA
value: {{ $values.postgres.pgdata }}
- name: PGUSER
value: {{ $values.postgres.user }}
- name: PGPASSWORD
value: {{ $values.postgres.password }}
- name: POD_IP
valueFrom:
fieldRef:
apiVersion: v1
fieldPath: status.podIP
image: {{ $values.postgres.image }}
imagePullPolicy: IfNotPresent
livenessProbe:
exec:
command:
- sh
- -c
- exec pg_isready --host localhost
failureThreshold: 6
initialDelaySeconds: 60
periodSeconds: 10
successThreshold: 1
timeoutSeconds: 5
name: postgresql
ports:
- containerPort: 5432
name: postgresql
protocol: TCP
readinessProbe:
exec:
command:
- sh
- -c
- exec pg_isready --host localhost
failureThreshold: 3
initialDelaySeconds: 5
periodSeconds: 5
successThreshold: 1
timeoutSeconds: 3
volumeMounts:
- mountPath: {{ $values.postgres.pgdata }}
name: data-{{ $v.usage }}
subPath: postgresql-db
- mountPath: /postgresha
name: postgresha
volumes:
- configMap:
defaultMode: 420
name: postgresha
name: postgresha
volumeClaimTemplates:
- metadata:
name: data-{{ $v.usage }}
spec:
accessModes:
- ReadWriteOnce
resources:
requests:
storage: {{ $values.persistence.size }}
selector:
matchLabels:
usage: {{ $v.usage }}
---
{{ end }}
postgresha/templates/service-postgresha.yaml
apiVersion: v1
kind: Service
metadata:
name: postgresha-ro
namespace: default
spec:
ports:
- name: postgresql
port: 5432
protocol: TCP
targetPort: 5432
selector:
function: postgresha
type: NodePort
---
{{ range $k, $v := .Values.statefulsets }}
apiVersion: v1
kind: Service
metadata:
name: {{ $v.name }}
namespace: default
spec:
ports:
- name: postgresql
port: 5432
protocol: TCP
targetPort: 5432
selector:
app: {{ $v.name }}
type: NodePort
---
{{ end }}
postgresha/templates/config-map.yaml
kind: ConfigMap
apiVersion: v1
metadata:
name: postgresha
data:
start.sh: |-
export PATH=/usr/lib/postgresql/$PG_MAJOR/bin:$PATH
postgres &
while [ 1 ]; do
echo "live..."
sleep 600
done
setup-master.sh: |-
if [ -z $PGDATA ]; then echo "PGDATA must be set!"; exit; fi
killall postgres
rm -rf $PGDATA/*
su -m postgres -c "export PATH=/usr/lib/postgresql/$PG_MAJOR/bin:$PATH; initdb"
cp /postgresha/postgresql-master.conf $PGDATA/postgresql.conf
cp /postgresha/pg_hba-master.conf $PGDATA/pg_hba.conf
export ARCHIVEDIR=$PGDATA/archivedir
[ ! -d "$ARCHIVEDIR" ] && mkdir $ARCHIVEDIR
chown -R postgres: $PGDATA
su -m postgres -c "export PATH=/usr/lib/postgresql/$PG_MAJOR/bin:$PATH; pg_ctl -D /var/lib/postgresql/data/pgdata -l logfile -w start"
# create the replication user
echo "CREATE USER {{ .Values.postgres.repuser }} REPLICATION ENCRYPTED PASSWORD '{{ .Values.postgres.reppassword }}'" | psql
echo "ALTER USER postgres WITH PASSWORD '{{ .Values.postgres.password }}'" | psql
date >> $PGDATA/setup_date
setup-slave.sh: |-
if [ -z $PGDATA ]; then echo "PGDATA must be set!"; exit; fi
killall postgres
rm -rf $PGDATA/*
# Copy data from the master to the slave
su -m postgres -c "export PATH=/usr/lib/postgresql/$PG_MAJOR/bin:$PATH; pg_basebackup --host=postgresha-master -D $PGDATA -U {{ .Values.postgres.repuser }} -v -P -W --xlog-method=stream"
cp /postgresha/postgresql-slave.conf $PGDATA/postgresql.conf
cp /postgresha/recovery-slave.conf $PGDATA/recovery.conf
chown -R postgres: $PGDATA
su -m postgres -c "export PATH=/usr/lib/postgresql/$PG_MAJOR/bin:$PATH; pg_ctl -D /var/lib/postgresql/data/pgdata -l logfile -w start"
date >> $PGDATA/setup_date
postgresql-master.conf: |-
listen_addresses = '*'
port = 5432
max_connections = 100
shared_buffers = 128MB
dynamic_shared_memory_type = posix
log_timezone = 'UTC'
datestyle = 'iso, mdy'
lc_messages = 'en_US.utf8'
lc_monetary = 'en_US.utf8'
lc_time = 'en_US.utf8'
default_text_search_config = 'pg_catalog.english'
wal_level = hot_standby
archive_mode = on
archive_command = 'cp -i %p $PGDATA/archivedir/%f'
max_wal_senders = 3
wal_keep_segments = 8
pg_hba-master.conf: |-
# TYPE DATABASE USER ADDRESS METHOD
local all all trust
host all all 127.0.0.1/32 trust
host all all ::1/128 trust
host replication {{ .Values.postgres.repuser}} 0.0.0.0/0 md5
host all all 0.0.0.0/0 md5
postgresql-slave.conf: |-
listen_addresses = '*'
port = 5432
max_connections = 100
shared_buffers = 128MB
dynamic_shared_memory_type = posix
log_timezone = 'UTC'
datestyle = 'iso, mdy'
lc_messages = 'en_US.utf8'
lc_monetary = 'en_US.utf8'
lc_time = 'en_US.utf8'
default_text_search_config = 'pg_catalog.english'
hot_standby = on
recovery-slave.conf: |-
standby_mode = on
primary_conninfo = 'host=postgresha-master port=5432 user={{ .Values.postgres.repuser }} password={{ .Values.postgres.reppassword }}'