Tahun baru dan Universitas Indonesia kedatangan peladen baru. Berhubung tim pengembang DSTI UI membuat pengembangan berbasis pelayan-mikro (microservice) dan ada pengembang yang iseng menantang saya menuju Kubernetes, saya pun tertantang membuat tutorial yang mendukung arsitektur tersebut. Kubernetes menyediakan fasilitas skalabilitas untuk menambah dan mengurangi peladen suatu layanan secara otomatis atau bisa diprogram manual.

Cara yang paling mudah untuk menyiapkan infrastruktur adalah dengan mengambil resep dari Ansible Playbook, menggunakan Juju, menggunakan helm, atau pemaket awan menurut keyakinan dan kepercayaan masing-masing. Namun, sebelum itu, saya tertarik untuk membahas bagaimana seandainya bila semua itu dibuat secara manual. Hal ini agar setiap kita dapat memahami bagaimana cara kerja masing-masing komponen yang nantinya diterbitkan dengan satu baris kode.

Tulisan ini sebenarnya mengikuti tutorial dari Linode. Hanya saja, saya menyesuaikan dengan lingkungan UI, Debian Stretch. Sehingga, ada yang saya modifikasi untuk keperluan dan keyakinan saya.

Arsitektur

PostgreSQL HA

PostgreSQL HA dengan 3 node dibalik haproxy

Untuk lingkungan ujicoba, saya membuat 5 mesin VM di VirtualBox dengan menggunakan 2 kartu jaringan (NIC). Satu NIC tipe NAT untuk keluar (standar VirtualBox) dengan DHCP. Satu lagi NIC tipe Jaringan Internal yang digunakan untuk setiap VM berkomunikasi satu sama lain.

pg1:

  • hostname: pg1
  • NIC: 192.0.2.11
  • Memori: 1GB

pg2:

  • hostname: pg2
  • NIC: 192.0.2.12
  • Memori: 1GB

pg3:

  • hostname: pg3
  • NIC: 192.0.2.13
  • Memori: 1GB

haproxy0:

  • hostname: haproxy0
  • NIC: 192.0.2.22
  • Memori: 512MB

etcd0:

  • hostname: etcd0
  • NIC: 192.0.2.21
  • Memori: 1GB

Berhubung komputer saya memiliki memori 32GB, saya agak royal mengalokasikan memori. Untuk keperluan pembelajaran, bisa, kok, dikurangi menjadi 512MB. Tapi, saya belum mencoba.

Sekedar tips untuk pengerjaan pg1 s.d. pg3. Sebaiknya kerjakan saja dulu pg1 lalu setelah rampung, klon dan ubah konfigurasi IP dan hostname sesuai dengan masing-masing mesin.

Konfigurasi Jaringan

Ada dua hal yang perlu dikerjakan:

  1. Konfigurasi IP pada NIC yang digunakan untuk berkomunikasi
  2. Tambahkan daftar hostname.

Konfigurasi IP

Pertama-tama kita perlu tahu NIC yang perlu dikonfigurasi. Debian Stretch sudah tidak lagi menyediakan ifconfig. Cara yang sahih sekarang untuk mengetahui ada antarmuka NIC apa saja yang tersedia:

$ ip link
1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN mode DEFAULT group default qlen 1
    link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00
2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP mode DEFAULT group default qlen 1000
    link/ether 08:00:27:86:ca:c3 brd ff:ff:ff:ff:ff:ff
3: enp0s8: <BROADCAST,MULTICAST> mtu 1500 qdisc noop state DOWN mode DEFAULT group default qlen 1000
    link/ether 08:00:27:20:b1:2b brd ff:ff:ff:ff:ff:ff

Pada konfigurasi VM saya, yang NIC yang perlu dikonfigurasi adalah enp0s8 — punya Anda bisa beda. Untuk menambahkan konfigurasi IP statik umpanya untuk mesin pg1:

$ sudo tee /etc/network/interfaces.d/enp0s8 << EOF
auto enp0s8
allow-hotplug enp0s8
iface enp0s8 inet static
  address 192.0.2.11
  netmask 255.255.255.0
EOF

Gunakan penyunting teks favorit Anda, tapi saya menggunakan cara heker. 😛

