サイト内の現在位置を表示しています。

AWSのマルチリージョン環境で強制停止リソースを試してみました(Windows/Linux)

CLUSTERPRO オフィシャルブログ ~クラブロ~

  • 2024/09/13 以下を追記。
  • サービス起動遅延時間の調整について記述を追加しました。

はじめに

Amazon Web Services(以降、AWS)のマルチリージョン環境におけるHAクラスターで強制停止リソースを試してみました。

強制停止リソースは、ハートビートの途絶を検知した時にCLI等を使用して外部から現用系サーバーを強制停止します。ネットワークパーティション解決リソースと併用することでより確実に両系活性を防止することが可能です。

CLUSTERPRO X 5.0以降では、AWS環境でもパラメータを指定するだけで簡単に強制停止リソースを利用可能になっていますが、マルチリージョン環境におけるHAクラスターでは強制停止リソースの使用において少し工夫が必要となります。本記事ではマルチリージョン環境での強制停止リソースの設定手順について紹介します。

本記事は、以前公開したpopupCLUSTERPRO X 5.0のご紹介~強制停止リソース~を補足する記事になりますので、まずは過去記事をご覧いただくことを推奨いたします。

この記事の内容

1. マルチリージョン環境での強制停止リソース

強制停止リソースは、クラスターを構築する環境に合わせていくつかのタイプが用意されています。AWS環境では通常「タイプ」が「AWS」の強制停止リソースを使用します。強制停止リソースは待機系が現用系とのハートビート途絶を検出した際に、待機系のインスタンスから現用系のインスタンスを停止するAWS CLIコマンドを実行し、強制停止します。

リージョン内での強制停止(AWS)

しかし、X 5.1時点の強制停止リソースは停止するインスタンスが同じリージョン内にあることを前提としています。そのため異なるリージョンに存在するインスタンスを停止することはできません。

異なるリージョンでの強制停止(AWS)

したがって、代わりに「タイプ」が「カスタム」の強制停止リソースを使用します。カスタムの強制停止リソースはスクリプトで任意の処理を実行可能です。そのため停止対象のインスタンスを、インスタンスの存在するリージョンを併せて指定することで停止させることが可能となります。

異なるリージョンでの強制停止(カスタム)

2. 強制停止リソースの設定手順

マルチリージョンに対応したカスタムの強制停止リソースの設定手順を紹介します。
強制停止リソースの詳細について以下のシステム構築ガイドを参照してください。

【参考】
  • CLUSTERPRO X 5.1 > Windows > リファレンスガイド
    → 第 7 章 強制停止リソースの詳細

  • CLUSTERPRO X 5.1 > Linux > リファレンスガイド
    → 第 7 章 強制停止リソースの詳細

カスタムの強制停止リソースのスクリプト内でAWS CLIコマンドを実行するため、HAクラスターを構成する各インスタンスにAWS CLIをインストールするなどの事前設定が必要となります。AWS CLIを利用するための詳細は以下のシステム構築ガイドを参照ください。

【参考】
  • CLUSTERPRO X 5.1 > Windows > スタートアップガイド
    → 第 6 章 注意制限事項
      → 6.2 CLUSTERPRO インストール前
        → 6.2.16 AWS 環境における時刻同期
        → 6.2.17 AWS 環境における IAM の設定について

  • CLUSTERPRO X 5.1 > Linux > スタートアップガイド
    → 第 6 章 注意制限事項
      → 6.3 OS インストール後、CLUSTERPRO インストール前
        → 6.3.19 AWS 環境における時刻同期
        → 6.3.20 AWS 環境における IAM の設定について

2.1 アカウントの登録(Windowsのみ)

Linuxでは本操作は不要なため、次の「2.2 フェンシングの設定」に進みます。
Windowsでは強制停止リソースのスクリプトをAdministratorユーザーで実行する必要があります。そのためCLUSTERPROにAdministratorユーザーの情報を登録します。

Cluster WebUIから「クラスタのプロパティ」を開き、「アカウント」タブの「追加」ボタンを押します。

「ユーザ名」に「Administrator」、「パスワード」にAdministratorのパスワードを入力します。
「OK」ボタンを押します。

Administratorユーザーを追加

2.2 フェンシングの設定

