0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

AWSでBIGIPのHA構成を作る(手動構築編ー第3章:CFE(CloudFailoverExtension)の設定)

0
Posted at

この記事はAWSでBIGIPのHA構成を作る(手動構築編ー第2章:アクトスタンバイ構築) の続きです。
CloudFormationテンプレートを使わずに、BIGIPのマルチAZ構成をAWSで再現する第3章です。

前回はアクトスタンバイ構成を作成するところまでやったので、今回はCFE(CloudFailoverExtension)の設定を扱います。

今回はほとんどCLI(CommandLineInterface)からの作業になります。

参考記事は以下:
F5公式ーCloud Failover Extension Overview
F5 BIG-IP AWS Multi-AZ for CFE 試してみた

==========================================================

目次

CFEとは
CFEの設定
 S3の作成
 IAMロールの設定
 AWSリソースへのタグ付け
 CFEパッケージのアップロード
 JSONの作成

CFEとは

そもそもCFEとは何なのか。今までの記事でも触れてきましたが、改めて整理します。

CFEは英語でみると Cloud Failover Extension。直訳すると「クラウド環境向けフェイルオーバー拡張機能」となります。

つまり、フェイルオーバー時の機能ということですね。

では今回の場合、どこでこれが必要なのか。

それは「BIGIPがマルチAZ構成だとIPアドレスを引き継げない」ことがキーとなってきます。

通常、オンプレなどのBIGIPでは、VIP(VirtualIP)を常にアクティブ機につけることで、接続先IPアドレスが変わらないようにします。

しかし、これをAWSで再現しようとすると、とある壁にぶち当たります。

そう、マルチAZ配置ではIPアドレスを引き継げないんです。

これまでの要件を考えると
・マルチAZ配置で障害対策をしたい
・アクトスタンバイ構成にしたい
・運用を考えると、クライアントが接続するIPアドレスをいちいち変えたくない
となっています。

ぱっと見、"マルチAZかつIPアドレス無変更"の時点で詰んでるんです。

しかし、それを可能にするのがCFEとなります。

ではどのようにこれを可能にするのか。

ざっくり言うと、

 AWSリソースをいじることで再現する

です。

例えばElastic IPアドレスやルートテーブルをフェイルオーバー時に操作することで、上記の要件を満たした構成ができます。

今回は「Elastic IPアドレスを付け替える」設定を扱っていきます。

また、追々説明しますが、AWSリソースへのタグ付けが重要となってきますので覚えておいてください。

ElasticIPアドレスを使用するということは、通信がインターネットに出るということです。
要件に「プライベートに閉じた環境で構築する」などがある場合は使用できません。
これに関する設定は続報をお待ちください。
※以下の記事を参考に解決できます。
Configuring AWS HA Failover Across AZs Without EIPs Using F5 Cloud Failover Extension (CFE)

CFEの設定

では順を追って設定していきます。

S3の作成

まずはS3を作成しましょう。
このS3は、フェイルオーバーの状態管理に使用されます。必須です。

フェイルオーバーのログが出力されたり、BIGIP自身が前回のログを元に「次はこっちに付け替えやな」みたいな感じで使用しています(多分)。

作成はすべてデフォルトでOKです。任意の名前だけ入力して作成しましょう。

注意点として、オブジェクトロックは絶対に有効にしないでください。

これを有効にするとS3バケット内のリソースに対して削除・上書きができなくなります。
BIGIPは対象S3内に1つのファイルを作成し、そこでフェイルオーバーごとの状態管理を行うため、上書きができる必要があります。

なお、デフォルトでは無効ですが、もし有効にすると後から変更はできないので、S3バケットを作り直しましょう。

では次に行きます。

IAMロールの設定

BIGIPがAWSリソースを操作するにも、タグが付いているリソースを認識するにも、それらの権限が必要になります。

そこで、その内容を記載したIAMロールをBIGIPインスタンス両機に付与していきます。