Lakukan ini untuk pg2, pg3, haproxy0, dan etcd0 dengan IP mereka masing-masing.

Untuk langsung mengaktifkan konfigurasi jaringan:

$ sudo ifup enp0s8

Lakukan ini di semua mesin.

Konfigurasi Hostname

Untuk VM, sebaiknya untuk setiap VM yang berhubungan dimasukkan namanya ke daftar /etc/hosts. Lakukan ini di semua mesin:

$ sudo tee -a  /etc/hosts << EOF
192.0.2.21      etcd0
192.0.2.22      haproxy0
192.0.2.11      pg1
192.0.2.12      pg2
192.0.2.13      pg3
EOF

Ganti nama hostname, umpanya untuk mesin pg1:

sudo hostnamectl set-hostname pg1

Keluar dari SSH lalu masuk kembali. Kalau tidak, nama sudah berganti tetapi shell Anda masih bernama yang lama.

Pemasangan etcd

TIPS: Pengerjaan yang saya lakukan adalah saya mematikan pg1. Lalu, saya klon dan saya ubah IP dan hostname.

Aplikasi etcd adalah sebuah repositori konfigurasi yang bisa diakses dari jaringan. Dia bisa dibuat kluster, tetapi untuk contoh kali ini dibuatkan satu saja. Saya asumsikan jaringan dan nama sudah terbuat.

Cara terbaik saat ini untuk lingkungan awan adalah menggunakan pemaket snapcraft untuk mendapatkan perangkat lunak terbaru yang stabil. Debian Stretch tidak memasang pemaket ini secara baku. Pasang dulu:

sudo apt update
sudo apt install snapd

Lalu, pasang etcd menggunakan snapcraft:

sudo snap install etcd

Konfigurasi aplikasi berbasis snapcraft ada di /var/snap. Berhubung konfigurasinya panjang, saya sudah sediakan unduhan. Saya jelaskan properti yang penting saja nanti. Cara pasang:

wget -q -O- https://raw.githubusercontent.com/jpmrblood/postgresql-ha-configuration/master/etcd.conf.yml | sudo tee /var/snap/etcd/common/etcd.conf.yml

Beberapa properti yang penting:

  • name: ‘etcd0’ — memberi nama mesin ini. Kalau ada lebih dari satu mesin etcd, pastikan masing-masing unik.
  • data-dir: /var/lib/etcd/data — tempat data etcd. Saya sesuaikan dengan FHS.
  • wal-dir: /var/lib/etcd/wal — tempat penampungan untuk jurnal etcd.
  • listen-peer-urls: http://192.0.2.21:2380 — Alamat TCP/IP untuk mendengarkan permintaan bergabung.
  • listen-client-urls: http://localhost:2379,http://192.0.2.21:2379 — Alamat TCP/IP untuk aplikasi ini beroperasi.
  • initial-advertise-peer-urls: http://192.0.2.21:2380 — Alamat TCP/IP untuk mengiklankan diri sendiri ke etcd yang lain. Saat ini tidak terpakai karena hanya ada satu saja.
  • advertise-client-urls: http://192.0.2.21:2379 — Alamat TCP/IP yang diberitahukan kepada yang lainnya.
  • initial-cluster: etcd0=http://192.0.2.21:2380, — Sejumlah alamat TCP/IP peladen etcd yang tergabung dalam kluster. Kali ini hanya satu.
  • initial-cluster-token: ‘etcd-cluster’ — Nama kluster etcd kita. Maaf kalau kurang kreatif.
  • initial-cluster-state: ‘new’ — Kondisi awal saat pertama kali etcd nanti dijalankan.

Kalau tutorial Linode memuat semua ini dalam variabel lingkungan. Sayangnya, Debian Stretch tidak ada etcd sehingga kita terpaksa memasangnya dari snapcraft.

Sebelum menjalankan etcd, jangan lupa membuat direktori yang dibutuhkan.

sudo mkdir -p /var/lib/etcd/data /var/lib/etcd/wal
sudo snap start etcd

TIPS #1: Kalau mau mencoba dulu, sebelum menggunakan snap start, gunakan snap run untuk menjalankan etcd langsung. Apabila sudah selesai diagnosis, tekan CTRL+C untuk selesai.

