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 停止・復帰の各パターンで切り替えを試験します

お気軽にご相談ください

お見積りへ お問い合わせへ
▲