Masih ingat tutorial saya tentang Patroni dahulu? Saya akan membuat tulisan lengkap dari nol sampai berjalan. Di akhir tutorial ini Anda bisa membuat kluster Patroni secara manual. Kalau Anda devops dan tertarik menulis resep untuk Ansible, Puppet, dan sejenisnya, saya harap artikel ini bisa menjadi acuan untuk mengerti Patroni.

Mesin-mesin yang Ada

Saya membagi setiap mesin yang digunakan dengan dua IP. Satu subnet IP internal yang digunakan untuk setiap mesin dalam kluster berkomunikasi dan satu subnet IP yang digunakan untuk akses luar. Implementasi fisik dengan menggunakan dua kartu jaringan (atau dua bonding fisik)  yang berbeda. Perbedaan jaringan untuk komunikasi internal dan komunikasi dengan klien ini selain menyediakan keamanan dalam isolasi, juga membuat koneksi internal atau pun eksternal tidak saling mengganggu.
 “Well, hell! PMP exam topics That’s no excuse for insulting me! You PMP exam topics 300-320 questions pdf are 300-320 questions pdf Ma’s PMP exam topics PMP exam topics own blood son, but did PMP exam topics she take on that time PMP exam topics Tony Fontaine shot you in the leg? 70-532 answer analysis No, she 70-532 answer analysis just 300-320 questions pdf sent for old Doc 70-532 answer analysis Fontaine to dress it and asked the doctor what ailed Tony’s aim. Said she guessed licker was spoiling his marksmanship. Remember how mad that made Tony?”Both boys yelled 70-532 answer analysis with laughter.“Ma’s a card!” said Brent with loving approval. “You can always count on her to do the right thing 300-320 questions pdf and 70-532 answer analysis not embarrass you in front of PMP exam topics folks.”  But Gerald remained Gerald. 300-320 questions pdf His habits PMP exam topics of living and his ideas changed, but his manners he would 300-075 certification exam not change, 300-075 certification exam even had he been 70-532 answer analysis able to change them. He admired 300-320 questions pdf the drawling 300-075 certification exam elegance of the 300-075 certification exam wealthy rice and cotton planters, who rode into Savannah from their moss-hung kingdoms, mounted 70-532 answer analysis on 300-320 questions pdf thoroughbred horses and followed by the carriages of their 300-320 questions pdf equally elegant ladies 70-532 answer analysis and the wagons 300-320 questions pdf of their slaves. But Gerald could never attain elegance. 70-532 answer analysis Their lazy, blurred voices fell pleasantly 300-075 certification exam 300-075 certification exam 300-320 questions pdf on PMP exam topics his PMP exam topics ears, but his 300-075 certification exam PMP exam topics own 300-075 certification exam brisk brogue clung to his tongue. He liked the casual 70-532 answer analysis 300-075 certification exam grace with which they PMP exam topics conducted affairs 300-320 questions pdf of importance, 300-320 questions pdf risking 300-320 questions pdf a fortune, a plantation or a slave 70-532 answer analysis 300-075 certification exam on the 300-075 certification exam turn 70-532 answer analysis of a card and writing off their losses with careless good humor and no more ado than when they scattered 300-320 questions pdf pennies to pickaninnies. But Gerald had known poverty, and PMP exam topics he could never PMP exam topics learn to lose money with 70-532 answer analysis good 300-075 certification exam humor or good 300-320 questions pdf 70-532 answer analysis 300-320 questions pdf grace. They were PMP exam topics a pleasant race, these coastal Georgians, with their soft-voiced, 70-532 answer analysis PMP exam topics quick rages and their charming inconsistencies, and Gerald liked them. But 300-075 certification exam there was a 300-075 certification exam brisk and 70-532 answer analysis restless vitality 300-075 certification exam about the young Irishman, fresh from a country where winds blew wet and chill, where misty swamps held no fevers, that 300-075 certification exam set him apart from these indolent gentle-folk of semi-tropical weather and malarial marshes.
Untuk mengurangi kompleksitas tutorial ini, saya hanya menyediakan satu mesin HAProxy dan satu mesin etcd. Fokus tulisan ini adalah untuk ketersediaan PostgreSQL. Untuk membuat ketersediaan HAProxy dan etcd akan dibahas lain kali bila ada waktu [baca: kalau tidak malas].
Agar tidak membingungkan, saya selalu mempraktikkan penamaan kluster ditambah dengan prefiks nama aplikasi. Hal ini penting karena di perawanan yang sudah semakin terotomatisasi, kadang kita suka bingung kalau konfigurasi sudah tidak ada lagi.
konfigurasi
Konfigurasi server yang dipakai
Yak, intinya ada 5 mesin untuk tutorial kali ini. Saya menggunakan GNU/Linux Debian 9 karena itu standar sistem operasi UI. Untuk sistem operasi lain saya rasa tidak ada yang berbeda karena kali ini saya tidak menggunakan paket repositori.
Untuk memudahkan, pastikan kelima mesin ini memiliki berkas /etc/hosts yang berisi kelima host.
$ sudo tee -a  /etc/hosts << EOF
192.168.100.1   haproxy0-nyata
192.168.100.2   etcd0-nyata
192.168.100.3   pg1-nyata
192.168.100.4   pg2-nyata
192.168.100.5   pg3-nyata
EOF
Selanjutnya, akan dibuatkan etcd terlebih dahulu sebagai inti yang mengatur kluster.