まずはIAMポリシーを作成します。内容はこんな感じ。
過剰かもしれませんが、拡張性を考えると問題ないかと思います。
(CloudFormationテンプレートから展開されたものをそのまま使ってます)

アカウント番号とS3バケット名は各自自分のものに置き換えてくださいね。

{
    "Version": "2012-10-17",
    "Statement": [
        {
            "Condition": {
                "StringEquals": {
                    "aws:RequestedRegion": "ap-northeast-1",
                    "aws:PrincipalAccount": "アカウント番号"
                }
            },
            "Action": [
                "ec2:DescribeAddresses",
                "ec2:DescribeInstances",
                "ec2:DescribeInstanceStatus",
                "ec2:DescribeNetworkInterfaces",
                "ec2:DescribeNetworkInterfaceAttribute",
                "ec2:DescribeTags"
            ],
            "Resource": [
                "*"
            ],
            "Effect": "Allow"
        },
        {
            "Condition": {
                "StringEquals": {
                    "aws:RequestedRegion": "ap-northeast-1",
                    "aws:PrincipalAccount": "アカウント番号"
                }
            },
            "Action": [
                "ec2:DescribeSubnets",
                "ec2:DescribeRouteTables"
            ],
            "Resource": [
                "*"
            ],
            "Effect": "Allow"
        },
        {
            "Condition": {
                "StringLike": {
                    "aws:ResourceTag/f5_cloud_failover_label": "bigip_high_availability_solution"
                }
            },
            "Action": [
                "ec2:AssociateAddress",
                "ec2:DisassociateAddress",
                "ec2:AssignPrivateIpAddresses",
                "ec2:UnassignPrivateIpAddresses",
                "ec2:AssignIpv6Addresses",
                "ec2:UnassignIpv6Addresses",
                "ec2:CreateRoute",
                "ec2:ReplaceRoute"
            ],
            "Resource": [
                "*"
            ],
            "Effect": "Allow"
        },
        {
            "Condition": {
                "StringEquals": {
                    "aws:PrincipalAccount": "アカウント番号"
                }
            },
            "Action": [
                "s3:ListAllMyBuckets"
            ],
            "Resource": [
                "*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "s3:ListBucket",
                "s3:GetBucketLocation",
                "s3:GetBucketTagging"
            ],
            "Resource": "arn:*:s3:::s3バケット名",
            "Effect": "Allow"
        },
        {
            "Action": [
                "s3:PutObject",
                "s3:GetObject",
                "s3:DeleteObject"
            ],
            "Resource": "arn:*:s3:::s3バケット名/*",
            "Effect": "Allow"
        },
        {
            "Condition": {
                "Null": {
                    "s3:x-amz-server-side-encryption": "true"
                }
            },
            "Action": [
                "s3:PutObject"
            ],
            "Resource": "arn:*:s3:::s3バケット名/*",
            "Effect": "Deny",
            "Sid": "DenyPublishingUnencryptedResources"
        },
        {
            "Condition": {
                "StringNotEquals": {
                    "s3:x-amz-server-side-encryption": "AES256"
                }
            },
            "Action": [
                "s3:PutObject"
            ],
            "Resource": "arn:*:s3:::s3バケット名/*",
            "Effect": "Deny",
            "Sid": "DenyIncorrectEncryptionHeader"
        },
        {
            "Condition": {
                "StringLike": {
                    "aws:ResourceTag/Name": ""
                }
            },
            "Action": [
                "logs:DescribeLogGroups",
                "logs:DescribeLogStreams",
                "logs:PutLogEvents"
            ],
            "Resource": [
                "*"
            ],
            "Effect": "Allow"
        },
        {
            "Condition": {
                "StringEquals": {
                    "cloudwatch:namespace": ""
                }
            },
            "Action": [
                "cloudwatch:PutMetricData"
            ],
            "Resource": [
                "*"
            ],
            "Effect": "Allow"
        },
        {
            "Action": [
                "cloudformation:ListStackResources",
                "cloudformation:SignalResource"
            ],
            "Resource": [
                "*"
            ],
            "Effect": "Allow"
        }
    ]
}

