Menyiapkan ZooKeeper Cluster.

Mari kita mulai dengan zookeeper cluster. Kita akan menggunakan multipass untuk mengelola virtual machine yang dibutuhkan.

Jalankan perintah berikut untuk membuat 3 vm ubuntu edisi jammy.

multipass launch jammy --name zookeeper-1
multipass launch jammy --name zookeeper-2
multipass launch jammy --name zookeeper-3

Jalankan perintah multipass list untuk melihat status vm dan ip dari setiap vm. output multipass list

Pasang paket zookeeperd di tiga vm (zookeeper-1, zookeeper-2, zookeeper-3). Kita bisa masuk ke vm multipass dengan menjalankan perintah multipass shell {namavm}. Gunakan tiga terminal agar tidak perlu keluar masuk vm.

Terminal 1:

multipass shell zookeeper-1
sudo apt update && sudo apt install zookeeperd -y

Terminal 2:

multipass shell zookeeper-2
sudo apt update && sudo apt install zookeeperd -y

Terminal 3:

multipass shell zookeeper-3
sudo apt update && sudo apt install zookeeperd -y

Catatan: Gunakan mirror repository terdekat untuk mempercepat proses download.

Anggota zookeeper cluster wajib memiliki id unik dengan nilai antara 1-255. Id unik ini perlu diatur di berkas myid. Pada ubuntu jammy, berkas ini tersimpan di /etc/zookeeper/conf/myid. Berikan id 1 untuk node zookeeper-1, id 2 untuk zookeeper-2, dan 3 untuk zookeeper-3.

echo {id} | sudo tee /etc/zookeeper/conf/myid

output zookeeper set myid

Langkah selanjutnya adalah menghubungkan setiap node zookeeper menjadi satu cluster. Buka file /etc/zookeeper/conf/zoo.cfg dengan nano atau vim (wajib menggunakan sudo).

sudo vim /etc/zookeeper/conf/zoo.cfg

Cari baris konfigurasi berikut:

#server.1=zookeeper1:2888:3888
#server.2=zookeeper2:2888:3888
#server.3=zookeeper3:2888:3888

Ubah menjadi

server.1=zookeeper-1.multipass:2888:3888
server.2=zookeeper-2.multipass:2888:3888
server.3=zookeeper-3.multipass:2888:3888

Sesuaikan nilai zookeeper-1, zookeeper-2, zookeeper-3 dengan hostname atau ip dari setiap node.

output zookeeper set myid

Nyalakan ulang service zookeeper pada setiap node. Pastikan seluruh node menujukkan status CONNECTED ketika diuji coba cengan zkCli.sh

sudo systemctl stop zookeeper.service 
sudo systemctl start zookeeper.service
sudo /usr/share/zookeeper/bin/zkCli.sh 

Status CONNECTING pada zkCli.sh menujukkan adanya kesalahan pada node zookeeper. Lakukan debugging dengan membaca log zookeeper di /var/log/zookeeper/zookeeper.log.

Menyiapkan Node Postgres.

Jalankan perintah berikut untuk membuat 3 vm untuk server postgresql.

multipass launch jammy --name postgresql-1
multipass launch jammy --name postgresql-2
multipass launch jammy --name postgresql-3

multipass list

Pasang postgresql-server di seluruh node postgres.

Terminal 4:

multipass shell postgresql-1
sudo apt update && sudo apt install postgresql -y

Terminal 5:

multipass shell postgresql-2
sudo apt update && sudo apt install postgresql -y

Terminal 6:

multipass shell postgresql-3
sudo apt update && sudo apt install postgresql -y

Matikan service postgresql di seluruh node postgres.

sudo systemctl stop postgresql

Menyiapkan Patroni.

Pasang patroni dengan menjalankan perintah berikut di tiga node postgres (postgresql-1, postgresql-2, postgresql-3).

sudo apt install patroni python3-kazoo -y 

Buat direktori untuk menyimpan database files di tiga node postgres.

sudo mkdir -p /data/patroni
sudo chown postgres:postgres /data/patroni
sudo chmod 700 /data/patroni 

Selanjutnya buat berkas /etc/patroni/config.yml pada tiga node postgres dengan isi sebagai berikut.

scope: postgres-multipass-0
namespace: /postgres-multipass-0/
name: postgresql-1

restapi:
  listen: 10.89.131.213:8008
  connect_address: 10.89.131.213:8008

zookeeper:
  hosts: ['10.89.131.56:2181', '10.89.131.132:2181', '10.89.131.151:2181']

bootstrap:
  dcs:
    ttl: 30
    loop_wait: 10
    retry_timeout: 10
    maximum_lag_on_failover: 1048576
    postgresql:
      use_pg_rewind: true
      pg_hba:
      - host replication replicator 127.0.0.1/32 md5
      - host replication replicator 10.89.131.213/0 md5
      - host replication replicator 10.89.131.29/0 md5
      - host replication replicator 10.89.131.5/0 md5
      - host all all 0.0.0.0/0 md5
      parameters:

  initdb:
  - encoding: UTF8
  - data-checksums

postgresql:
  listen: 10.89.131.213:5432
  connect_address: 10.89.131.213:5432

  data_dir: /data/patroni
  bin_dir: /usr/lib/postgresql/14/bin
  pgpass: /tmp/pgpass0
  authentication:
    replication:
      username: replicator
      password: replicator
    superuser:
      username: postgres
      password: postgres
    rewind:
      username: rewind_user
      password: rewind_password
  parameters:
    unix_socket_directories: '.'

tags:
    nofailover: false
    noloadbalance: false
    clonefrom: false
    nosync: false

