概要
- デフォルトゲートウェイのように1つしかIPを設定できない箇所を冗長化したい
- ロードバランサ、Proxyを冗長化したい
- active/standby型でフェイルオーバーした時にクライアント側でIPの変更を意識したくない
といったケースでVIP(仮想IP)を用いることで解決するのがVRRPです。
今回はそのVRRPを実現できるkeepalivedを紹介します。
環境
- Ubuntu 18.04
- keepalived v1.3.9
VRRPとは
VRRP(Virtual Router Redundancy Protocol)とはその名の通りルータを冗長化させるために考えられたプロトコルです。
複数のルータを外部からは仮想的な1つのルータとして扱うことでルータの冗長構成を実現します。
VIPを振られていた機器が故障してもVRRPによって別の機器にVIPが振られ直すので、クライアントは引き続きアクセスでき高可用性を担保できます。
検証
それでは検証を進めていきます。
システム図
システムのイメージは以下です。
接続元はvipへのアクセスを行います。
master側がダウンした場合は以下のようにvipが切り替わります。
接続元はvipを見ており、値自体は変わらないので設定の変更が不要です。
各種設定
Vagrantfile
# -*- mode: ruby -*- # vi: set ft=ruby : Vagrant.configure("2") do |config| config.vm.box = "ubuntu/bionic64" config.vm.define :master do |master| master.vm.network :private_network, ip: "192.168.33.10" end config.vm.define :slave do |slave| slave.vm.network :private_network, ip: "192.168.33.20" end end
ネットワーク周りの変更
vipのようなローカルシステムのデバイスに割り当てられていない、非ローカルのIPアドレスをバインドするためには以下の設定が必要です。
# echo 1 > /proc/sys/net/ipv4/ip_nonlocal_bind
上記は再起動で効果を失うので、再起動後も反映されるためには以下の値を/etc/sysctl.conf
に追記し
net.ipv4.ip_nonlocal_bind = 1
下記コマンドを実行します。
# sysctl -p
ref: 3.7. 「パケット転送および非ローカルバインディングの有効化」 Red Hat Enterprise Linux 7 | Red Hat Customer Portal
Keepalived & Nginxのインストール
$ sudo apt-get update $ sudo apt-get install keepalived nginx
keepalivedの設定
etc/keepalived/keepalived.conf
という新しいファイルを用意します。
各項目は
で説明されています。
今回の設定のポイントとしては以下です。
virtual_router_id
、auth_pass
を全ノード同じ値にするinterface
はUbuntuのネットワークインタフェースに合わせるpriority
はmaster側を高い値にするvirtual_ipaddress
はUbuntuのネットワークインタフェースと同じサブネットにする
master
global_defs { vrrp_garp_master_refresh 60 } vrrp_instance VI_1 { state MASTER interface enp0s8 virtual_router_id 51 priority 150 advert_int 1 authentication { auth_type PASS auth_pass 1234 } unicast_peer { 192.168.33.10 192.168.33.20 } virtual_ipaddress { 192.168.33.30 } }
slave
global_defs { vrrp_garp_master_refresh 60 } vrrp_instance VI_1 { state MASTER interface enp0s8 virtual_router_id 51 priority 100 advert_int 1 authentication { auth_type PASS auth_pass 1234 } unicast_peer { 192.168.33.10 192.168.33.20 } virtual_ipaddress { 192.168.33.30 } }
こちらのpriority
はmasterより低い100にしておきます。
設定ができたらkeepalivedを再起動しておきます。
$ sudo service keepalived restart
Nginxの設定
基本的に変更不要ですが、masterかslaveか分かりやすいようにindex.htmlを変更しておきます。
master
Welcome to nginx! -> Welcome to 192.168.33.10!
にしています。
<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to 192.168.33.10!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
slave
Welcome to nginx! -> Welcome to 192.168.33.20!
にしています。
<!DOCTYPE html> <html> <head> <title>Welcome to nginx!</title> <style> body { width: 35em; margin: 0 auto; font-family: Tahoma, Verdana, Arial, sans-serif; } </style> </head> <body> <h1>Welcome to 192.168.33.20!</h1> <p>If you see this page, the nginx web server is successfully installed and working. Further configuration is required.</p> <p>For online documentation and support please refer to <a href="http://nginx.org/">nginx.org</a>.<br/> Commercial support is available at <a href="http://nginx.com/">nginx.com</a>.</p> <p><em>Thank you for using nginx.</em></p> </body> </html>
動作確認
それでは動作確認してみます。
初期状態
keepalivedを再起動した段階ですでにmaster側ではvipが振られていることが確認できます。
master
$ ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 02:b7:1f:33:e9:24 brd ff:ff:ff:ff:ff:ff inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic enp0s3 valid_lft 83659sec preferred_lft 83659sec inet6 fe80::b7:1fff:fe33:e924/64 scope link valid_lft forever preferred_lft forever 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:cf:4a:47 brd ff:ff:ff:ff:ff:ff inet 192.168.33.10/24 brd 192.168.33.255 scope global enp0s8 valid_lft forever preferred_lft forever inet 192.168.33.30/32 scope global enp0s8 # ここ valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fecf:4a47/64 scope link valid_lft forever preferred_lft forever
slave
slave側はありません
$ ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 02:b7:1f:33:e9:24 brd ff:ff:ff:ff:ff:ff inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic enp0s3 valid_lft 83962sec preferred_lft 83962sec inet6 fe80::b7:1fff:fe33:e924/64 scope link valid_lft forever preferred_lft forever 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:51:37:d4 brd ff:ff:ff:ff:ff:ff inet 192.168.33.20/24 brd 192.168.33.255 scope global enp0s8 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fe51:37d4/64 scope link valid_lft forever preferred_lft forever
vipへアクセス
vip192.168.33.30
にアクセスすると、masterの方にリクエストが飛びます。
masterを落とす
master側が死んだと仮定するため、master側のkeepalivedを落としてみます。
$ sudo service keepalived stop
master
vipがNICから消えました。
$ ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 02:b7:1f:33:e9:24 brd ff:ff:ff:ff:ff:ff inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic enp0s3 valid_lft 83388sec preferred_lft 83388sec inet6 fe80::b7:1fff:fe33:e924/64 scope link valid_lft forever preferred_lft forever 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:cf:4a:47 brd ff:ff:ff:ff:ff:ff inet 192.168.33.10/24 brd 192.168.33.255 scope global enp0s8 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fecf:4a47/64 scope link valid_lft forever preferred_lft forever
slave
slave側にvipが付いていることが確認できます。フェイルオーバーできていますね。
$ ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 02:b7:1f:33:e9:24 brd ff:ff:ff:ff:ff:ff inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic enp0s3 valid_lft 83352sec preferred_lft 83352sec inet6 fe80::b7:1fff:fe33:e924/64 scope link valid_lft forever preferred_lft forever 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:51:37:d4 brd ff:ff:ff:ff:ff:ff inet 192.168.33.20/24 brd 192.168.33.255 scope global enp0s8 valid_lft forever preferred_lft forever inet 192.168.33.30/32 scope global enp0s8 # ここ valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fe51:37d4/64 scope link valid_lft forever preferred_lft forever
vipへアクセス
vip192.168.33.30
にアクセスすると、slaveの方にリクエストが飛びます。
masterが復旧すると
master側が復旧と仮定するため、masterのkeepalivedをもう一度起動してみます。
$ sudo service keepalived start
master
するとmasterにvipが戻りました。masterの方がslaveよりもpriorityが高いためですね。フェイルバック成功です。
$ ip a 1: lo: <LOOPBACK,UP,LOWER_UP> mtu 65536 qdisc noqueue state UNKNOWN group default qlen 1000 link/loopback 00:00:00:00:00:00 brd 00:00:00:00:00:00 inet 127.0.0.1/8 scope host lo valid_lft forever preferred_lft forever inet6 ::1/128 scope host valid_lft forever preferred_lft forever 2: enp0s3: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 02:b7:1f:33:e9:24 brd ff:ff:ff:ff:ff:ff inet 10.0.2.15/24 brd 10.0.2.255 scope global dynamic enp0s3 valid_lft 83117sec preferred_lft 83117sec inet6 fe80::b7:1fff:fe33:e924/64 scope link valid_lft forever preferred_lft forever 3: enp0s8: <BROADCAST,MULTICAST,UP,LOWER_UP> mtu 1500 qdisc fq_codel state UP group default qlen 1000 link/ether 08:00:27:cf:4a:47 brd ff:ff:ff:ff:ff:ff inet 192.168.33.10/24 brd 192.168.33.255 scope global enp0s8 valid_lft forever preferred_lft forever inet 192.168.33.30/32 scope global enp0s8 valid_lft forever preferred_lft forever inet6 fe80::a00:27ff:fecf:4a47/64 scope link valid_lft forever preferred_lft forever
その他
ARPテーブルのリフレッシュ
VIPによってクライアントからは冗長化されたサーバやルータを意識せずに利用できますが、フェイルオーバー後もARPテーブルが古いままだとパケットは古いMACアドレスの方(ダウンした方)に送られてしまいます。
そのためARPテーブルを更新する必要があります。
keepalivedではvrrp_garp_master_refresh
を設定することで、masterでいる間GARP(Gratuitous ARP)を送って他の機器に「VIP持ってるのは私ですよー」とブロードキャストで伝えてARPテーブルを更新してもらいます。
フェイルバックさせたくない
keepalived.confにnopreempt
を設定するとフェイルバックしなくなります。