2026年10月11日
2026年10月11日
keepalivedでVIPを使った冗長化設定方法|VRRPで2台のWebサーバーを自動切り替えする
keepalived を使うと、2台のサーバーで1つの仮想IPアドレス(VIP)を共有し、稼働中のサーバーが止まったときにもう1台へ VIP を自動で移せます。この記事では、VRRP の仕組みを押さえたうえで、Nginx が動く2台の Linux サーバーに keepalived を設定し、ヘルスチェック付きのフェイルオーバーを構成してテストするまでを説明します。オンプレミスや VPS の同一ネットワーク内で、Web サーバーやロードバランサーを冗長化したい人向けの内容です。
仕組み:VRRP と VIP
keepalived の冗長化は VRRP(Virtual Router Redundancy Protocol)に基づいています。2台のうち優先度(priority)の高い方が MASTER となって VIP を自分のインターフェースに付け、一定間隔で「自分は生きている」という広告(advertisement)を送ります。BACKUP 側は広告が一定時間届かなくなると、自分が MASTER に昇格して VIP を引き継ぎ、Gratuitous ARP で「この IP は今こちらの MAC アドレスにある」と周囲に知らせます。
クライアントは常に VIP に接続するので、切り替えの前後で接続先を変える必要がありません。ただし、keepalived が移すのはあくまで IP アドレスだけです。WordPress を2台で動かすなら、データベース、アップロードファイル(wp-content/uploads)、セッションやキャッシュの置き場所を、どちらのサーバーからも同じ内容で使えるように別途設計しておく必要があります。
クラウドでは前提が変わる
AWS、Google Cloud、Azure などのパブリッククラウドの多くは、マルチキャストや Gratuitous ARP による IP の移動をネットワーク側で受け付けません。これらの環境で VIP を移すには、クラウドの API でセカンダリ IP や Elastic IP を付け替える仕組みを組み合わせるか、マネージドのロードバランサーを使います。この記事は、同一の L2 ネットワーク(同じセグメント)にある2台を前提とします。
構成例
VIP : 192.168.10.100
web1 (MASTER 候補) : 192.168.10.11 eth0
web2 (BACKUP 候補) : 192.168.10.12 eth0
インターフェース名は環境によって ens3 や enp1s0 などになります。ip -br addr で確認し、以下の設定例を読み替えてください。
インストールとファイアウォール
# Debian / Ubuntu
sudo apt install keepalived
# RHEL / AlmaLinux / Rocky Linux
sudo dnf install keepalived
keepalived --version
VRRP の広告は TCP や UDP ではなく、IP プロトコル番号 112 のパケットです。ファイアウォールでこれを許可しないと、お互いの広告が届かず両方が MASTER になる「スプリットブレイン」が起きます。設定でつまずく原因として最も多いのがこの点です。
# firewalld の例
sudo firewall-cmd --permanent --add-rich-rule='rule protocol value="vrrp" accept'
sudo firewall-cmd --reload
# nftables / iptables を直接使っている場合は、相手サーバーからの
# IP プロトコル 112 を受け付けるルールを追加する
ヘルスチェック用スクリプト
keepalived 自体は「サーバーが動いているか」しか分かりません。Nginx が落ちているのに VIP を持ち続けると、サービスは止まったままです。そこで、Web サーバーが応答しているかを確かめるスクリプトを用意し、失敗したら優先度を下げて VIP を手放すようにします。
#!/bin/sh
# /usr/local/bin/check_web.sh
# ローカルの Nginx が 2 秒以内に応答すれば 0、それ以外は 1 を返す
curl -fsS -o /dev/null --max-time 2 http://127.0.0.1/ || exit 1
exit 0
sudo chown root:root /usr/local/bin/check_web.sh
sudo chmod 755 /usr/local/bin/check_web.sh
curl -f は 400 番台以上の応答で失敗扱いになり、リダイレクト(301 や 302)は成功として扱います。WordPress 側で専用のヘルスチェック用 URL を用意している場合は、そちらを指定する方が正確です。プロセスの有無だけを見る pidof nginx でも動きますが、プロセスは生きていても応答できない状態を見逃します。
keepalived の設定
設定ファイルは /etc/keepalived/keepalived.conf です。既存のファイルがあれば、先にバックアップを取っておきます。まず web1 の設定です。
global_defs {
router_id web1
enable_script_security
script_user root
}
vrrp_script chk_web {
script "/usr/local/bin/check_web.sh"
interval 2 # 2秒ごとに実行
timeout 3
fall 2 # 2回連続で失敗したら異常とみなす
rise 2 # 2回連続で成功したら正常に戻す
weight -30 # 異常時に priority から 30 を引く
}
vrrp_instance VI_1 {
state BACKUP
interface eth0
virtual_router_id 51
priority 110
advert_int 1
unicast_src_ip 192.168.10.11
unicast_peer {
192.168.10.12
}
virtual_ipaddress {
192.168.10.100/24 dev eth0
}
track_script {
chk_web
}
}
web2 では、router_id を web2、priority を 100、unicast_src_ip を 192.168.10.12、unicast_peer を 192.168.10.11 に変えます。それ以外は同じにします。
設定の要点を順に説明します。
- state と priority:MASTER になるかどうかは、最終的には priority の大小で決まります。両方を
state BACKUPで起動しても、priority の高い web1 が MASTER になります。起動直後に両方が MASTER を名乗る時間を作らないため、この記事では両方とも BACKUP から始めています。 - virtual_router_id:同じ VIP を共有する2台で同じ値にし、同じネットワーク上の別の VRRP グループとは重ならない値(1〜255)を選びます。重複すると、無関係な機器の広告を受け取って誤動作します。
- weight と priority の関係:web1 のヘルスチェックが失敗すると priority が 110 − 30 = 80 となり、web2 の 100 を下回るため VIP が移ります。weight の大きさ(マイナス記号を除いた値)は、2台の priority の差より大きくしておく必要があります。
- unicast_peer:既定では広告をマルチキャストで送ります。マルチキャストが通らないネットワーク(一部の VPS など)では、このようにユニキャストで相手を指定します。
- enable_script_security と script_user:ヘルスチェックスクリプトを実行するユーザーを明示し、一般ユーザーが書き換えられるスクリプトは実行しないようにする設定です。
VRRP には authentication ブロックで簡易的なパスワードを付ける設定もありますが、平文で送られるため防御としては弱く、VRRP バージョン3では廃止されています。広告を送り合うネットワークを専用のセグメントに分ける、ファイアウォールで相手サーバー以外からの VRRP を拒否する、といった対策の方が有効です。
設定の確認と起動
# 設定ファイルの構文チェック(keepalived 2.x の -t オプション)
sudo keepalived -t -f /etc/keepalived/keepalived.conf
sudo systemctl enable --now keepalived
sudo journalctl -u keepalived -n 50
ログに Entering MASTER STATE(web1)、Entering BACKUP STATE(web2)が出ていれば想定どおりです。VIP が付いているかは ip addr show eth0 で確認します。ifconfig では VIP のようなセカンダリアドレスが表示されないことがあるため、ip コマンドを使ってください。
VIP で待ち受けるサービスの注意
Nginx の listen を 192.168.10.100:80 のように VIP で指定すると、VIP を持っていない BACKUP 側では起動に失敗します。listen 80; のように全アドレスで待ち受けるか、カーネルパラメーター net.ipv4.ip_nonlocal_bind=1 を設定して、まだ持っていないアドレスへのバインドを許可します。
切り替えテスト
本番投入前に、意図したとおりに切り替わるかを試験します。別のホストから VIP へ ping を打ち続けながら、次の順で確かめます。
# 別ホストで
ping 192.168.10.100
# web1 で Nginx を止める → 数秒で web2 に VIP が移る
sudo systemctl stop nginx
# web1 で Nginx を戻す → web1 が MASTER に戻る
sudo systemctl start nginx
# web1 の keepalived 自体を止めた場合も試す
sudo systemctl stop keepalived
各段階で両方のサーバーの ip addr show eth0 と journalctl -u keepalived を見て、VIP がどちらか一方にだけ付いていることを確認します。両方に VIP が付いている場合はスプリットブレインで、ほとんどはファイアウォールで VRRP が遮断されているか、virtual_router_id やユニキャストの相手アドレスが食い違っていることが原因です。sudo tcpdump -nn -i eth0 ip proto 112 で、相手の広告が届いているかを確かめられます。
復帰時に VIP を戻さない設定
web1 が復帰した瞬間に VIP が戻ると、その切り替えで再び短い断が起きます。これを避けたい場合は、両方を state BACKUP にしたうえで vrrp_instance に nopreempt を加えると、復帰した側は BACKUP のまま待機します。その代わり、どちらが MASTER かは障害の履歴によって変わるので、監視で現在の MASTER を把握できるようにしておきます。
運用のポイント
- 状態が変わったときに通知したい場合は、
notify_master、notify_backup、notify_faultに通知用スクリプトを指定できます - WP-Cron やバックアップのように「1台だけで動かしたい処理」は、MASTER 側でのみ実行する仕組みにするか、サーバーの cron から片方だけで実行するように決めておきます
- keepalived の設定項目は版によって追加・変更があります。現在は 2.x 系が主流です(2026年10月現在)。ディストリビューションの版のマニュアル(
man keepalived.conf)で、使う項目があるかを確認してください
まとめ
- keepalived は VRRP で VIP を2台のうち1台に持たせ、広告が途絶えたりヘルスチェックが失敗したりするともう1台へ移します
- VRRP は IP プロトコル 112 を使うため、ファイアウォールで許可しないと両方が MASTER になります
vrrp_scriptのweightは2台の priority の差より大きくし、プロセスの有無ではなく実際の応答で判定します- 移るのは IP アドレスだけなので、WordPress のデータベースやアップロードファイルの共有は別に設計します
- 本番投入前に、サービス停止・keepalived 停止・復帰の各パターンで切り替えを試験します