Cluster WebUIから「クラスタのプロパティ」を開き、「フェンシング」タブを選択します。
NP解決には、PINGもしくはHTTP方式を選択してserver1、server2からNP解決可能なターゲットを設定します。
「強制停止」の「タイプ」のプルダウンから「カスタム」を選択し、「プロパティ」ボタンを押します。

「サーバ一覧」タブで「server1」を選択し、「追加」ボタンを押します。

server2も同様の手順で設定します。

「強制停止」タブで強制停止実施時の最大待ち時間を「強制停止タイムアウト」として次の式で計算式し、設定します。本記事では例として180秒とします。

強制停止タイムアウト秒数 > CHECK_LOOP_MAX × SLEEP_WAIT
    CHECK_LOOP_MAX:停止チェックの最大試行回数
    SLEEP_WAIT:停止チェック間隔(秒)
 
変数は「2.3 スクリプトの編集」のスクリプト内で設定するものと同一です。
AWS CLI実行時のオーバーヘッドも見込んで余裕のある秒数にします。

また、強制停止に失敗した場合にフェールオーバーさせたくない場合は「停止失敗時にグループのフェイルオーバを抑制する」にチェックを入れます。

「スクリプト」タブの設定は次節に続きます。

2.3 スクリプトの編集

カスタム強制停止リソースで実行するスクリプトに、強制停止スクリプトを指定します。

カスタム強制停止リソースで使用するスクリプトには、定期チェック時の動作と、強制停止実行時の動作をそれぞれ記載する必要があり、それぞれの動作の分岐処理を実現するために環境変数[CLP_FORCESTOP_MODE]を利用します。[CLP_FORCESTOP_MODE]の値が0の場合は定期チェック、1の場合は強制停止をそれぞれ実行します。

今回はWindows版、Linux版のそれぞれのスクリプト記述例を紹介します。

2.3.1 Windows版スクリプト

「スクリプト」タブで「forcestop.bat」を選択し、「編集」ボタンを押します。

以下のスクリプトの内容を入力します。

rem ***************************************
rem * forcestop.bat
rem ***************************************

cd %~dp0
PowerShell ".\forcestop.ps1; exit $lastexitcode"
set ret=%ERRORLEVEL%
echo ret: %ret%
exit /b %ret%

また、forcestop.batから呼び出されるPowerShellスクリプトを追加するために、「追加」ボタンを押します。

「スクリプトファイル名」に「forcestop.ps1」を入力します。
「参照ファイルパス」の指定は不要です。
「保存」ボタンを押します。

forcestop.ps1スクリプトの追加

「forcestop.ps1」を選択して「編集」ボタンを押し、以下のスクリプトの内容を入力します。 変数INSTANCESには、HAクラスターを構成するインスタンスのホスト名、インスタンスID、インスタンスのリージョンを指定します。 変数CHECK_LOOP_MAXとSLEEP_WAITにはそれぞれ停止チェックの最大試行回数と停止チェック間隔を設定します。

#***************************************
#*            forcestop.ps1
#***************************************

##########################################
# Configuration

# インスタンス情報定義
# 書式:
#   "<ホスト名>" = "<インスタンスID> <インスタンスのリージョン>";
$INSTANCES = @{
    "server1" = "i-xxxxxxxxxxxxxxxxx ap-northeast-1";
    "server2" = "i-yyyyyyyyyyyyyyyyy ap-northeast-3";
}

# 停止チェックの最大試行回数
$CHECK_LOOP_MAX = 50

# 停止チェック間隔(秒)
$SLEEP_WAIT = 3

##########################################

# 指定したインスタンスの状態を取得する
function get_node_status($id, $region) {
    aws ec2 describe-instances `
        --region $region `
        --instance-ids $id `
        --query 'Reservations[].Instances [].State.Name' `
        --output text
}

