# Zalando Postgres Operator

DANGER

This is not complete !

Logo

The Postgres Operator enables highly-available PostgreSQL (opens new window) clusters on Kubernetes (K8s) powered by Patroni (opens new window). It is configured only through manifests to ease integration into automated CI/CD pipelines with no access to Kubernetes directly.

# Operator features

  • Rolling updates on Postgres cluster changes
  • Volume resize without Pod restarts
  • Cloning Postgres clusters
  • Logical Backups to S3 Bucket
  • Standby cluster from S3 WAL archive
  • Configurable for non-cloud environments
  • UI to create and edit Postgres cluster manifests

# PostgreSQL Operator features

The Postgres Operator has been developed at Zalando and is being used in production for over two years.

# Installation

Clone the repository

mkdir tmp
git clone https://github.com/zalando/postgres-operator.git tmp/zalando-postgres-operator
git -C tmp/zalando-postgres-operator checkout v1.2.0

Install the PostgreSQL Operator:

helm install --name zalando --namespace zalando tmp/zalando-postgres-operator/charts/postgres-operator \
  --set configKubernetes.cluster_domain=${MY_DOMAIN} \
  --set configLoadBalancer.db_hosted_zone=db.${MY_DOMAIN}

Create a Postgres cluster:

cat << EOF | kubectl apply -f -
apiVersion: "acid.zalan.do/v1"
kind: postgresql
metadata:
  name: myteam-mytest-cluster5
  namespace: default
spec:
  teamId: "myteam"
  volume:
    size: 1Gi
  numberOfInstances: 2
  users:
    myuser:           # database owner
    - superuser
    - createdb
    # mytestdb_user: []
  enableMasterLoadBalancer: false
  enableReplicaLoadBalancer: false
  databases:
    mytestdb: myuser  # dbname: owner
  postgresql:
    version: "10"
EOF

Check the deployed cluster:

kubectl describe postgresql

Check created database pods and services:

kubectl get pods,svc -l application=spilo -L spilo-role

Allow access to the database using Istio:

cat << EOF | kubectl apply -f -
apiVersion: networking.istio.io/v1alpha3
kind: Gateway
metadata:
  name: pgsql-myteam-mytest-cluster-gateway
  namespace: default
spec:
  selector:
    istio: ingressgateway
  servers:
  - port:
      number: 5432
      name: pgsql-myteam-mytest-cluster
      protocol: TCP
    hosts:
    - pgsql.${MY_DOMAIN}
  - port:
      number: 5433
      name: pgsql-repl-myteam-mytest-cluster
      protocol: TCP
    hosts:
    - pgsql.${MY_DOMAIN}
---
apiVersion: networking.istio.io/v1alpha3
kind: VirtualService
metadata:
  name: pgsql-myteam-mytest-virtual-service
  namespace: default
spec:
  hosts:
  - pgsql.${MY_DOMAIN}
  gateways:
  - pgsql-myteam-mytest-cluster-gateway
  tcp:
  - match:
    - port: 5432
    route:
    - destination:
        host: myteam-mytest-cluster.default.svc.cluster.local
        port:
          number: 5432
  - match:
    - port: 5433
    route:
    - destination:
        host: myteam-mytest-cluster-repl.default.svc.cluster.local
        port:
          number: 5432
EOF
export PGHOST=pgsql.${MY_DOMAIN}
export PGPORT=5432
export PGPASSWORD=$(kubectl get secret postgres.myteam-mytest-cluster.credentials -o 'jsonpath={.data.password}' | base64 -d)
psql -U postgres