2026年6月25日

2026年6月25日

Keepalived を Auto Scaling と連携させる手順|AWSでVIPを引き継ぎ、増減するWebサーバーに追従する

Keepalived を AWS の Auto Scaling と組み合わせるときは、「LB 層の冗長化」と「Webサーバー層の増減への追従」を分けて考えるのがこつです。LB 層は Keepalived の VRRP で現用・待機を切り替え、切り替え時に AWS の API で Elastic IP などを付け替えます。Webサーバー層は Auto Scaling グループで増減させ、その一覧を HAProxy などに反映します。この記事では、クラウドで VRRP がそのままでは動かない理由から、unicast 設定、フェイルオーバー時のスクリプト、ライフサイクルフックによる安全な縮退、動作確認までを順に説明します。

最初に検討したいこと

AWS では ALB や NLB を使えば、LB 自体の冗長化と Auto Scaling グループとの連携を AWS に任せられます。Keepalived を使う構成は、自分で管理する部品が増えます。それでも選ばれるのは、HAProxy の細かな機能を前段で使いたい、オンプレと同じ構成をクラウドでも再現したい、特定の固定IPで受けたい、といった理由がある場合です。理由が特にないなら、マネージドLBを先に検討してください。

クラウドで VRRP がそのまま動かない理由

オンプレの Keepalived は、マルチキャストで VRRP の通知を送り合い、現用になったノードが仮想IP(VIP)を自分のNICに付けて、Gratuitous ARP で周囲に知らせます。AWS の VPC ではマルチキャストが使えず、Gratuitous ARP でIPの持ち主を変えることもできません。IPアドレスの割り当ては AWS 側が管理しているためです。

そこで次の2点を変えます。

  1. VRRP の通知をユニキャストにする(unicast_src_ip と unicast_peer)
  2. 現用に切り替わったときに、AWS CLI で Elastic IP の関連付けやセカンダリIPを自分へ付け替える(notify_master スクリプト)

セキュリティグループでは、LB 同士の間で VRRP(IPプロトコル番号112)を許可します。TCP や UDP ではない点でつまずきやすいので注意してください。

全体構成

  • LB 層:Keepalived と HAProxy を入れたインスタンス2台。別々のアベイラビリティーゾーンに置く
  • 公開IP:Elastic IP 1つ。現用側に関連付ける
  • Webサーバー層:WordPress を動かすインスタンスを Auto Scaling グループで管理
  • 連携:Webサーバーの増減を HAProxy に反映し、縮退時はライフサイクルフックで接続が終わるのを待ってから終了させる

Elastic IP は別のゾーンのインスタンスにも付け替えられますが、セカンダリのプライベートIPは同じサブネット内でしか移せません。LB をゾーンをまたいで置くなら、公開側は Elastic IP の付け替えにするのが扱いやすい方法です。

手順1:Keepalived の設定

Ubuntu や Amazon Linux のパッケージで Keepalived を入れ、/etc/keepalived/keepalived.conf を次のように書きます。IPアドレスは自分の環境に置き換えます。もう1台では unicast_src_ip と unicast_peer を入れ替え、priority を低くします。

global_defs {
    enable_script_security
    script_user root
}

vrrp_script chk_haproxy {
    script "/usr/bin/pidof haproxy"
    interval 2
    fall 2
    rise 2
}

vrrp_instance VI_WEB {
    state BACKUP
    interface eth0
    virtual_router_id 51
    priority 150
    advert_int 1
    nopreempt

    unicast_src_ip 10.0.1.10
    unicast_peer {
        10.0.2.10
    }

    track_script {
        chk_haproxy
    }

    notify_master /etc/keepalived/to_master.sh
}

nopreempt は、元の現用ノードが復旧しても自動で現用を奪い返さない設定です。切り替えのたびに短い断が出るため、往復を避ける目的で付けています。nopreempt は state BACKUP と組み合わせて使います。インターフェース名は OS やインスタンスタイプで ens5 などになることがあるので、ip addr で確認してください。

track_script で HAProxy の生存を見ているため、HAProxy が落ちたノードは現用を降ります。

手順2:現用に切り替わったときのスクリプト

/etc/keepalived/to_master.sh で、Elastic IP を自分に関連付けます。インスタンスIDはインスタンスメタデータ(IMDSv2)から取得します。

#!/bin/bash
set -euo pipefail

REGION="ap-northeast-1"
ALLOCATION_ID="eipalloc-0123456789abcdef0"

TOKEN=$(curl -sS -X PUT "http://169.254.169.254/latest/api/token" \
  -H "X-aws-ec2-metadata-token-ttl-seconds: 300")