# 指定したインスタンスを強制停止する
function stop_node($id, $region, $opt) {
    aws ec2 stop-instances `
        --region $region `
        --instance-ids $id `
        $opt
}

if ( $env:CLP_FORCESTOP_MODE -ne "1" ) {
    # 定期チェック時の動作
    # ローカルサーバー名からインスタンスIDとリージョンを決定する
    $target = $env:CLP_SERVER_LOCAL
    if ( ! $INSTANCES.ContainsKey($target) ) {
        # サーバー名に対応するインスタンス情報定義が見つからない
        exit 1
    }

    $info = $INSTANCES[$target].split()
    $instanceid = $info[0]
    $region = $info[1]

    # 強制停止のテスト
    $result = stop_node $instanceid $region --dry-run 2>&1 | `
        Select-String "DryRunOperation"
    if ( $null -eq $result ) {
        # 強制停止処理テストの失敗
        exit 2
    }

} else {
    # 強制停止実行時の動作
    # ダウンしたサーバー名からインスタンスIDとリージョンを決定する
    $target = $env:CLP_SERVER_DOWN
    if ( ! $INSTANCES.ContainsKey($target) ) {
        # サーバー名に対応するインスタンス情報定義が見つからない
        exit 4
    }

    $info = $INSTANCES[$target].split()
    $instanceid = $info[0]
    $region = $info[1]

    # ダウンサーバーの強制停止
    stop_node $instanceid $region --force > $null
    if ( $lastexitcode -ne 0 ) {
        # 強制停止処理の失敗
        exit 5
    }

    # 停止チェック
    $loop_count = 0
    while ( $loop_count -lt $CHECK_LOOP_MAX ) {
        $status = get_node_status $instanceid $region
        if ( $lastexitcode -eq 0 -and $status -eq "stopped" ) {
            # 停止を確認
            break
        }

        Start-Sleep -Seconds $SLEEP_WAIT

        $loop_count++
    }

    if ( $loop_count -ge $CHECK_LOOP_MAX ) {
        # 停止チェックのタイムアウト発生
        exit 6
    }
}

exit 0

「スクリプト」タブの下の方にある「実行ユーザ」に「Administrator」を選択します。

設定が完了したら「OK」ボタンを押して保存します。保存した後に「OK」ボタンを押して設定を完了します。

2.3.2 Linux版スクリプト

「スクリプト」タブで「forcestop.sh」を選択し、「編集」ボタンを押します。

以下のスクリプトの内容を入力します。
変数AWS_CLIにはインストールしたAWS CLIのパスを設定します。
変数INSTANCESには、HAクラスターを構成するインスタンスのホスト名、インスタンスID、インスタンスのリージョンを指定します。
変数CHECK_LOOP_MAXとSLEEP_WAITにはそれぞれ停止チェックの最大試行回数と停止チェック間隔を設定します。

#! /bin/bash
#***************************************
#*            forcestop.sh
#***************************************

##########################################
# Configuration

# AWS CLIの絶対パス
AWS_CLI="/bin/aws"

# インスタンス情報定義
# 書式:
#   [<ホスト名>]="<インスタンスID> <インスタンスのリージョン>"
declare -A INSTANCES=(
  [server1]="i-xxxxxxxxxxxxxxxxx ap-northeast-1"
  [server2]="i-yyyyyyyyyyyyyyyyy ap-northeast-3"
)

# 停止チェックの最大試行回数
CHECK_LOOP_MAX=50

# 停止チェック間隔(秒)
SLEEP_WAIT=3

##########################################

# 指定したインスタンスの状態を取得する
get_node_status() {
  local id=$1
  local region=$2
  ${AWS_CLI} ec2 describe-instances \
    --region ${region} \
    --instance-ids ${id} \
    --query 'Reservations[].Instances [].State.Name' \
    --output text
}

# 指定したインスタンスを強制停止する
stop_node() {
  local id=$1
  local region=$2
  local opt=$3
  ${AWS_CLI} ec2 stop-instances \
    --region ${region} \
    --instance-ids ${id} \
    ${opt}
}