ポリシーの作成が完了したら、このポリシーを指定してIAMロールを作成しましょう。
EC2に渡すものなので、作成時にAWSのサービスでEC2を選びましょう。

IAMロールができたらBIGIPのEC2インスタンスに付与しましょう。

インスタンス概要のアクションボタンから「セキュリティ」を選んでIAMロールを設定できます。

実際にEC2インスタンスにIAMロールを設定する際は、設定する人に iam:PassRoleが無いとできないので注意してください。

これでIAMロールの作成・アタッチが完了しました。

AWSリソースへのタグ付け

CFEでは「タグ」がとても重要になってきます。

というのも、BIGIP君は、フェイルオーバー時にとあるタグが付いたAWSリソースを認識して、CFEの対象として扱います。

そのタグとは「f5_cloud_failover_label」。

流れとしては
1.フェイルオーバー発生
2.BIGIP「AWSリソースから"f5_cloud_failover_label"のタグが付いているやつを探せ!」
3.探索完了、CFE対象決定
4.前回のCFEログをS3から参照し、どこからどこへ何を付け替えるかを判断
となります。

今回はタグの値を以下で固定させていただきますが、値は自由に変えていただいて構いません。
※変える際はIAMポリシーでの記載も修正してください。

key value
f5_cloud_failover_label bigip_high_availability_solution

このタグとバリューを、以下のAWSリソースにつけてください。
・S3バケット
・Elastic IP
・ENI(external, internalのENI 計4つ)

後者2つについてはこのタグ以外にも付与するタグがあるので以下に一覧でまとめました。

〇S3バケット

key value
f5_cloud_failover_label bigip_high_availability_solution
name S3バケットの名前

〇Elastic IP

key value
f5_cloud_failover_label bigip_high_availability_solution
f5_cloud_failover_vips 10.5.1.100,10.5.16.100

f5_cloud_failover_vipsにはExternalENIで作成したセカンダリIPを書きます。書き方は「1号機のセカンダリIP,2号機のセカンダリIP」です。
おそらくですが、EIPがくっつく先となるIPを記載する必要があります。
EIPを増やした場合、対応するセカンダリIPのペアを新たに作成し、ここのIPをそれらで記載すればOKです。

〇ENI

key value
f5_cloud_failover_label bigip_high_availability_solution
f5_cloud_failover_nic_map external (またはinternal)

f5_cloud_failover_nic_mapにはexternalENIならexternal、internalENIならinternalと記載します。CFEにどっちのENIなのかを判定させるためと持ってもらえれば大丈夫です。

タグはこれにて完了です。

CFEパッケージのアップロード

GUIからCFEパッケージをアップロードしましょう。
以下のページに行き、最新版のパッケージ「f5_cloud-faiover-x.x.x.x-x.noarch.rpm」をダウンロードしましょう。
F5-github (f5_cloudfaiover_extension)

続いてアクティブ機となっているBIGIPのGUIへログインします。
左側のリストから「iApps」 > 「 Package Management LX」と進みます。
右上に「import」ボタンがあるので、それを押し「参照」ボタンから先ほどローカルにダウンロードしたパッケージを選択します。
アップロードが完了すると、画面に「f5-cloud-failover」のパッケージが表示されます。
これで完了です。

スタンバイ機でも同様に実施しましょう。

JSONの作成

ここからは基本的にCLIからコマンドを打っていきます。
まずはadminユーザーでBIGIPのアクティブ機のCLIにログインしましょう。

ssh -i .ssh/keyPair.pem -o MACs=hmac-sha1 admin@x.x.x.x

ログイン出来たらbashへ移動します。

admin@(ip-a-a-a-a)(cfg-sync In Sync)(Active)(/Common)(tmos)# 
admin@(ip-a-a-a-a)(cfg-sync In Sync)(Active)(/Common)(tmos)# run util bash
[admin@ip-a-a-a-a:Active:In Sync] ~ #

