Triển khai dịch vụ High Available với Keepalived + HAproxy trên server Ubuntu

High Available có tên tiếng Việt thân thiện là " tính sẵn sàng cao" - ám chỉ các dịch vụ, ứng dụng hoặc một thứ gì đó luôn sẵn sàng hoạt động phục vụ người dùng. Trong thời buổi công nghệ thông tin bùng phát như hiện nay, một dịch vụ có thể có đến hàng chục nhà cung cấp khác nhau. Do vậy, để tăng năng lực cạnh tranh cũng như hiệu quả kinh doanh thì ngoài dịch vụ tốt ra, các nhà cung cấp còn phải đảm bảo yếu tố "luôn luôn sẵn sàng phục vụ" của dịch vụ mà mình cung cấp.

Bạn cứ thử tưởng tượng, với một dịch vụ mail chẳng hạn. Bạn vốn là user ruột của dịch vụ [email protected] gì gì đó ,bỗng dưng 1 ngày đẹp trời sáng trăng nọ, bạn đang cần nhận một email từ khách hàng hoặc bạn bè. Thế mà cái dịch vụ mail kia bỗng dưng dở chứng 404 với 505 các kiểu con đà điểu ! Bạn không thể nào check được cái mail mà mình cần. Rồi bạn liên lạc với khách hàng, bạn bè của bạn và than phiền rằng mình không thể check được mail do bị làm sao ấy chả biết ! Bạn bè, khách hàng của bạn lập tức cho bạn lời khuyên rằng " Sao ông không dùng cái mail xyz ấy, nó tốt hơn nhiều, chả bao giờ bị thế đâu !! ". Và thế là a-lê-hấp , anh dịch vụ mail [email protected] bỗng dưng mất một user trung thành vào tay anh [email protected] vì lý do mail server bị chuột cắn mất dây =)).

Để phòng tránh các sự cố làm gián đoạn dịch vụ như trên, tất nhiên chúng ta phải tiến hành diệt chuột tận gốc trong khu vực đặt server =)). Ngoài chuột ra thì còn có ty tỷ lý do khác khiến cho dịch vụ chúng ta bị gián đoạn. Lúc này nguyên tắc bất hủ "không bao giờ để trứng trong cùng một rổ" được áp dụng tối đa. Ở bài viết trước, mình đã hướng dẫn các bạn cách tách riêng các server ra và cân bằng tải cũng như fail-over với HAproxy . Các bạn có thể tham khảo tại đây.

Trong mô hình mình triển khai ở bài viết trước như trên. Rất dễ nhận ra điểm yếu của hệ thống nằm ở anh Loadbalancer HAproxy ! Nếu chẳng may anh ấy đột tử thì xem như việc tăng số lượng webserver phía sau gần như không còn ý nghĩa gì trong việc tăng khả năng chịu lỗi(fail-over) của dịch vụ. Vậy, giải pháp nâng cấp cho mô hình trên tất nhiên sẽ là xây dựng thêm nhiều anh HAproxy nữa. Khi xây dựng thêm các Loadbalancer cùng chạy song song thì lại nảy sinh ra một vấn đề khác - đó là user sẽ truy cập vào đâu ?? Cùng một dịch vụ, chúng ta không thể nào đưa cho user 2 IP truy cập được. Để giải quyết bài toán đó, chúng ta có 1 giải pháp đó là sử dụng Virtual IP ( IP ảo) để user truy cập vào. Các Loadbalacer của chúng ta lúc này sẽ chỉ hoạt động với cùng một V-IP. Có khá nhiều giải pháp cung cấp tính năng Virtual IP như UCARP , Keepalived... Và trong khuôn khổ bài viết này, mình sẽ giới thiệu các bạn về Keepalived.

Giới thiệu Keepalived.