ETCD

Aplikasi etcd adalah sebuah basisdata konfigurasi yang digunakan status. Aplikasi etcd tidak ada di repositori Debian 9. Saya mengunduh versi terbaru dari CoreOS dan memasang manual.
wget https://github.com/coreos/etcd/releases/download/v3.3.1/etcd-v3.3.1-linux-amd64.tar.gz
tar xvfz etcd-v3.3.1-linux-amd64.tar.gz
sudo cp etcd-v3.3.1-linux-amd64/etcd /usr/local/bin

Konfigurasi

Aplikasi etcd berisi satu binari. Untuk konfigurasi, buat manual.
$ sudo /etc/etcd.conf.yml << EOF
# This is the configuration file for the etcd server.

# Human-readable name for this member.
name: 'etcd0-nyata'

# Path to the data directory.
data-dir: /var/lib/etcd/data

# Path to the dedicated wal directory.
wal-dir: /var/lib/etcd/wal

# Number of committed transactions to trigger a snapshot to disk.
snapshot-count: 10000

# Time (in milliseconds) of a heartbeat interval.
heartbeat-interval: 100

# Time (in milliseconds) for an election to timeout.
election-timeout: 1000

# Raise alarms when backend size exceeds the given quota. 0 means use the
# default quota.
quota-backend-bytes: 0

# List of comma separated URLs to listen on for peer traffic.
listen-peer-urls: http://192.168.100.2:2380

# List of comma separated URLs to listen on for client traffic.
listen-client-urls: http://localhost:2379,http://192.168.100.2:2379

# Maximum number of snapshot files to retain (0 is unlimited).
max-snapshots: 5

# Maximum number of wal files to retain (0 is unlimited).
max-wals: 5

# Comma-separated white list of origins for CORS (cross-origin resource sharing).
cors: 

# List of this member's peer URLs to advertise to the rest of the cluster.
# The URLs needed to be a comma-separated list.
initial-advertise-peer-urls: http://192.168.100.2:2380

# List of this member's client URLs to advertise to the public.
# The URLs needed to be a comma-separated list.
advertise-client-urls: http://192.168.100.2:2379

# Discovery URL used to bootstrap the cluster.
discovery: 

# Valid values include 'exit', 'proxy'
discovery-fallback: 'proxy'

# HTTP proxy to use for traffic to discovery service.
discovery-proxy: 

# DNS domain used to bootstrap initial cluster.
discovery-srv: 

# Initial cluster configuration for bootstrapping.
initial-cluster: etcd0-scele=http://192.168.100.2:2380,

# Initial cluster token for the etcd cluster during bootstrap.
initial-cluster-token: 'etcd-nyata-cluster'

# Initial cluster state ('new' or 'existing').
initial-cluster-state: 'new'

# Reject reconfiguration requests that would cause quorum loss.
strict-reconfig-check: false

# Valid values include 'on', 'readonly', 'off'
proxy: 'off'

# Time (in milliseconds) an endpoint will be held in a failed state.
proxy-failure-wait: 5000

# Time (in milliseconds) of the endpoints refresh interval.
proxy-refresh-interval: 30000

# Time (in milliseconds) for a dial to timeout.
proxy-dial-timeout: 1000

# Time (in milliseconds) for a write to timeout.
proxy-write-timeout: 5000

# Time (in milliseconds) for a read to timeout.
proxy-read-timeout: 0

# Enable debug-level logging for etcd.
debug: false

# Specify a particular log level for each etcd package (eg: 'etcdmain=CRITICAL,etcdserver=DEBUG'.
log-package-levels: 

# Force to create a new one member cluster.
force-new-cluster: true
EOF

Layanan

Agar dapat dijalankan secara sistem, perlu dibuatkan layanan systemd secara manual.
$ sudo tee -a /etc/systemd/system/etcd.service << EOF
[Unit]
Description=etcd key-value store
Documentation=https://github.com/coreos/etcd
After=network.target

[Service]
User=etcd
Group=etcd
Type=notify
ExecStart=/bin/bash --login -c "/usr/local/bin/etcd --config-file /etc/etcd.conf.yml"
Restart=always
RestartSec=10s
LimitNOFILE=40000