Bila sudah benar, maka akan terlihat:

$ snap services
Snap  Service  Startup  Current
etcd  etcd     enabled  active

Bila statusnya sudah aktif, sekarang saatnya memasang PostgreSQL beserta Patroni.

Pemasangan PostgreSQL (pg1, pg2, dan pg3)

Kecuali hostname dan IP, semua pemasangan PostgreSQL identik. Selain itu, saya menggunakan pwgen untuk membuat sandi. Mohon sandi Anda berbeda dengan tutorial ini!

Pasang PostgreSQL

Pasang seperti biasa.

echo "deb http://kambing.ui.ac.id/postgresql/repos/apt/ `lsb_release -cs`-pgdg main" | sudo tee /etc/apt/sources.list.d/postgresql.list
wget --quiet -O - http://kambing.ui.ac.id/postgresql/repos/apt/ACCC4CF8.asc | sudo apt-key add -
sudo apt update && sudo apt install postgresql-10

Saya sengaja memilih versi 10. Lebih baru dan keren.

Matikan layanan PostgreSQL karena kita mau menjalankannya dari Patroni:

sudo systemctl disable postgresql

Pasang Patroni

Patroni tersedia di Python PIP. Pasang PIP:

sudo apt install python3-pip
sudo pip3 install --upgrade setuptools

Baru pasang Patroni dan Python-etcd:

sudo pip3 install patroni[etcd]

Selanjutnya, buat konfigurasi Patroni:

$ sudo tee /etc/patroni.yml << EOF
scope: postgres
namespace: /db/
name: pg1

restapi:
    listen: 192.0.2.11:8008
    connect_address: 192.0.2.11:8008

etcd:
    host: 192.0.2.21:2379

bootstrap:
    dcs:
        ttl: 30
        loop_wait: 10
        retry_timeout: 10
        maximum_lag_on_failover: 1048576
        postgresql:
            use_pg_rewind: true

    initdb:
    - encoding: UTF8
    - data-checksums

    pg_hba:
    - host replication replicator 127.0.0.1/32 md5
    - host replication replicator 192.0.2.11/0 md5
    - host replication replicator 192.0.2.12/0 md5
    - host replication replicator 192.0.2.13/0 md5
    - host all all 0.0.0.0/0 md5

    users:
        admin:
            password: ioqu8ohqueh6kai5va0Hoigirae7Xaem
            options:
                - createrole
                - createdb

postgresql:
    listen: 192.0.2.11:5432
    connect_address: 192.0.2.11:5432
    data_dir: /var/lib/postgresql/10/patroni
    pgpass: /tmp/pgpass
    authentication:
        replication:
            username: replicator
            password: shohkaitahsee0er6eXoh0Ohghie2toh
        superuser:
            username: postgres
            password: exuush9shohlail6Cool9eeng3kae5iy
    parameters:
        unix_socket_directories: '.'

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

Jangan lupa mengganti IP pada setiap baris listen dan connect_address pada mesin pg2 dan pg3 dengan IP masing-masing. Jangan lupa mengganti sandi (password) agar tidak sama dengan tutorial ini!

Siapkan direktori data untuk PostgreSQL versi Patroni:

sudo -u postgres mkdir -p /var/lib/postgresql/10/patroni

Terakhir, pasang unit pelayan systemd Patroni:

$ sudo tee /etc/systemd/system/patroni.service << EOF
[Unit]
Description=Runners to orchestrate a high-availability PostgreSQL
After=syslog.target network.target

[Service]
Type=simple

User=postgres
Group=postgres

Environment="PATH=/usr/lib/postgresql/10/bin:/usr/local/bin:/usr/bin:/bin:/usr/local/games:/usr/games"
ExecStart=/usr/local/bin/patroni /etc/patroni.yml

KillMode=process

TimeoutSec=30

Restart=no

[Install]
WantedBy=multi-user.target
EOF

Daftarkan dan jalankan Patroni:

sudo systemctl daemon-reload
sudo systemctl enable patroni
sudo systemctl start patroni

Kalau sudah benar, maka Patroni akan menjalankan PostgreSQL versinya.