Keepalived (Nghe như lời 1 bài hát của nhóm Scorpions =))) là một dạnh định tuyến "mềm" được viết bằng C. Mục đích để cung cấp các tính năng Loadbalacing và High available cho các hệ thống Linux. Phiên bản đầu tiên được ra đời tháng 12-2000, đến nay đã trải qua 16 năm phát triển. Các bạn có thể xem thêm tại www.keepalived.org Để dễ hiểu về tính năng cũng như cách hoạt động của keepalived, chúng ta sẽ đi thẳng vào phần cài đặt và config.

Install và config.

Vì vấn đề con lap cùi không thể chạy nhiều máy ảo được , và chủ yếu là ..... lười nên mình sẽ chỉ dựng lên 2 server, với mỗi server mình sẽ cài đặt cả 3 dịch vụ keepalived , HAproxy và Apache2. Mô hình như sau :

– Test1
Hostname: test1
OS: Ubuntu server 16.04
Service : Keepalived + HAproxy + Apahce2
Private IP: 172.17.3.98

– Test2
Hostname: test2
OS: Ubuntu server 16.04
Service : Keepalived + HAproxy + Apache2
Private IP: 172.17.3.99

Cài đặt các máy chủ :

Trên mỗi máy chủ, chúng ta lần lượt cài đặt các dịch vụ sau :

sudo apt-get update
sudo apt-get install apache2 
sudo apt-get keepalived 
sudo apt-get install haproxy

#hoặc lười gì gõ luôn

sudo apt-get install apache2 keepalived haproxy

Sau khi cài đặt , có thể kiểm tra các phiên bản đã cài bằng các câu lệnh :

apache2 --v
haproxy --v
keepalived --v

Lần lượt trên từng máy test1 và test2, các bạn thay đổi nội dung trang index.html mặc định trong /var/www/html/index.html để chuẩn bị cho bước test cho dễ 😄 Cụ thể mình làm như sau : Trên máy test1

sudo sh -c "test1 : 172.17.3.98  >> /var/www/index.html"

Trên máy test2

sudo sh -c "test2 : 172.17.3.99 >> /var/www/index.html"

Lần lượt truy cập vào 2 địa chỉ trên bằng web browser để xem kết quả nhé .

Config Keepalived :

Bước 1 :

Dịch vụ Keepalived sẽ giúp chúng ta tạo 1 Virtual IP để dùng cho máy chủ, nói một cách nôm na là máy chủ sẽ sử dụng IP do chúng ta tự định nghĩa bằng Keepalived chứ không phải dùng IP trên interface của máy chủ (được cấp bởi 1 DHCP nào đó hay do chúng ta tự gán.). Để làm việc này, chúng ta cần vào file /etc/sysctl.conf và thêm dòng sau vào file sysctl.conf :

net.ipv4.ip_nonlocal_bind=1

Sau đó các bạn lưu lại và thoát ra. Tiếp tục thực thi câu lệnh được gán vào bằng cách restart server hoặc chạy câu lệnh sau :

[email protected]ubuntu:~$ sudo sysctl -p

Thực hiện việc này lần lượt trên cả 2 máy chủ nhé !

Bước 2 : Config Keepalived

File config của Keepalived sẽ được lưu ở /etc/keepalived/keepalived.conf .Lưu ý nếu file chưa có sẵn thì tạo file mới nhé. Bạn có thể dùng bất cứ trình biên soạn text nào trên Linux đều được. Ở đây mình sẽ dùng nano.

Trên server test1

[email protected]ubuntu:~$ sudo nano /etc/keepalived/keepalived.conf

Điền vào file nội dung sau :

global_defs {
  router_id test1                            #khai báo route_id của keepalived
}
vrrp_script chk_haproxy {
  script "killall -0 haproxy"
  interval 2
  weight 2
}
vrrp_instance VI_1 {
  virtual_router_id 51
  advert_int 1
  priority 100
  state MASTER
  interface ens33                            #thông tin tên interface của server, bạn dùng lệnh `ifconfig` để xem và điền cho đúng
  virtual_ipaddress {
    172.17.3.222 dev ens33           #Khai báo Virtual IP cho interface tương ứng
  }
 authentication {
     auth_type PASS
     auth_pass 123456                    #Password này phải khai báo giống nhau giữa các server keepalived
     }
  track_script {
    chk_haproxy
  }
}

