ตั้งค่า Keepalived High Availability บน VPS ด้วย VRRP
Keepalived คือซอฟต์แวร์ Open Source สำหรับทำ High Availability (HA) บน Linux โดยใช้โปรโตคอล VRRP (Virtual Router Redundancy Protocol) — สร้าง Virtual IP ที่จะย้ายตัวเองไปยังเซิร์ฟเวอร์ตัวสำรองโดยอัตโนมัติภายในไม่กี่วินาที หากเซิร์ฟเวอร์หลักล้มเหลว
บทความนี้จะพาคุณตั้งค่า Keepalived แบบ Master/Backup บน VPS 2 ตัว พร้อม health check สำหรับ Nginx หรือ HAProxy เพื่อให้ระบบมี uptime สูงสุด
Keepalived คืออะไร และทำงานอย่างไร
VRRP เป็นมาตรฐาน RFC 3768/5798 ที่กำหนดให้กลุ่มเราเตอร์/เซิร์ฟเวอร์แชร์ Virtual IP (VIP) ตัวเดียวกัน โดยมีเพียงหนึ่งตัว (Master) ที่รับ traffic จริงในขณะใดขณะหนึ่ง ตัวอื่น (Backup) คอยฟัง heartbeat — ถ้า Master เงียบไปนานเกิน threshold, Backup จะ promote ตัวเองขึ้นเป็น Master ทันที
| บทบาท | คำอธิบาย | Priority |
|---|---|---|
| Master | รับ traffic ผ่าน Virtual IP | สูงกว่า (เช่น 101) |
| Backup | Standby, คอยรับ VIP หาก Master ล่ม | ต่ำกว่า (เช่น 100) |
เตรียม VPS ก่อนติดตั้ง
ต้องการ VPS อย่างน้อย 2 ตัวที่อยู่ใน Network เดียวกัน (same subnet หรือ private network):
- node1 (Master): IP
192.168.1.10 - node2 (Backup): IP
192.168.1.11 - Virtual IP:
192.168.1.100(VIP ที่ client จะเชื่อมต่อ)
ติดตั้ง Keepalived
ทำทั้งสองเซิร์ฟเวอร์ (node1 และ node2):
Ubuntu / Debian
sudo apt update
sudo apt install -y keepalived
CentOS / AlmaLinux / Rocky Linux
sudo dnf install -y keepalived
เปิดใช้ IP nonlocal bind (สำคัญมาก)
Keepalived ต้องการ bind บน Virtual IP ซึ่งยังไม่ได้ assign บน interface — ต้องเปิด kernel parameter นี้ก่อน:
# เพิ่มใน /etc/sysctl.conf
echo "net.ipv4.ip_nonlocal_bind = 1" | sudo tee -a /etc/sysctl.conf
sudo sysctl -p
ตั้งค่า Keepalived บน Master (node1)
sudo nano /etc/keepalived/keepalived.conf
global_defs {
router_id node1
script_user root
enable_script_security
}
vrrp_script chk_nginx {
script "/usr/bin/systemctl is-active nginx"
interval 2 # ตรวจทุก 2 วินาที
weight -20 # ลด priority 20 เมื่อ nginx ล้มเหลว
fall 2 # ต้องล้มเหลว 2 ครั้งติดกันก่อน failover
rise 2 # ต้องสำเร็จ 2 ครั้งติดกันก่อน recovery
}
vrrp_instance VI_1 {
state MASTER
interface eth0 # ชื่อ interface ของเซิร์ฟเวอร์ (ตรวจด้วย ip a)
virtual_router_id 51 # ต้องตรงกันทั้งสองเซิร์ฟเวอร์ (1-255)
priority 101 # Master ต้องสูงกว่า Backup
advert_int 1 # ส่ง heartbeat ทุก 1 วินาที
authentication {
auth_type PASS
auth_pass MySecretPass2026 # รหัสผ่านต้องตรงกันทั้งสองฝั่ง
}
virtual_ipaddress {
192.168.1.100/24 dev eth0 # Virtual IP
}
track_script {
chk_nginx
}
}
ตั้งค่า Keepalived บน Backup (node2)
sudo nano /etc/keepalived/keepalived.conf
global_defs {
router_id node2
script_user root
enable_script_security
}
vrrp_script chk_nginx {
script "/usr/bin/systemctl is-active nginx"
interval 2
weight -20
fall 2
rise 2
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51 # ต้องตรงกับ Master
priority 100 # Backup ต้องต่ำกว่า Master
advert_int 1
authentication {
auth_type PASS
auth_pass MySecretPass2026 # ต้องตรงกัน
}
virtual_ipaddress {
192.168.1.100/24 dev eth0
}
track_script {
chk_nginx
}
}
เริ่มต้นและเปิดใช้ Keepalived
รันบนทั้งสองเซิร์ฟเวอร์:
sudo systemctl enable --now keepalived
sudo systemctl status keepalived
ตั้งค่า Notify Script (แจ้งเตือนเมื่อ Failover)
สร้าง script เพื่อรับการแจ้งเตือนเมื่อ state เปลี่ยน (ส่ง email หรือ log):
sudo nano /etc/keepalived/notify.sh
#!/bin/bash
TYPE=$1
NAME=$2
STATE=$3
case $STATE in
"MASTER")
echo "[$(date)] ${NAME} became MASTER" >> /var/log/keepalived-notify.log
;;
"BACKUP")
echo "[$(date)] ${NAME} became BACKUP" >> /var/log/keepalived-notify.log
;;
"FAULT")
echo "[$(date)] ${NAME} entered FAULT state" >> /var/log/keepalived-notify.log
;;
esac
sudo chmod +x /etc/keepalived/notify.sh
เพิ่มใน vrrp_instance ทั้งสองฝั่ง:
notify /etc/keepalived/notify.sh
Health Check สำหรับ HAProxy แทน Nginx
หากใช้ HAProxy แทน Nginx ให้เปลี่ยน script เป็น:
vrrp_script chk_haproxy {
script "/usr/bin/systemctl is-active haproxy"
interval 2
weight -20
fall 2
rise 2
}
หรือตรวจด้วย TCP port แทน (ยืดหยุ่นกว่า):
vrrp_script chk_port {
script "/bin/bash -c 'echo > /dev/tcp/127.0.0.1/80'"
interval 3
weight -20
fall 3
rise 2
timeout 2
}
ตั้งค่า Firewall สำหรับ VRRP
VRRP ใช้ IP Protocol 112 (multicast 224.0.0.18) — ต้องเปิด firewall:
UFW
sudo ufw allow proto vrrp
# หรือกำหนด IP เฉพาะ
sudo ufw allow from 192.168.1.11 proto vrrp
iptables
sudo iptables -A INPUT -p vrrp -j ACCEPT
sudo iptables -A OUTPUT -p vrrp -j ACCEPT
firewalld (CentOS/AlmaLinux)
sudo firewall-cmd --add-protocol=vrrp --permanent
sudo firewall-cmd --reload
ตรวจสอบว่า Keepalived ทำงานถูกต้อง
# ดูว่า Virtual IP อยู่บน interface ไหน (ควรอยู่บน node1/Master)
ip addr show eth0 | grep 192.168.1.100
# ดู log ของ keepalived
journalctl -u keepalived -f
# ดู state ปัจจุบัน
sudo cat /tmp/keepalived.pid # หรือดูจาก systemctl
sudo systemctl status keepalived
# ทดสอบ failover — หยุด keepalived บน Master
sudo systemctl stop keepalived # บน node1
# แล้วตรวจว่า VIP ย้ายไป node2
ip addr show eth0 | grep 192.168.1.100 # บน node2 (ควรปรากฏ)
# Ping VIP ต่อเนื่องระหว่างทดสอบ
ping 192.168.1.100
tcpdump -i eth0 -p vrrp เพื่อดู VRRP heartbeat packets ระหว่าง node1 และ node2 — ช่วย debug เมื่อ VIP ไม่ย้ายตามที่คาดแก้ปัญหาที่พบบ่อย
Error: "VRRP_Script(chk_nginx) timed_out"
Script ที่ใช้ตรวจสอบ service ทำงานช้าเกินกำหนด timeout เริ่มต้น (5 วินาที)
# เพิ่ม timeout ใน vrrp_script
vrrp_script chk_nginx {
script "/usr/bin/systemctl is-active nginx"
interval 2
weight -20
timeout 5 # เพิ่มบรรทัดนี้
fall 2
rise 2
}
Error: "Keepalived_vrrp: ip address associated with VRID not present in MASTER advert"
virtual_router_id ของทั้งสองเซิร์ฟเวอร์ไม่ตรงกัน หรือมี Keepalived instance อื่นใน subnet ที่ใช้ VRID เดียวกัน
# ตรวจสอบ VRID ทั้งสองฝั่ง
sudo grep virtual_router_id /etc/keepalived/keepalived.conf
# ต้องตรงกันเสมอ และเปลี่ยนเป็นตัวเลขที่ไม่ซ้ำกับระบบอื่น (1-255)
Error: "Keepalived_vrrp: VRRP_Instance(VI_1) Sending gratuitous ARPs on eth0 for 192.168.1.100" แต่ client ยังต่อไม่ได้
ARP cache ของ client ยังเก่าอยู่ — ทำ ARP flush:
# บน client หรือ router
arp -d 192.168.1.100
# บน Linux ทำ ARP request ใหม่
arping -c 3 192.168.1.100
Error: "Can't open PID file /run/keepalived.pid"
Permission issue หรือ Keepalived ไม่มีสิทธิ์เขียน /run/
# แก้ไข service unit
sudo systemctl edit keepalived --force
# เพิ่ม:
[Service]
RuntimeDirectory=keepalived
RuntimeDirectoryMode=0755
sudo systemctl daemon-reload
sudo systemctl restart keepalived
Error: VIP ไม่ย้ายกลับมาที่ Master หลังจาก Master กลับมาออนไลน์ (Preemption)
โดยค่าเริ่มต้น Keepalived จะ preempt (ย้าย VIP กลับ Master) เมื่อ Master กลับมา ถ้าไม่ต้องการพฤติกรรมนี้:
# เพิ่มใน vrrp_instance บน Master
nopreempt # VIP จะไม่ย้ายกลับอัตโนมัติ
# หรือกำหนด delay
preempt_delay 30 # รอ 30 วินาทีก่อน preempt
คำถามที่พบบ่อย
Keepalived ต่างจาก HAProxy อย่างไร?
Keepalived ทำ IP-level failover — ย้าย Virtual IP จาก node หนึ่งไปอีก node เมื่อล้มเหลว ส่วน HAProxy ทำ application-level load balancing — กระจาย request ไปยัง backend หลายตัว ทั้งสองมักถูกใช้ร่วมกัน: Keepalived ดูแล VIP ของ HAProxy และ HAProxy กระจาย traffic ไปยัง web server
Keepalived รองรับกี่ Virtual IP ต่อ instance?
รองรับได้หลาย VIP ต่อหนึ่ง vrrp_instance เพียงแค่ระบุหลายบรรทัดใน virtual_ipaddress {}:
virtual_ipaddress {
192.168.1.100/24
192.168.1.101/24
10.0.0.50/24
}
ใช้ Keepalived กับ Cloud VPS ทั่วไปได้ไหม?
ได้ แต่มีข้อจำกัดสำหรับ Public IP — Cloud provider ส่วนใหญ่ไม่ให้ broadcast VRRP multicast บน Public Network เพราะ security policy จึงต้องใช้ VIP บน Private Network แทน แล้วให้ Load Balancer ของ Cloud รับ Public IP มาชี้ที่ VIP อีกที หรือใช้ Floating IP ของ provider ร่วมกับ API script