if [ "${CLP_FORCESTOP_MODE}" != "1" ]; then
  # 定期チェック時の動作
  # ローカルサーバー名からインスタンスIDとリージョンを決定する
  info=(${INSTANCES["${CLP_SERVER_LOCAL}"]})
  if [ ${#info[@]} -eq 0 ]; then
    # サーバー名に対応するインスタンス情報定義が見つからない
    exit 1
  fi
  instanceid="${info[0]}"
  region="${info[1]}"

  # 強制停止のテスト
  stop_node "${instanceid}" "${region}" --dry-run 2>&1 | \
    grep -q "DryRunOperation" >& /dev/null
  if [ $? -ne 0 ]; then
    # 強制停止処理テストの失敗
    exit 2
  fi

else
  # 強制停止実行時の動作
  # ダウンしたサーバー名からインスタンスIDとリージョンを決定する
  info=(${INSTANCES["${CLP_SERVER_DOWN}"]})
  if [ ${#info[@]} -eq 0 ]; then
    # サーバー名に対応するインスタンス情報定義が見つからない
    exit 4
  fi
  instanceid="${info[0]}"
  region="${info[1]}"

  # ダウンサーバーの強制停止
  stop_node "${instanceid}" "${region}" --force > /dev/null
  if [ $? -ne 0 ]; then
    # 強制停止処理の失敗
    exit 5
  fi

  # 停止チェック
  loop_count=0
  while [ ${loop_count} -lt ${CHECK_LOOP_MAX} ]
  do
    status=$(get_node_status "${instanceid}" "${region}")
    if [ $? -eq 0 -a "${status}" == "stopped" ]; then
      # 停止を確認
      break
    fi

    sleep ${SLEEP_WAIT}
    let loop_count++
  done

  if [ ${loop_count} -ge ${CHECK_LOOP_MAX} ]; then
    # 停止チェックのタイムアウト発生
    exit 6
  fi
fi

exit 0

設定が完了したら「OK」ボタンを押して保存します。保存した後に「OK」ボタンを押して設定を完了します。

3. サービス起動遅延時間の設定

CLUSTERPROサービス起動時の遅延時間を設定します。
これにより、強制停止リソース実行中に対向サーバーでOS再起動などが実行された場合に、両系活性が発生することや、クラスター起動処理中に強制停止が実行されることを防止します。
サービス起動遅延時間を以下となるように設定します。

サービス起動遅延時間 >= 強制停止リソースの強制停止タイムアウト + ハートビートタイムアウト + ハートビートインターバル

サービス起動遅延時間は、「クラスタのプロパティ」の「タイムアウト」タブにある[サービス起動遅延時間]で設定できます。

また、DISK方式によるNP解決を行う場合や共有ディスクを利用する場合はサービス起動遅延時間の計算について、別の観点での考慮が必要です。
詳細については、popup【2024年版】サービス起動遅延時間設定機能の紹介も併せて参照ください。
  • 強制停止リソースを利用する場合にサービス起動遅延時間に追加する時間は「強制停止リソースの強制停止タイムアウト時間 + 強制停止リソースの停止完了待ち時間」ですが、リンク先の記事の注釈にも記載している通り、カスタム強制停止リソースを利用する場合、強制停止リソースの停止完了待ち時間は0秒で計算します。
    そのため、本記事のサービス起動遅延時間の計算式では強制停止リソースの停止完了待ち時間は記載しておりません。

4. 動作確認

強制停止リソースの設定後、ネットワークパーティション状態を起こし、HAクラスターの動作を確認します。

ネットワークパーティション状態を起こすため、ネットワークACLの設定によりHAクラスターを構成するサーバーのVPC間をまたぐ通信を全て遮断するようにします。動作確認の詳細についてはpopup【2022年版】AWSで両系活性を防止する方法(Windows/Linux)の「4. NP解決時の動作確認」を参照してください。なお、AZ間通信は異なるリージョンのVPC間通信に読み替えてください。

まとめ

今回は、AWSのマルチリージョン環境でカスタムの強制停止リソースを試してみました。カスタムの強制停止リソースを使用することで、マルチリージョンでもハートビートの途絶によりダウンしたサーバーを強制停止させることが可能となります。

本記事の構成をご検討の際は、CLUSTERPROのpopup試用版を用いて検証した後、ご提案・構築ください。

お問い合わせ

本記事に関するお問い合わせは、popupお問い合わせ窓口までお問い合わせください。
  • 本記事で紹介しているスクリプトはサンプルであり動作を保証するものではありません。スクリプトの内容についてのお問い合わせ、および、お客様環境に合わせたカスタマイズにつきましてはCLUSTERPRO導入支援サービスにて承っておりますので、上記窓口の"ご購入前のお問い合わせ"フォームまでお問い合わせください。