[Install]
WantedBy=multi-user.target
EOF

Pengaktifan Layanan etcd

Perhatikan bahwa untuk contoh kali ini saya menggunakan akun etcd dan grup etcd. Praktik aman selalu jalankan layanan sebagai pengguna biasa, bukan root. Buat pengguna baru ini.
sudo adduser --system --home /var/lib/etcd --group etcd
Bagian terakhir dari etcd adalah mengaktifkan dan menjalankan layanan etcd.
sudo systemctl daemon-reload
sudo systemctl enable etcd
sudo systemctl start etcd
Baris daemon-reload adalah agar systemd membaca konfigurasi yang baru saja dibuat. Baris enable untuk mendaftarkan etcd sebagai layanan yang dijalankan otomatis saat mesin baru mulai. Baris terakhir untuk menjalankan layanan etcd.

PostgreSQL

Berbeda dengan tutorial yang lalu, saya akan membuat konfigurasi per mesin agar lebih menggambarkan apa yang terjadi. Sebelum memulai, saya asumsikan bahwa setiap mesin PostgreSQL pengguna root memiliki kunci SSH sehingga antar mesin bisa masuk tanpa kunci.
Cara paling gampang, di salah satu mesin buat kunci.
ssh-keygen -t ecdsa
Lalu, taruh kunci publik dan privat ke root. Saya asumsikan bahwa kita bekerja di mesin pg1-nyata.
# asumsi kerja di mesin pg1-nyata
sudo mkdir /root/.ssh/
sudo cp ~/.ssh/id_ecdsa /root/.ssh/
cat ~/.ssh/id_ecdsa.pub | sudo tee -a /root/.ssh/authorized_keys

# Transfer
scp ~/.ssh/id_ecdsa ~/.ssh/id_ecdsa.pub pg2-nyata:/tmp
scp ~/.ssh/id_ecdsa ~/.ssh/id_ecdsa.pub pg3-nyata:/tmp

# ke mesin pg2-nyata
ssh pg2-nyata
sudo mkdir /root/.ssh/
sudo cp ~/.ssh/id_ecdsa /root/.ssh/
cat ~/.ssh/id_ecdsa.pub | sudo tee -a /root/.ssh/authorized_keys
rm /tmp/id_ecdsa*
exit

# ke mesin pg3-nyata
ssh pg3-nyata
sudo mkdir /root/.ssh/
sudo cp ~/.ssh/id_ecdsa /root/.ssh/
cat ~/.ssh/id_ecdsa.pub | sudo tee -a /root/.ssh/authorized_keys
rm /tmp/id_ecdsa*
exit
Ini saya pasang secara manual. Biasanya untuk Vagrant, Proxmox, dan sejenisnya sudah menyediakan opsi pemasangan kunci SSH di konfigurasi/plugin mereka. Namun, untuk kelengkapan tutorial ini saya tuliskan saja manual. Saya sendiri sebenarnya hanya memasang satu mesin; memasang PostgreSQL; dan baru diklon menjadi dua mesin lainnya.

Pemasangan PostgreSQL

Saya kali ini menggunakan PostgreSQL yang saya kompilasi sendiri. Mengapa? Karena hasil kompilasi lebih irit dan saya mau ada variasi tulisan. Di blog saya ada kok cara-caranya untuk memasang versi repo.
Pemasangan PostgreSQL setiap mesin sama. Untuk memasang paket ketergantungan di setiap mesin jalankan:
sudo apt -y install build-essential libreadline-dev zlib1g-dev flex bison libxml2-dev libxslt-dev libssl-dev pkg-config libsystemd-dev
Unduh PostgreSQL. Saya memakai versi stabil terbaru, 10.2. Kebetulan juga, saya ada peladen cermin di samping ruangan:
wget http://kambing.ui.ac.id/postgresql/source/v10.2/postgresql-10.2.tar.bz2
tar xvfj postgresql-10.2.tar.bz2
cd postgresql-10.2
sed -i '/DEFAULT_PGSOCKET_DIR/s@/tmp@/run/postgresql@' src/include/pg_config_manual.h
./configure --prefix=/usr --with-icu --with-openssl --with-systemd --enable-thread-safety --docdir=/usr/share/doc/postgresql-10.2 CFLAGS="-O3 -march=native -mtune=native -pipe"
make -j$(nproc)
sudo make install
Saya melakukan optimasi CFLAGS untuk kompilasi. Hal ini karena saya tahu bahwa peladen di tempat saya itu homogen. Tapi, kalau misalnya Anda memasang di penyedia awan, sebaiknya  CFLAGS jangan disertakan.
Selanjutnya pemasangan Patroni.

Patroni