Tương tự trên máy test2

global_defs {
  router_id test2
}
vrrp_script chk_haproxy {
  script "killall -0 haproxy"
  interval 2
  weight 2
}
vrrp_instance VI_1 {
  virtual_router_id 51
  advert_int 1
  priority 99
  state BACKUP
  interface ens33
  virtual_ipaddress {
    172.17.3.222 dev ens33
  }
authentication {
        auth_type PASS
        auth_pass 123456
        }
track_script {
    chk_haproxy
    }
  }

Sau khi khai báo file keepalived.conf ở cả 2 máy thì nhớ sudo service keepalived start nhé.

Cần lưu ý ở 2 khai báo trên : Với máy test1

vrrp_instance VI_1 {
  virtual_router_id 51
  advert_int 1
  priority 100
  state MASTER
  interface ens33

máy test2

vrrp_instance VI_1 {
  virtual_router_id 51
  advert_int 1
  priority 99
  state BACKUP
  interface ens33

Ta thấy khai báo với test1 stateMASTER , priority 100 Khác với test2 state BACKUPpriority 99

Khai báo trên có ý nghĩa khởi tạo ban đầu máy test1 sẽ là MASTER và được quyền giữ VIP 172.17.3.222 được gán vào interface ens33. Ta có thể kiểm tra với câu lệnh ip addr sh sẽ thấy như sau : máy test1

[email protected]ubuntu:/var/log$ ip addr sh
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  link/ether 00:0c:29:f5:30:5b brd ff:ff:ff:ff:ff:ff
  inet 172.17.3.98/24 brd 172.17.3.255 scope global ens33
     valid_lft forever preferred_lft forever
  inet 172.17.3.222/32 scope global ens33
     valid_lft forever preferred_lft forever
  inet6 fe80::20c:29ff:fef5:305b/64 scope link 
     valid_lft forever preferred_lft forever

máy test2

[email protected]ubuntu:/var/log$ ip addr sh
2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
  link/ether 00:0c:29:21:87:40 brd ff:ff:ff:ff:ff:ff
  inet 172.17.3.99/24 brd 172.17.3.255 scope global ens33
     valid_lft forever preferred_lft forever
  inet6 fe80::20c:29ff:fe21:8740/64 scope link 
     valid_lft forever preferred_lft forever

Virtual IP chỉ được gán vào interface ens33 của máy test1 chứ không được gán vào máy test2 dù ta đã khai báo trên cả 2 máy. Vì hiện tại khởi tạo ban đầu máy test1 giữ vai trò MASTER

Tiếp theo, với các khai báo vrrp_script trên cả 2 máy

vrrp_script chk_haproxy {
script "killall -0 haproxy"           #check pid của dịch vụ haproxy có tồn tại hay không
interval 2                                     #thời gian lặp lại đoạn script đơn vị là second
weight 2                                      #trọng số khấu trừ priority 2
}
track_script {
  chk_haproxy                             #khai báo tên đoạn script 
  }

Trong file cấu hình Keepalived trên của 2 máy test1test2 đều có track_script - có nghĩa là cả 2 server đều sẽ tiến hành chạy đoạn script check trạng thái của dịch vụ process ID (PID) được khai báo trong script ( ở đây mình khai báo check service haproxy). Giả sử service haproxy trên test1 (được khởi tạo ban đầu với state MASTERpriotiry 100) vì một lý do nào đó không hoạt động, Keepalived sẽ trừ trọng số (priority 100-2=98) trên máy test1. Lúc này priority của test1 sẽ là 98 và nhỏ hơn priority=99 được khai báo ban đầu ở test2 , do đó Keepalived sẽ chuyển trạng thái của test2 từ BACKUP thành MASTERtest2 sẽ được giữ VIP đã khai báo.

Test config Keepalived

Để dễ hình dung, chúng ta sẽ cùng đi check trạng thái ban đầu của cả 2 máy, và thử tắt dịch vụ haproxy trên máy test1 xem chuyện gì sẽ xảy ra nhé.

Trên máy test1

[email protected]ubuntu:~$ sudo tail /var/log/syslog -n 100

Cùng xem kết quả trả về

Jan 24 21:58:28 ubuntu Keepalived_vrrp[21757]: VRRP_Script(chk_haproxy) succeeded
Jan 24 21:58:29 ubuntu Keepalived_vrrp[21757]: VRRP_Instance(VI_1) Transition to MASTER STATE
Jan 24 21:58:29 ubuntu Keepalived_vrrp[21757]: VRRP_Instance(VI_1) Received higher prio advert
Jan 24 21:58:29 ubuntu Keepalived_vrrp[21757]: VRRP_Instance(VI_1) Entering BACKUP STATE
Jan 24 21:58:30 ubuntu Keepalived_vrrp[21757]: VRRP_Instance(VI_1) forcing a new MASTER election
Jan 24 21:58:30 ubuntu Keepalived_vrrp[21757]: VRRP_Instance(VI_1) forcing a new MASTER election
Jan 24 21:58:31 ubuntu Keepalived_vrrp[21757]: VRRP_Instance(VI_1) Transition to MASTER STATE
Jan 24 21:58:32 ubuntu Keepalived_vrrp[21757]: VRRP_Instance(VI_1) Entering MASTER STATE

Tương tự trên máy test2

[email protected]ubuntu:~$ sudo tail /var/log/syslog -n 100
Jan 24 21:58:07 ubuntu Keepalived_vrrp[11335]: VRRP_Instance(VI_1) Dropping received VRRP packet...
Jan 24 21:58:28 ubuntu Keepalived_vrrp[11335]: receive a 0 auth, expecting 1!
Jan 24 21:58:28 ubuntu Keepalived_vrrp[11335]: bogus VRRP packet received on ens33 !!!
Jan 24 21:58:28 ubuntu Keepalived_vrrp[11335]: VRRP_Instance(VI_1) Dropping received VRRP packet...
Jan 24 21:58:29 ubuntu Keepalived_vrrp[11335]: VRRP_Instance(VI_1) Received lower prio advert, forcing new election
Jan 24 21:58:29 ubuntu Keepalived_vrrp[11335]: VRRP_Instance(VI_1) Received lower prio advert, forcing new election
Jan 24 21:58:30 ubuntu Keepalived_vrrp[11335]: VRRP_Instance(VI_1) Received higher prio advert
Jan 24 21:58:30 ubuntu Keepalived_vrrp[11335]: VRRP_Instance(VI_1) Entering BACKUP STATE

Bây giờ mình sẽ tắt HAproxy trên máy test1

[email protected]ubuntu:~$ sudo service haproxy stop

Và check lại nhé test1

  [email protected]ubuntu:~$ sudo tail /var/log/syslog -n 100
  
Jan 24 22:46:13 ubuntu systemd[1]: Stopping HAProxy Load Balancer...
Jan 24 22:46:13 ubuntu systemd[1]: Stopped HAProxy Load Balancer.
Jan 24 22:46:14 ubuntu Keepalived_vrrp[21757]: VRRP_Script(chk_haproxy) failed

Check lại máy test2 nào

    [email protected]ubuntu:~$ sudo tail /var/log/syslog -n 100
    
 Jan 24 21:58:28 ubuntu Keepalived_vrrp[11335]: VRRP_Instance(VI_1) Dropping received VRRP packet...
Jan 24 21:58:29 ubuntu Keepalived_vrrp[11335]: VRRP_Instance(VI_1) Received lower prio advert, forcing new election
Jan 24 21:58:29 ubuntu Keepalived_vrrp[11335]: VRRP_Instance(VI_1) Received lower prio advert, forcing new election
Jan 24 21:58:30 ubuntu Keepalived_vrrp[11335]: VRRP_Instance(VI_1) Received higher prio advert
Jan 24 21:58:30 ubuntu Keepalived_vrrp[11335]: VRRP_Instance(VI_1) Entering BACKUP STATE
Jan 24 22:17:01 ubuntu CRON[19914]: (root) CMD (   cd / && run-parts --report /etc/cron.hourly)
Jan 24 22:46:15 ubuntu Keepalived_vrrp[11335]: VRRP_Instance(VI_1) forcing a new MASTER election
Jan 24 22:46:15 ubuntu Keepalived_vrrp[11335]: VRRP_Instance(VI_1) forcing a new MASTER election
Jan 24 22:46:17 ubuntu Keepalived_vrrp[11335]: VRRP_Instance(VI_1) Transition to MASTER STATE
Jan 24 22:46:18 ubuntu Keepalived_vrrp[11335]: VRRP_Instance(VI_1) Entering MASTER STATE

Check luôn interface của máy test2

    [email protected]ubuntu:~$ ip addr sh
    2: ens33: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc pfifo_fast state UP group default qlen 1000
    link/ether 00:0c:29:21:87:40 brd ff:ff:ff:ff:ff:ff
    inet 172.17.3.99/24 brd 172.17.3.255 scope global ens33
       valid_lft forever preferred_lft forever
    inet 172.17.3.222/32 scope global ens33
       valid_lft forever preferred_lft forever
    inet6 fe80::20c:29ff:fe21:8740/64 scope link 
       valid_lft forever preferred_lft forever

Chúng ta thấy ở trạng thái ban đầu, máy test1 sẽ là MASTER STATE trong khi máy test2 sẽ là BACKUP STATE. Sau khi tắt service HAproxy trên máy test1 thì test2 đã trở thành MASTER và được gán Virtual IP trên interface của máy test2 , config keepalived đã hoàn thành.

Bây giờ chúng ta config nốt haproxy.

Config HAproxy

HAproxy ở bài viết này vì kiến thức hạn hẹp nên mình cũng xin phép được config basic vừa đủ dùng thôi nhá ^^. Nhìn chung config cũng không khác gì bài trước bao nhiêu. Lần lượt trên cả 2 máy chủ ta tiến hành chỉnh sửa file config của haproxy

sudo nano /etc/haproxy/haproxy.cfg

nội dung file như sau :

global
        daemon
        maxconn 256

    defaults
        mode http
        timeout connect 5000ms
        timeout client 50000ms
        timeout server 50000ms

    frontend http-in
        bind *:80
        default_backend app
    backend static
        balance roundrobin
        server static 172.17.3.222:80
    backend app
        balance roundrobin
        server test1 172.17.3.98:8080 check
        server test2 172.17.3.99:8080 check

Lưu ý : Các bạn nhớ chuyển listen port của apache2 thành port khác nhé. Vì mình cài tất cả các dịch vụ haproxy và http đều sử dụng port 80 trên cùng 1 máy nên sẽ conflict đó. Cụ thể ở đây mình sẽ chuyển default listen port của apache thành 8080 Mình sẽ chỉnh sửa lần lượt trên cả 2 server . Edit cả 2 file sau trên mỗi server sudo nano /etc/apache2/ports.confsudo nano /etc/apache2/sites-available/000-default.conf

Ok, vậy là đã hoàn tất phần cấu hình, chúng ta cùng test thành quả bằng cách truy cập vào V_IP nhé. Mở trình duyệt và gõ vào 172.17.3.222

F5 để thấy sự khác biệt

Kết :

Chúng ta đã hoàn thành triển khai một hệ thống có khả năng chịu lỗi cao. Bây giờ thì tha hồ đi nhậu mà không sợ dịch vụ bị down giữa chừng nữa nhé 😄 . Keepalived cũng như HAproxy là những công cụ miễn phí với rất nhiều tính năng. Trên đây mình chỉ thực hiện những config cơ bản của chúng thôi. Muôn chuyên sâu hơn thì chắc mình còn phải nghiên cứu thêm nhiều. Các bạn có thể tham khảo thêm ở trang chủ của keepalivedhaproxy nhé. Chúc các bạn ăn tết vui vẻ 😃