INSTANCE_ID=$(curl -sS -H "X-aws-ec2-metadata-token: ${TOKEN}" \
  http://169.254.169.254/latest/meta-data/instance-id)

aws ec2 associate-address \
  --region "${REGION}" \
  --allocation-id "${ALLOCATION_ID}" \
  --instance-id "${INSTANCE_ID}" \
  --allow-reassociation

スクリプトは root 所有で、ほかのユーザーが書き換えられない権限(例: chmod 700)にします。enable_script_security を有効にしていると、権限が緩いスクリプトは Keepalived が実行を拒否します。

インスタンスには IAM ロールを付け、ec2:AssociateAddress など必要な操作だけを許可します。アクセスキーをサーバーに置く方法は避けてください。

手順3:Webサーバーの増減を HAProxy に反映する

Auto Scaling グループのインスタンスはIPが毎回変わるため、HAProxy の設定に固定のIPを書くわけにはいきません。方法は主に2つあります。

  • DNS で追従する:Webサーバーの起動時に、Route 53 のプライベートホストゾーンや AWS Cloud Map へ自分を登録し、HAProxy の server-template と resolvers でその名前を引く。HAProxy の再読み込みなしで増減に追従できます
  • 設定を生成して再読み込みする:Auto Scaling のイベントを受けて、aws autoscaling describe-auto-scaling-groups でインスタンス一覧を取り、HAProxy のバックエンド設定を書き直して systemctl reload haproxy する

LB 2台の両方で同じ一覧を持つ必要があるので、どちらの方法でも待機側にも反映されているかを確認してください。

手順4:縮退時に接続を切らないための待ち合わせ

Auto Scaling が台数を減らすとき、そのままではインスタンスが処理中のリクエストごと終了します。ライフサイクルフック(終了時)を設定すると、インスタンスは待機状態で止まり、その間に HAProxy から切り離せます。

# 1. HAProxy で対象サーバーを drain(新規接続を止める)。LB 2台の両方で実行する
echo "set server be_wp/web3 state drain" | sudo socat stdio /run/haproxy/admin.sock

# 2. 接続が落ち着いたら、終了を進めてよいと Auto Scaling に伝える
aws autoscaling complete-lifecycle-action \
  --lifecycle-hook-name wp-terminate-hook \
  --auto-scaling-group-name wp-web-asg \
  --lifecycle-action-result CONTINUE \
  --instance-id i-0123456789abcdef0

この処理は、EventBridge でライフサイクルのイベントを受けて Lambda や Systems Manager から実行する形が一般的です。待機の上限時間を過ぎると既定の動作で処理が進むため、上限は接続が落ち着くまでの時間より長めに設定します。

手順5:異常なWebサーバーを Auto Scaling に知らせる

ALB を使わない構成では、Auto Scaling は HAProxy のヘルスチェック結果を知りません。EC2 のステータスは正常なのに WordPress が 500 を返し続ける、という状態でも入れ替わらないことになります。HAProxy で長時間外れているサーバーを検出したら、次のコマンドで異常を通知し、入れ替えを促せます。

aws autoscaling set-instance-health \
  --instance-id i-0123456789abcdef0 \
  --health-status Unhealthy

一時的な負荷でまとめて異常扱いにしないよう、判定の閾値は慎重に決めてください。

動作確認

本番に入れる前に、検証環境で次の順に試します。AWS CLI のオプションやイベントの仕様は変わることがあるため、最新のドキュメントとあわせて確認してください(2026年10月現在)。

  1. 両ノードで journalctl -u keepalived を見て、片方が MASTER、もう片方が BACKUP になっているか確認する
  2. 現用ノードで sudo systemctl stop haproxy を実行し、待機側が MASTER に変わり、Elastic IP が付け替わるかを確認する
  3. 外部から curl を1秒間隔で流し続け、切り替え中に何秒エラーが出るかを記録する
  4. Auto Scaling グループの希望台数を増減させ、HAProxy の統計に反映されるか、縮退時に drain を経て終了するかを確認する

WordPress 側で必要なこと

LB 層がどの構成でも、WordPress 側には X-Forwarded-Proto による HTTPS 判定、X-Forwarded-For からの訪問者IPの復元、全サーバーで共有するメディア置き場(EFS やオブジェクトストレージへのオフロード)、共通の wp-config.php の認証用キーが必要です。Webサーバーはいつ消えてもよい前提で作り、管理画面からのプラグイン更新は起動テンプレートやデプロイの仕組みに反映してください。設定変更の前には、データベースと設定ファイルのバックアップを取っておきます。

まとめ

  • AWS では VRRP のマルチキャストと Gratuitous ARP が使えないため、unicast 設定と AWS API による IP の付け替えを組み合わせる
  • notify_master で Elastic IP を付け替え、権限は IAM ロールで最小限にする
  • Webサーバーの増減は DNS(server-template)か設定の再生成で HAProxy に反映する
  • 縮退はライフサイクルフックで drain してから進め、異常は set-instance-health で Auto Scaling に伝える
  • 特別な理由がなければ、ALB/NLB で済むかを先に検討する

お気軽にご相談ください

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