ここで以下のコマンドでJSONファイルを作成します。

[admin@ip-a-a-a-a:Active:In Sync] ~ # vi cfe.json

このコマンドが分からない方は以下の記事を参考にしてみてください。
【保存版】viエディタの使い方&コマンド集

ここで以下を貼り付けます。

{
  "schemaVersion": "1.0.0",
  "class": "Cloud_Failover",
  "environment": "aws",
  "controls": {
    "class": "Controls",
    "logLevel": "silly"
  },
  "externalStorage": {
    "encryption": {
      "serverSide": {
        "enabled": true,
        "algorithm": "AES256"
      }
    },
    "scopingTags": {
      "f5_cloud_failover_label": "bigip_high_availability_solution"
    }
  },
  "failoverAddresses": {
    "enabled": true,
    "scopingTags": {
      "f5_cloud_failover_label": "bigip_high_availability_solution"
    },
    "requireScopingTags": false
  }
}

「f5_cloud_failover_label」の値を変えた方はそちらに置き換えてください。
編集(ペースト)が完了したら「Escape」を押してから「:wq」と入力し、保存しましょう。
これで、カレントディレクトリに cfe.json というファイルが作成されました。

ちょっと寄り道:事前確認========================

以下のコマンドで今までの設定が正しいかを確認できます。
①パッケージが正しく設定できているか
期待結果:パッケージのバージョンが出力されること

curl -sku admin:password http://localhost/mgmt/shared/cloud-failover/info | jq

②IAMロールが付いているか
期待結果:IAMロールの名前が出力されること

curl http://169.254.169.254/latest/meta-data/iam/security-credentials/

③S3やEC2サービスと疎通が取れているか
期待結果:疎通が取れていること

nslookup ec2.ap-northeast-1.amazonaws.com
nslookup s3.ap-northeast-1.amazonaws.com

=======================================

続いて、このJSONファイルをBIGIPのCFE APIへポストします。
以下のコマンドを実行しましょう。

[admin@ip-a-a-a-a:Active:In Sync] ~ #
[admin@ip-a-a-a-a:Active:In Sync] ~ # curl -sku admin:password -X POST http://localhost/mgmt/shared/cloud-failover/declare -H "Content-Type: application/json" -d @cfe.json | jq

「f5_cloud_failover_label」が付いたAWSリソースが、JSON形式で出力されたらポスト成功です。
もしエラーが出た場合、
・cfe.jsonに余計な空白等がないか
・AWSリソースに正しくタグが付いているか
・コマンドは間違っていないか
などを確認してみてください。
(それでもわからない場合AIに聞いてみてネ!)

以下のコマンドで正しく設定できているか確認できます。
これらのコマンドでも期待する結果が得られるかたまに見てみると安心です。
①CFE設定の取得(JSON中身を見る)

curl -sku admin:password http://localhost/mgmt/shared/cloud-failover/declare | jq

②JSONにより判定されたAWSリソースを表示する

curl -sku admin:password http://localhost/mgmt/shared/cloud-failover/inspect | jq

最後に以下のコマンドを打ちましょう。
このコマンドは、CFEに対してフェイルオーバー処理をトリガーするAPIです。
今はアクティブ機から実行しているためアクトスタンバイは切り替わりませんが、AWSリソース(EIP)が正しくアクティブ側についているかなどの整合性を取ってくれます。

curl -sku admin:password -X POST http://localhost/mgmt/shared/cloud-failover/trigger -H "Content-Type: application/json" -d '{}' | jq

成功するとJSON形式でAWSリソース移動の出力が得られます。また、S3にも同様のログが出力されます。
↓こんな感じ