Patroni merupakan skrip Python. Untuk memasang Patroni, pastikan Python PIP dipasang. Saya memilih Python3. Namun, biasanya yang digunakan Python2. Saya memakai Python3 karena saya keren.
sudo apt install python3-pip
sudo pip3 install --upgrade setuptools
Pasang Patroni dan plugin etcd-nya.
sudo pip3 install psycopg2-binary
sudo -E pip3 install patroni[etcd]
Buat pengguna postgres
sudo adduser --system --home /var/lib/postgresql --group postgres
Buatkan layanan sistem.
$ 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/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
Selanjutnya, buat konfigurasi per mesin.

Konfigurasi Per Mesin

Buat konfigurasi per mesin /etc/patroni.yml
scope: postgres
namespace: /pg-nyata/
name: pg1-nyata
 
restapi:
    listen: 192.168.100.3:8008
    connect_address: 192.168.100.3:8008
 
etcd:
    host: 192.168.100.2: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.168.100.3/0 md5
    - host replication replicator 192.168.100.4/0 md5
    - host replication replicator 192.168.100.5/0 md5
    - host all all 0.0.0.0/0 md5
 
    users:
        admin:
            password: aiwaQuaeHuojeuyai2fiemai6Reeneix
            options:
                - createrole
                - createdb
 
postgresql:
    listen: 192.168.100.3:5432
    connect_address: 192.168.100.3:5432
    data_dir: /var/lib/postgresql/10.2-patroni
    pgpass: /tmp/pgpass
    authentication:
        replication:
            username: replicator
            password: zee0ohjisai5ohCohsaegho5gaeN8Xei
        superuser:
            username: postgres
            password: saichae9Aich0xeen2Otethaduphiepo
    parameters:
        unix_socket_directories: '.'
 
tags:
    nofailover: false
    noloadbalance: false
    clonefrom: false
    nosync: false
Contoh konfigurasi yang tertulis untuk mesin pg1-nyata. Untuk pg2-nyata dan pg3-nyata ubah baris ke-3 name dengan nama mesin, dan setiap baris listen dan connect_address dengan IP per mesin.
Contoh perbedaan pg1-nyata dan pg2-nyata.
$ diff pg{1,2}-nyata/etc/patroni.yml -u
--- pg1-nyata/etc/patroni.yml   2018-03-08 10:03:26.502995392 +0700
+++ pg2-nyata/etc/patroni.yml   2018-03-08 10:08:35.869743378 +0700
@@ -1,14 +1,14 @@
 scope: postgres
 namespace: /pg-nyata/
-name: pg1-nyata
- 
+name: pg2-nyata
+
 restapi:
-    listen: 192.168.100.3:8008
-    connect_address: 192.168.100.3:8008
- 
+    listen: 192.168.100.4:8008
+    connect_address: 192.168.100.4:8008
+
 etcd:
     host: 192.168.100.2:2379
- 
+
 bootstrap:
     dcs:
         ttl: 30
@@ -17,28 +17,28 @@
         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.168.100.3/0 md5
     - host replication replicator 192.168.100.4/0 md5
     - host replication replicator 192.168.100.5/0 md5
     - host all all 0.0.0.0/0 md5
- 
+
     users:
         admin:
             password: aiwaQuaeHuojeuyai2fiemai6Reeneix
             options:
                 - createrole
                 - createdb
- 
+
 postgresql:
-    listen: 192.168.100.3:5432
-    connect_address: 192.168.100.3:5432
+    listen: 192.168.100.4:5432
+    connect_address: 192.168.100.4:5432
     data_dir: /var/lib/postgresql/10.2-patroni
     pgpass: /tmp/pgpass
     authentication:
@@ -50,7 +50,7 @@
             password: saichae9Aich0xeen2Otethaduphiepo
     parameters:
         unix_socket_directories: '.'
- 
+
 tags:
     nofailover: false
     noloadbalance: false
Semoga dengan ini tidak ada salah ganti atau terlewat.

Pengaktifan Layanan Patroni

Setelah konfigurasi dan unit layanan Patroni terpasang, layanan Patroni sudah bisa dijalankan. Untuk setiap mesin, jalankan:
sudo systemctl daemon-reload
sudo systemctl enable patroni
sudo systemctl start patroni
Satu langkah lagi.

HAProxy

Bagian yang paling mudah saya salin saja, ya, perintahnya.
sudo apt install haproxy
Konfigurasi:
$ 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.168.100.3_5432 192.168.100.3:5432 maxconn 100 check port 8008
    server postgresql_192.168.100.4_5432 192.168.100.4:5432 maxconn 100 check port 8008
    server postgresql_192.168.100.5_5432 192.168.100.5:5432 maxconn 100 check port 8008
EOF
Lalu,
sudo systemctl restart haproxy
Selesai.

Bacaa