$ systemctl status patroni
● patroni.service - Runners to orchestrate a high-availability PostgreSQL
   Loaded: loaded (/etc/systemd/system/patroni.service; enabled; vendor preset: enabled)
   Active: active (running) since Fri 2018-01-26 11:18:14 WIB; 2min 27s ago
 Main PID: 9391 (patroni)
    Tasks: 12 (limit: 4915)
   CGroup: /system.slice/patroni.service
           ├─9391 /usr/bin/python3 /usr/local/bin/patroni /etc/patroni.yml
           ├─9417 postgres -D /var/lib/postgresql/10/patroni --config-file=/var/lib/postgresql/10/patroni/postgresql.conf --max_prepared_transactions=0 --port=5432 --cluster_name=postgres --max_locks_per_transaction
           ├─9420 postgres: postgres: checkpointer process   
           ├─9421 postgres: postgres: writer process   
           ├─9422 postgres: postgres: wal writer process   
           ├─9423 postgres: postgres: autovacuum launcher process   
           ├─9424 postgres: postgres: stats collector process   
           ├─9425 postgres: postgres: bgworker: logical replication launcher   
           └─9430 postgres: postgres: postgres postgres 192.0.2.11(44308) idle

Lakukan ini di pg2 dan pg3. Jangan lupa mengganti IP pada berkas /etc/patroni.yml.

Oh, iya, kalau menggunakan klon, jangan lupa /etc/network/interfaces.d/enp0s8 diubah sesuai dengan IP mesin. Jangan lupa juga ganti hostname.

Terus, kalau misalnya pg2 dan pg3 diklon dari pg1 saat Patroni sudah terkonfigurasi, jangan lupa kosongkan terlebih dahulu direktori data Patroni.

sudo systemctl stop patroni
sudo -u postgres rm -rf /var/lib/postgresql/10/patroni/
sudo -u postgres mkdir /var/lib/postgresql/10/patroni/
sudo systemctl start patroni

Kalau tidak, bisa aneh nanti.

Pemasangan HAProxy

Komponen terakhir yang hendak kita pasang adalah HAProxy. Untungnya, sudah ada paket Debian untuk HAProxy. Pasang seperti biasa:

sudo apt install haproxy

Konfigurasi HAProxy untuk menjadi proksi ketiga mesin  PostgreSQL kita.

$ sudo tee /etc/haproxy/haproxy.cfg << EOF
global
    maxconn 100

defaults
    log global
    mode tcp
    retries 2
    timeout client 30m
    timeout connect 4s
    timeout server 30m
    timeout check 5s

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

listen postgres
    bind *:5000
    option httpchk
    http-check expect status 200
    default-server inter 3s fall 3 rise 2 on-marked-down shutdown-sessions
    server postgresql_192.0.2.11_5432 192.0.2.11:5432 maxconn 100 check port 8008
    server postgresql_192.0.2.12_5432 192.0.2.12:5432 maxconn 100 check port 8008
    server postgresql_192.0.2.13_5432 192.0.2.13:5432 maxconn 100 check port 8008
EOF

Setelah itu, muat ulang HAProxy untuk memuat konfigurasi baru.

sudo systemctl restart haproxy

Saya mengikuti Tutorial Linode untuk membuat port PostgreSQL pada port 5000. Anda bisa saja membuat port 5432. Kebetulan PC saya ada layanan PostgreSQL lain yang jalan pada port itu.

Untuk memonitor, silakan buka peramban Anda pada port 7000.

HAProxy interfacing Patriani's PostgreSQL nodes

HAProxy interfacing Patriani’s PostgreSQL nodes

Hanya ada satu yang hijau/aktif. Kalau tiga-tiganya, kemungkinan Anda mengklon tanpa mengubah konfigurasi dan mengosongkan direktori data PostgreSQL terlebih dahulu.

Selesai.

(Kulshekhar Kabra, 2017)

Daftar Pustaka

Kulshekhar Kabra (2017, September 19). Create a Highly Available PostgreSQL Cluster Using Patroni and HAProxy. Retrieved January 26, 2018 from https://linode.com/docs/databases/postgresql/create-a-highly-available-postgresql-cluster-using-patroni-and-haproxy/.^