{
    "taskState": "SUCCEEDED",
    "message": "Failover Complete",
    "timestamp": "2026-XX-XXTHH:SS:ZZ.ZZZ",
    "instance": "instance name",
    "failoverOperations": {
        "addresses": {
            "publicAddresses": {
                "付け替えを実行したElastic ip": {
                    "current": {
                        "PrivateIpAddress": "10.5.1.100",
                        "AssociationId": "eipassoc-xxxxxxxxxxxxxxxxx"
                    },
                    "target": {
                        "PrivateIpAddress": "10.5.16.100",
                        "NetworkInterfaceId": "eni-yyyyyyyyyyyyyyyyy"
                    },
                    "AllocationId": "eipalloc-zzzzzzzzzzzzzzzzz"
                },
            "interfaces": {
                "disassociate": [
                    {
                        "networkInterfaceId": "eni-aaaaaaaaaaaaaaaa",
                        "addresses": []
                    },
                    {
                        "networkInterfaceId": "eni-bbbbbbbbbbbbbbbb",
                        "addresses": []
                    }
                ],
                "associate": [
                    {
                        "networkInterfaceId": "eni-cccccccccccccccc",
                        "addresses": []
                    },
                    {
                        "networkInterfaceId": "eni-dddddddddddddddd",
                        "addresses": []
                    }
                ]
            },
            "loadBalancerAddresses": {}
        },
        "routes": {}
    }
}

続いていよいよフェイルオーバーを実行してみましょう。
Active機のGUIから画面左側「Device Management > Devices > xxxxx( self )」を押します。
下へスクロールすると「Force to Standby」というボタンがあるのでそれを押します。

すると、画面左上の表示から判断できますが、アクティブとスタンバイが入れ替わると思います。

さて、EIPはうまくつけ変わっているかな?

と思ってS3を見てもログが更新されていない。ほう...

実際にコンソールから見てもEIPは現在スタンバイとなっているほうについたままだ...

大丈夫です、安心してください。

どうやら、旧スタンバイ機(現在アクティブ機)でも同様の作業が必要なようです。

現在アクティブとなっているBIGIPのCLIに接続し、
JSONの作成から、さっきのトリガーコマンドまでを実施しましょう。
すると、S3でログが更新され、EIPもつけ変わると思います。

こうすると、両方の機器からそれぞれCFEの設定をしたことになりますね。

改めて、現在アクティブとなっている機器から「Force to Standby」を押してフェイルオーバーを実施してみましょう。

S3を確認するとログが更新されていると思いますし、実際にEIPがつけ変わっていると思います。

これにてCFEの設定は完了です。

あとは実際の振り分け対象サーバたちを登録してくだけですね。

この辺についてはもはやAWSは関係ないので割愛します。

おわりに

これにてAWSでBIGIPのHA構成を作るシリーズ完結です。
最後までお付き合いいただきありがとうございました。
正直思い出しながら書いているので、書き漏れがないか気が気でないです。

もし、これを読んで参考にしながら構築する人がいて、変な点や間違っている点、足りない点に気づいたら是非教えてください。

あとはElasticIPを使わない構成(インターネットに出ない構成)の構築に関する記事を書くかどうかですが、元気とモチベがあればそのうち書こうと思います。
以前も頭出ししましたが、基本的には構成は同じで、以下の記事の考えを取り入れればOKです。
AWS HA Failover Across AZs Without EIPs

これ面白いんですけど、「エイリアンIPアドレス帯」っていう概念を使うんです。
英語で「Alian IP range」って書いてあるのでそのまま呼んでますが、日本語名あるんですかね...
どういうものかというと、使っているVPCだったり、関係する他のネットワーク帯に含まれないIPアドレス帯を定義して、それを利用することでEIPを使わなくて済む、というものです。

未使用のIPアドレス帯の中で定義する必要があるということです

このエイリアンIPアドレス帯は、RFC1918アドレス内で定義する必要があるかとは思いますが、このアドレス帯の中でIPアドレスを定めて、BIGIPのVirtualServerに利用することができるんです。

どこにも属さないIPアドレス帯だから「エイリアンIP帯」っていうんでしょうか。
もはや一般名称ではないのかもわかりませんが、こういうネーミングセンスとても好きです。

おわり

0
0
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
0
0

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?