Sesuaikan nilai-nilai berikut

  • Ubah nilai name dengan identitas unik node
  • Ubah nilai ip restapi.listen dan restapi.connect_address dengan ip dari node
  • Ubah nilai ip zookeeper.hosts dengan daftar ip dari zookeeper cluster
  • Tambahkan ip seluruh node postgresql/patroni ke bootstrap.dcs.postgresql.pg_hba
  • Ubah nilai ip postgresql.listen dan postgresql.connect_address dengan ip dari node
  • Ubah nilai versi postgresql di postgresql.bin_dir (14 di jammy)

Jalankan patroni disetiap node postgresql.

sudo systemctl start patroni

Pastikan service patroni berjalan di setiap node.

sudo systemctl status patroni

Pastikan juga seluruh node postgresql terdaftar sebagai anggota cluster dengan menjalankan perintah berikut disalah satu node.

patronictl -c /etc/patroni/config.yml list

luaran patronictl list

Perintah journalctl -xeu patroni dapat digunakan untuk melihat log (debugging) service patroni.

Menguji Replikasi.

Buat database baru pada leader dari cluster. Gunakan password sesuai konfigurasi postgresql.authentication.superuser.password saat diminta.

psql -h 10.89.131.213 -U postgres -c 'CREATE DATABASE testdb'

Pastikan database terbentuk juga pada postgres follower

psql -h 10.89.131.29 -U postgres -c 'SELECT datname FROM pg_database;'
psql -h 10.89.131.5 -U postgres -c 'SELECT datname FROM pg_database;'

Menguji Failover.

Matikan service patroni pada node leader.

sudo systemctl stop patroni

Pastikan posisi leader berubah ke node lain.

patronictl -c /etc/patroni/config.yml list

luaran patronictl list setelah node leader dimatikan

Nyalakan ulang service patroni.

sudo systemctl start patroni

Pastikan node kembali lagi menjadi anggota cluster sebagai member.

patronictl -c /etc/patroni/config.yml list

luaran patronictl list setelah node dinyalakan ulang

Pergantian leader dapat dilakukan secara manual dengan menjalankan switchover.

patronictl -c /etc/patroni/config.yml switchover

luaran perintah switchover

Menyiapkan Haproxy.

Sekarang postgresql kita terbagi menjadi dua yaitu leader yang dapat menerima akses read write dan follower yang hanya bisa menerima akses read only. Masalahnya, saat terjadi proses switchover posisi node leader dapat berubah menjadi follower. Aplikasi yang memerlukan read write akan mengalami error karena terkoneksi ke node follower. Haproxy (load balancer) dapat digunakan untuk menyelesaikan masalah ini. Aplikasi cukup terkoneksi ke haproxy dan haproxy yang akan bertanggung jawab merutekan koneksi ke node yang sesuai.

Jalankan perintah berikut untuk membuat vm ubuntu untuk haproxy.

multipass launch jammy --name haproxy-1

Single node haproxy adalah Single Point of Failure. Hindari single node haproxy di lingkungan production.

multipass list

Pasang haproxy di node haproxy-1.

sudo apt update && sudo apt install haproxy -y

Matikan service haproxy.

sudo systemctl stop haproxy

Backup default konfigurasi haproxy.

sudo cp /etc/haproxy/haproxy.cfg /etc/haproxy/haproxy.cfg.original

Tambahkan konfigurasi berikut dibagian bawah /etc/haproxy/haproxy.cfg. Jangan lupa sesuaikan nilai ip dari cluster postgresql.

listen stats
    mode http
    bind *:7000
    stats enable
    stats uri /

listen pg_rw
    mode tcp
    bind *:5432
    option httpchk
    http-check expect status 200
    default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
    server postgresql-1 10.89.131.213:5432 maxconn 100 check port 8008
    server postgresql-2 10.89.131.29:5432 maxconn 100 check port 8008
    server postgresql-3 10.89.131.5:5432 maxconn 100 check port 8008

listen pg_ro
    mode tcp
    bind *:5433
    option httpchk
    http-check expect status 503
    default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
    server postgresql-1 10.89.131.213:5432 maxconn 100 check port 8008
    server postgresql-2 10.89.131.29:5432 maxconn 100 check port 8008
    server postgresql-3 10.89.131.5:5432 maxconn 100 check port 8008

Konfigurasi diatas menambahkan 3 entry yaitu stats, pg_rw, dan pg_ro. stats berfungsi mengembalikan halaman statistics haproxy di port 7000. pg_rw menerima koneksi postgres di port 5432 dan meneruskannya ke node leader. pg_ro menerima koneksi di port 5433 dan meneruskannya ke node follower. Jalankan ulang service haproxy.

sudo systemctl restart haproxy.service 

Buka http://10.89.131.49:7000/ (ip haproxy) untuk melihat statistics dari haproxy. Pada bagian pg_rw haproxy akan menunjukkan status node leader terkini, ditandai dengan warna hijau. Pada bagian pg_ro haproxy akan menujukkan node follower.

haproxy stats

Lakukan switchover dan haproxy akan mengupdate status pg_rw dan pg_ro.

haproxy stats after switchover

Periksa status koneksi dengan fungsi pg_is_in_recovery() melalui port 5432 (pg_rw) dan 5433 (pg_ro).

psql -h 10.89.131.49 -p 5432 -U postgres -c 'SELECT pg_is_in_recovery();'
psql -h 10.89.131.49 -p 5433 -U postgres -c 'SELECT pg_is_in_recovery();'

pg_is_in_recovery() mengembalikan nilai t jika koneksi adalah read only dan f jika koneksi adalah read write.

testing koneksi ke haproxy

Selesai