Amazon FSx for NetApp ONTAPにNetwork Load Balancer経由でアクセスしてみた

Transit Gatewayの代替策としてNLBが使えるかもしれません
2022.06.01

この記事は公開されてから1年以上経過しています。情報が古い可能性がありますので、ご注意ください。

Amazon FSx for NetApp ONTAPにTransit Gatewayを使わずにアクセスしたい

こんにちは、のんピ(@non____97)です。

皆さんはAmazon FSx for NetApp ONTAP(以降、FSx for ONTAP)にTransit Gatewayを使わずにアクセスしたいと思ったことはありますか? 私はあります。

FSx for ONTAPのFAQにある通り、VPC外からMulti-AZ構成のFSx for ONTAPに接続する際はTransit Gatewayが必要です。

Q: オンプレミスまたは別の AWS 仮想プライベートクラウド (VPC) から Amazon FSx for NetApp ONTAP ファイルシステムにアクセスできますか?

A: はい、Amazon FSx for NetApp ONTAP マルチ AZ ファイルシステム、およびシングル AZ ファイルシステムは、オンプレミスまたは別の VPC からアクセスすることができます。

マルチ AZ ファイルシステムには、AWS Transit Gateway で AWS VPN または Direct Connect を使用してオンプレミスからアクセスできます。Transit Gateway または VPC ピアリングを使用して、別の VPC (別の AWS リージョンの VPC を含む) からファイルシステムにアクセスすることもできます。ファイルシステムの VPC の外部 (オンプレミスネットワークなど) のクライアントからファイルシステムにアクセスする場合は、Transit Gateway を使用するか、(NetApp グローバルファイルキャッシュまたは NetApp FlexCache を使用して) データのリモートオフィスキャッシングを設定する必要があります。これにより、データへ高可用性で低レイテンシーのアクセスが行えます。詳細については、Amazon FSx ドキュメントを参照してください。

NetApp ONTAP ファイルシステム管理リソース – Amazon Web Services

Transit Gatewayは私も大好きなサービスなのですが、取り分けオンプレミス環境とTransit Gatewayを介してVPCを接続する際に必要なTransit VIFを用意するのが大変だったりします。

可用性を向上させるためにFSx for ONTAPはMulti-AZ構成にしたい。でもTransit VIFを新たに用意するのが難しい」や「Transit Gatewayの料金が気になる」という方に何か良い方法は無いかと考えた時に思いつきました。

Network Load Balancerを使用したOverlay IPルーティング

今回は、FSx for ONTAPにNetwork Load Balancer(以降、NLB)経由でアクセスしてみたので紹介します。

2022/12/10 追記 : AWS Storage BlogにもFSx for ONTAPにNLB経由でアクセスする記事が投稿されました。AWSが私に追いついてきました。併せて以下記事もご覧ください。

いきなりまとめ

  • FSx for ONTAPがMulti-AZ構成の場合に付与される一部のIPアドレスはVPCのCIDR外のFloating IPになる
  • NLBを使用したOverlay IPルーティング構成を取ることで、NLB経由でFSx for ONTAPにアクセスできる
    • ただし、本番利用する際はよく検証した上で自己責任でご利用を
  • Floating IPが設定されているFSx for ONTAPファイルシステムとSVMの数分、NLBを作成する
  • ターゲットグループに指定できるIPアドレスに制限があるためエンドポイントIPアドレスの範囲は以下の範囲内のCIDRを指定する必要がある
    • ターゲットグループの VPC のサブネット
    • 10.0.0.0/8 (RFC 1918)
    • 100.64.0.0/10 (RFC 6598)
    • 172.16.0.0/12 (RFC 1918)
    • 192.168.0.0/16 (RFC 1918)

そもそも何故Transit Gatewayが必要か

そもそも何故、FSx for ONTAPがMulti-AZ構成の場合にTransit Gatewayが必要かを説明します。

一言で言えば、FSx for ONTAPがMulti-AZ構成の場合に付与されるIPアドレスが、VPCのCIDR外のFloating IPであるためです。

??? ですね。もう少し詳細に説明します。

AWS公式ドキュメントに記載の通り、FSx for ONTAPをMulti-AZ構成にする場合は、エンドポイントIPアドレスの範囲を設定する必要があります。設定したエンドポイントIPアドレスの範囲で以下のIPアドレスが割り当てられます。

  • ファイルシステムの管理エンドポイントIPアドレス
  • SVMの管理IPアドレス、NFS IPアドレス

割り当てられたIPアドレスはルートテーブルのルートで送信先として指定されます。ターゲットには優先サブネット上のENIが登録されており、障害が発生した場合はスタンバイサブネット上のENIに自動的に切り替わります。

参考:

エンドポイントIPアドレスの範囲で設定するIPアドレスの範囲は以下のどちらかを満たす必要があります。

  • VPCのルートテーブル内の既存のCIDRと競合しないCIDR
  • VPCのルートテーブル内の既存のCIDRよりも具体的なCIDR

(マルチ AZ のみ) [Endpoint IP address range] (エンドポイント IP アドレスの範囲) で、ファイルシステムにアクセスするためのエンドポイントを作成する、IP アドレスの範囲を指定します。

重要

ファイルシステムに対して選択するエンドポイント IP アドレスの範囲は、VPC のルートテーブル内の既存の CIDR 範囲と競合しないか、厳密なサブセット (つまり、より具体的である必要があります) でなければなりません。アドレス範囲の最大許容サイズは /16 です。

FSx for ONTAP ファイルシステムの管理 - FSx for ONTAP

加えて、前提条件としてVPCは以下のようにVPCをまたぐ通信(トランジット通信)はできません。

推移的なピアリング接続

VPC ピアリングを使用する代わりに、ネットワークの中継ハブとして機能する AWS Transit Gateway を使用して、VPC とオンプレミスネットワークを相互接続することができます。トランジットゲートウェイの詳細については、Amazon VPC トランジットゲートウェイの「トランジットゲートウェイとは」を参照してください。

VPC A と VPC B の間 (pcx-aaaabbbb)、および、VPC A と VPC C の間 (pcx-aaaacccc) に VPC ピアリング接続が設定されています。VPC B と VPC C の間には VPC ピアリング接続がありません。VPC A を経由して VPC B から VPC C にパケットを直接ルーティングすることはできません。

ゲートウェイまたはプライベート接続経由のエッジツーエッジルーティング

ピアリング接続の VPC に次のいずれかの関係がある場合、その接続にピア関係を拡張することはできません。

  • 社内ネットワークに対する VPN 接続または AWS Direct Connect 接続
  • インターネットゲートウェイ経由のインターネット接続
  • NAT デバイス経由のプライベートサブネットのインターネット接続
  • AWS のサービスへのゲートウェイ VPC エンドポイント (たとえば、Amazon S3 へのエンドポイント)。
  • (IPv6) ClassicLink 接続。リンクされた EC2-Classic インスタンスと VPC ピアリング接続の別の側の VPC のインスタンス間で IPv4 通信を有効にすることができます。ただし、EC2-Classic では IPv6 はサポートされていないため、IPv6 通信用にこの接続を拡張することはできません。

たとえば、VPC A と VPC B がピアリング接続され、VPC A にこれらのいずれかの接続がある場合、VPC B のインスタンスはこの接続を使用して、接続の他方の側にあるリソースにアクセスすることはできません。同様に、接続の他方の側にあるリソースは、この接続を使用して VPC B にアクセスすることはできません。

サポートされていない VPC ピア接続設定 - Amazon Virtual Private Cloud

上述の3つの条件を見て、「VPCのCIDR内のCIDRをエンドポイントIPアドレスの範囲用に指定すれば良いのでは?」と思った方がいらっしゃるかもしれません。

残念ながら、それはできません。

ルートテーブルでは、「VPCのCIDR内」かつ「サブネットのCIDR外」を送信先にしたルートを指定することはできません。例として以下のような条件で考えます。

  • VPCのCIDR : 10.0.0.0/16
  • サブネットのCIDR : 10.0.0.0/24
  • エンドポイントIPアドレスの範囲 : 10.0.1.0/24

コンソールから上述の条件で送信先が10.0.1.0/24のルートを作成しようとすると、VPCのCIDR内(10.0.0.0/16)に10.0.1.0/24というサブネットがないためRoute destination doesn't match any subnet CIDR blocks.とエラーになってしまいます。

このような状況でさらに思いつくのは、「エンドポイントIPアドレスの範囲用サブネット」を作成しておくことですが、こちらも設定できません。何故なら、FSx for ONTAPファイルシステム作成時に設定されるルートの送信先はエンドポイントIPアドレスの範囲内のIPアドレス (xxx.xxx.xxx.xxx/32)になるためです。例として以下のような条件で考えます。

  • VPCのCIDR : 10.0.0.0/16
  • サブネットのCIDR : 10.0.0.0/2410.0.1.0/24
  • エンドポイントIPアドレスの範囲 : 10.0.1.0/24

コンソールから上述の条件で送信先がエンドポイントIPアドレスの範囲内のIPアドレス10.0.1.10/32のルートを作成しようとすると、VPCのCIDR内(10.0.0.0/16)に10.0.1.10/32というサブネットがないためRoute destination doesn't match any subnet CIDR blocks.と同様のエラーが出力されます。

以上の理由から、エンドポイントIPアドレスの範囲には、VPCのCIDR外のCIDRを指定する必要があります。

そして、VPCはトランジット通信はできないので、Transit Gatewayが必要になります。

AWS公式ドキュメントにも記載がありますね。

NFS、SMB、ONTAP CLI および REST API へのアクセス

マルチ AZ ファイルシステムの場合、NFS または SMB 経由の Amazon FSx for NetApp ONTAP へのアクセス、または ONTAP CLI または REST API を使用したファイルシステムの管理に使用されるエンドポイントは、ファイルシステムに関連付けた VPC ルートテーブルで作成されるフローティング IP アドレスです。これらの IP アドレスはファイルシステムを作成するときに指定できる EndpointIpAddressRange にあります。デフォルトでは、Amazon FSx は 198.19.0.0/16 IP アドレス範囲から IP アドレス範囲を選択します。フローティング IP アドレスにより、管理、NFS、SMB トラフィックが、優先ファイルサーバーとスタンバイファイルサーバー間でシームレスにフェイルオーバーできます。詳細情報は、「FSx for ONTAP のフェイルオーバープロセス」セクションから入手できます。NFS、SMB、管理エンドポイントはフローティング IP を使用するため、FSx for ONTAP ファイルシステムがデプロイされている VPC の外部のインターフェイスにアクセスするには、AWS Transit Gateway が必要です。これは、VPC ピアリングがフローティング IP (推移的なピアリング接続とも呼ばれます) へのルーティングをサポートしていないためです。

AWS 内からデータにアクセスする - FSx for ONTAP

Transit Gatewayを経由して行う通信は以下のように紹介されています。NFSやSMBを使ってオンプレミス環境や、他のVPCから直接マウントする場合はTransit Gatewayが必要です。

データアクセス Transit Gateway は必要ですか。
NFS、SMB、NetApp ONTAP REST API/CLI 経由の FSx へのアクセス 次の場合に限ります。
- ピアリング接続されたネットワーク (オンプレミスなど) からアクセスし、
- NetApp FlexCache またはグローバルファイルキャッシュインスタンスから FSx にアクセスしない
iSCSI 経由でデータにアクセスする なし
SVM をアクティブディレクトリに結合する なし
SnapMirror なし
FlexCache キャッシュ なし
Global File Cache なし

抜粋 : AWS 内からデータにアクセスする - FSx for ONTAP

Network Load Balancerを使用したOverlay IPルーティングとは

それでは、NLBを使用したOverlay IPルーティングについて紹介します。

NLBを使用したOverlay IPルーティングを一言で言うと、NLBをDestination NAT(DNAT)装置として使い、VPCのCIDR外のFloating IPにアクセスする方法です。

こちらは、SAP on AWSのドキュメントで紹介されていたSAP HANAにTransit Gatewayを使わずにアクセスする方法から着想を得ました。

以下図中のASCSやHANAのEC2インスタンスがFSx for ONTAPのENIになるイメージです。

抜粋 : Architecture - SAP HANA on AWS

注意点としては、エンドポイントIPアドレスの範囲がターゲットグループで指定できるIPアドレスの範囲内である必要があります。

エンドポイントIPアドレスの範囲のデフォルトは198.19.255.0/24です。

ターゲットグループで指定できるIPアドレスの範囲は以下の通りです。

  • ターゲットグループの VPC のサブネット
  • 10.0.0.0/8 (RFC 1918)
  • 100.64.0.0/10 (RFC 6598)
  • 172.16.0.0/12 (RFC 1918)
  • 192.168.0.0/16 (RFC 1918)

抜粋 : ターゲットグループへのターゲットの登録 - Elastic Load Balancing

そのため、エンドポイントIPアドレスの範囲をデフォルトのままでFSx for ONTAPファイルシステムを作成してしまうと、こちらの構成を取ることはできません。エンドポイントIPアドレスの範囲を後から変更することはできないので、FSx for ONTAPファイルシステムを作り直すことになるので要注意です。

やってみた

検証の構成

それでは、NLBを使用したOverlay IPルーティングを使って、Multi-AZ構成のFSx for ONTAPファイルシステムに接続してみます。

検証の構成は以下の通りです。

構成図

エンドポイントIPアドレスの範囲172.31.255.0/24にしたMulti-AZ構成のFSx for ONTAPファイルシステムを作成し、ファイルシステムとSVMの管理IPアドレスに対してNLBでルーティングします。

アクセス元のEC2インスタンスは別のVPC上に用意しました。VPC間はTransit Gatewayではなく、VPCピアリングで接続します。アクセス元のEC2インスタンスからNLBを介してNFSとSMBでマウントできることを確認します。

FSx for ONTAPファイルシステムのデプロイ

まず、FSx for ONTAPファイルシステムをデプロイします。

前回同様、AWS CDKでデプロイします。

準備したコードは以下リポジトリに格納してあります。

まず、事前準備としてドメイン情報をSecrets Managerに保存します。SVMがドメイン参加する際にこちらのシークレットを使います。

$ service_account_password='xxxx'
$ secret_json=$(cat <<EOM
{
  "domainName": "fsx-dev.classmethod.jp",
  "fileSystemAdministratorsGroup": "FSxAdminGroup",
  "organizationalUnitDistinguishedName": "OU=FSxForNetAppONTAP,DC=fsx-dev,DC=classmethod,DC=jp",
  "userName": "FSxServiceAccount",
  "password": "$service_account_password"
}
EOM
)

$ aws secretsmanager create-secret \
    --name "/fsx-dev.classmethod.jp/FSxForNetAppONTAP/ServiceAccount" \
    --secret-string "$secret_json"
{
    "ARN": "arn:aws:secretsmanager:ap-northeast-1:<AWSアカウントID>:secret:/fsx-dev.classmethod.jp/FSxForNetAppONTAP/ServiceAccount-p7l2XZ",
    "Name": "/fsx-dev.classmethod.jp/FSxForNetAppONTAP/ServiceAccount",
    "VersionId": "252f66cf-c51c-4000-827f-f94b61ec14f5"
}

下準備が終わったらAWS CDKでFSx for ONTAPのリソースをデプロイします。npx cdk deployでデプロイすると、NLBとターゲットグループ以外の各種リソースが作成されます。

NLBの設定

それではNLB周りの設定を行なっていきます。今回は全てAWS CLIで設定していきます。

まず、Floating IPであるFSx for ONTAPファイルシステムの管理エンドポイントIPアドレスとSVMの管理IPアドレスを取得して配列に保存します。

$ file_system_id=fs-038b1517ef3b4a2d1

# FSx for ONTAPファイルシステムの管理エンドポイントIPアドレスを取得
$ file_system_management_ip_addresses=$(aws fsx describe-file-systems \
    --file-system-ids "$file_system_id" \
  | jq -r ".FileSystems[].OntapConfiguration.Endpoints.Management.IpAddresses[]"
)

# FSx for ONTAPファイルシステムの管理エンドポイントIPアドレスを確認
$ echo "$file_system_management_ip_addresses"
172.31.255.131

# SVMの管理IPアドレスを取得
$ svm_management_ip_addresses=$(aws fsx describe-storage-virtual-machines \
    --filters Name=file-system-id,Values="$file_system_id" \
  | jq -r ".StorageVirtualMachines[].Endpoints.Management.IpAddresses[]"
)

# SVMの管理IPアドレスを確認
$ echo "$svm_management_ip_addresses"
172.31.255.108

# FSx for ONTAPファイルシステムの管理エンドポイントIPアドレスとSVMの管理IPアドレスを配列に保存
$ declare -a target_ip_addresses=($file_system_management_ip_addresses $svm_management_ip_addresses)

# 保存されているか確認
$ echo ${target_ip_addresses[@]}
172.31.255.131 172.31.255.108

次に、FSx for ONTAPで使用するプロトコルとポートごとのターゲットグループを作成します。

iSCSIやSnapMirrorはFloating IPを使用しないので、ターゲットグループは作成しなくても良いですが勢いで作成しました。

$ vpc_id=vpc-0bdab140380e5888e

# FSx for ONTAPで使用するプロトコルとポートの組み合わせを配列で定義
$ protocol_port_array=($(cat <<EOM
  {"Protocol":"TCP","Port":"22"}
  {"Protocol":"TCP","Port":"443"}
  {"Protocol":"TCP","Port":"445"}
  {"Protocol":"TCP","Port":"749"}
  {"Protocol":"TCP","Port":"3260"}
  {"Protocol":"TCP","Port":"11104"}
  {"Protocol":"TCP","Port":"11105"}
  {"Protocol":"TCP_UDP","Port":"111"}
  {"Protocol":"TCP_UDP","Port":"135"}
  {"Protocol":"TCP_UDP","Port":"139"}
  {"Protocol":"TCP_UDP","Port":"161"}
  {"Protocol":"TCP_UDP","Port":"162"}
  {"Protocol":"TCP_UDP","Port":"635"}
  {"Protocol":"TCP_UDP","Port":"2049"}
  {"Protocol":"TCP_UDP","Port":"4045"}
  {"Protocol":"TCP_UDP","Port":"4046"}
  {"Protocol":"UDP","Port":"137"}
  {"Protocol":"UDP","Port":"4049"}
EOM
))

# FSx for ONTAPファイルシステムの管理エンドポイントIPアドレスとSVMの管理IPアドレスについて、プロトコルとポートの組み合わせ毎にターゲットグループを作成
# 併せてターゲットとして、FSx for ONTAPファイルシステムの管理エンドポイントIPアドレス、もしくはSVMの管理IPアドレスを設定する
$ for target_ip_address in "${target_ip_addresses[@]}"; do
    target_group_prefix="${target_ip_address//./-}"

    for protocol_port_hash in "${protocol_port_array[@]}"; do
        protocol=$(echo "$protocol_port_hash" | jq -r ".Protocol")
        protocol_sanitized="${protocol//_/-}"
        port=$(echo "$protocol_port_hash" | jq -r ".Port")
        
        create_target_group_input=$(cat <<EOM
        {
            "Name": "${target_group_prefix}-${protocol_sanitized}-${port}",
            "Protocol": "$protocol",
            "Port": $port,
            "VpcId": "$vpc_id",
            "HealthCheckProtocol": "TCP",
            "HealthCheckPort": "443",
            "HealthCheckEnabled": true,
            "TargetType": "ip",
            "Tags": [
                {
                    "Key": "Target Ip Address",
                    "Value": "$target_ip_address"
                },
                {
                    "Key": "Protocol",
                    "Value": "$protocol"
                },
                {
                    "Key": "Port",
                    "Value": "$port"
                }
            ]
        }
EOM
        )

        target_group_arn=$(aws elbv2 create-target-group \
            --cli-input-json "$create_target_group_input" \
          | jq -r ".TargetGroups[].TargetGroupArn"
        )

        aws elbv2 register-targets \
            --target-group-arn "$target_group_arn" \
            --targets Id="$target_ip_address",AvailabilityZone=all
    done
done

# FSx for ONTAPファイルシステムの管理エンドポイントIPアドレスとSVMの管理IPアドレスについて、プロトコルとポートの組み合わせ毎にターゲットグループが作成されたか確認
$ aws elbv2 describe-target-groups \
  | jq -r ".TargetGroups[].TargetGroupName"
172-31-255-108-TCP-11104
172-31-255-108-TCP-11105
172-31-255-108-TCP-22
172-31-255-108-TCP-3260
172-31-255-108-TCP-443
172-31-255-108-TCP-445
172-31-255-108-TCP-749
172-31-255-108-TCP-UDP-111
172-31-255-108-TCP-UDP-135
172-31-255-108-TCP-UDP-139
172-31-255-108-TCP-UDP-161
172-31-255-108-TCP-UDP-162
172-31-255-108-TCP-UDP-2049
172-31-255-108-TCP-UDP-4045
172-31-255-108-TCP-UDP-4046
172-31-255-108-TCP-UDP-635
172-31-255-108-UDP-137
172-31-255-108-UDP-4049
172-31-255-131-TCP-11104
172-31-255-131-TCP-11105
172-31-255-131-TCP-22
172-31-255-131-TCP-3260
172-31-255-131-TCP-443
172-31-255-131-TCP-445
172-31-255-131-TCP-749
172-31-255-131-TCP-UDP-111
172-31-255-131-TCP-UDP-135
172-31-255-131-TCP-UDP-139
172-31-255-131-TCP-UDP-161
172-31-255-131-TCP-UDP-162
172-31-255-131-TCP-UDP-2049
172-31-255-131-TCP-UDP-4045
172-31-255-131-TCP-UDP-4046
172-31-255-131-TCP-UDP-635
172-31-255-131-UDP-137
172-31-255-131-UDP-4049

次に、NLBを作成します。

NLBはFSx for ONTAPファイルシステム用とSVM用とでそれぞれ必要です。今回はSVMが1つなので計2つですが、SVMが複数ある場合はその数分だけNLBが追加になります。

# FSx for ONTAPファイルシステムの管理エンドポイントIPアドレスとSVMの管理IPアドレスを配列に保存
declare -a nlb_ip_addresses=($file_system_management_ip_addresses $svm_management_ip_addresses)

# FSx for ONTAPファイルシステムの管理エンドポイントIPアドレスとSVMの管理IPアドレス毎にNLBを作成
for nlb_ip_address in "${nlb_ip_addresses[@]}"; do
    nlb_ip_address_sanitized="${nlb_ip_address//./-}"

    create_load_balancer_input=$(cat <<EOM
    {
        "Name": "nlb-${nlb_ip_address_sanitized}",
        "Subnets": [
            "subnet-0edad58231582149e",
            "subnet-02c64a402de04fc57"
        ],
        "Scheme": "internal",
        "Tags": [
            {
                "Key": "Target Ip Address",
                "Value": "$nlb_ip_address"
            }
        ],
        "Type": "network",
        "IpAddressType": "ipv4"
    }
EOM
    )

    aws elbv2 create-load-balancer \
        --cli-input-json "$create_load_balancer_input"
done
{
    "LoadBalancers": [
        {
            "LoadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:loadbalancer/net/nlb-172-31-255-131/18ca6bafadb7cca3",
            "DNSName": "nlb-172-31-255-131-18ca6bafadb7cca3.elb.ap-northeast-1.amazonaws.com",
            "CanonicalHostedZoneId": "Z31USIVHYNEOWT",
            "CreatedTime": "2022-05-31T06:13:43.547000+00:00",
            "LoadBalancerName": "nlb-172-31-255-131",
            "Scheme": "internal",
            "VpcId": "vpc-0bdab140380e5888e",
            "State": {
                "Code": "provisioning"
            },
            "Type": "network",
            "AvailabilityZones": [
                {
                    "ZoneName": "ap-northeast-1c",
                    "SubnetId": "subnet-02c64a402de04fc57",
                    "LoadBalancerAddresses": []
                },
                {
                    "ZoneName": "ap-northeast-1a",
                    "SubnetId": "subnet-0edad58231582149e",
                    "LoadBalancerAddresses": []
                }
            ],
            "IpAddressType": "ipv4"
        }
    ]
}
{
    "LoadBalancers": [
        {
            "LoadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:loadbalancer/net/nlb-172-31-255-108/c013af8e1ea63c44",
            "DNSName": "nlb-172-31-255-108-c013af8e1ea63c44.elb.ap-northeast-1.amazonaws.com",
            "CanonicalHostedZoneId": "Z31USIVHYNEOWT",
            "CreatedTime": "2022-05-31T06:13:44.465000+00:00",
            "LoadBalancerName": "nlb-172-31-255-108",
            "Scheme": "internal",
            "VpcId": "vpc-0bdab140380e5888e",
            "State": {
                "Code": "provisioning"
            },
            "Type": "network",
            "AvailabilityZones": [
                {
                    "ZoneName": "ap-northeast-1c",
                    "SubnetId": "subnet-02c64a402de04fc57",
                    "LoadBalancerAddresses": []
                },
                {
                    "ZoneName": "ap-northeast-1a",
                    "SubnetId": "subnet-0edad58231582149e",
                    "LoadBalancerAddresses": []
                }
            ],
            "IpAddressType": "ipv4"
        }
    ]
}

最後にNLBのリスナーの設定です。作成したNLBとターゲットグループを関連付けます。

# NLBのARNを取得
$ declare -a nlb_arns=($(aws elbv2 describe-load-balancers \
  | jq -r ".LoadBalancers[].LoadBalancerArn"
))
$ echo ${nlb_arns[@]}
arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:loadbalancer/net/nlb-172-31-255-131/18ca6bafadb7cca3 arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:loadbalancer/net/nlb-172-31-255-108/c013af8e1ea63c44

# ターゲットグループ一覧を取得
$ target_groups=$(aws elbv2 describe-target-groups \
  | jq -r ".TargetGroups"
)
$ target_groups_length=$(echo "${target_groups}" \
  | jq length
)

# NLBにリスナーを作成し、ターゲットグループを関連付ける
$ for i in $(seq 0 $((${target_groups_length} - 1))); do
    target_group=$(echo ${target_groups} | jq .[${i}])

    target_group_name=$(echo "$target_group" | jq -r ".TargetGroupName")
    target_group_arn=$(echo "$target_group" | jq -r ".TargetGroupArn")
    protocol=$(echo "$target_group" | jq -r ".Protocol")
    port=$(echo "$target_group" | jq -r ".Port")

    ip_address_sanitized=$(echo "$target_group_name}" \
      | grep -o '[0-9]\+-[0-9]\+-[0-9]\+-[0-9]\+'
    )
    ip_address="${ip_address_sanitized//-/.}"

    aws elbv2 register-targets \
        --target-group-arn "$target_group_arn" \
        --targets Id="$ip_address",AvailabilityZone=all

    for nlb_arn in "${nlb_arns[@]}"; do
        if [[ ! "$nlb_arn" =~ "$ip_address_sanitized" ]]; then
            continue
        fi

        aws elbv2 create-listener \
            --load-balancer-arn "$nlb_arn" \
            --protocol "$protocol" \
            --port $port \
            --default-actions Type=forward,TargetGroupArn="$target_group_arn"
    done
done
{
    "Listeners": [
        {
            "ListenerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:listener/net/nlb-172-31-255-108/c013af8e1ea63c44/dadd51be42e3d48c",
            "LoadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:loadbalancer/net/nlb-172-31-255-108/c013af8e1ea63c44",
            "Port": 11104,
            "Protocol": "TCP",
            "DefaultActions": [
                {
                    "Type": "forward",
                    "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:targetgroup/172-31-255-108-TCP-11104/b3f7de0ccd6fbc8c",
                    "ForwardConfig": {
                        "TargetGroups": [
                            {
                                "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:targetgroup/172-31-255-108-TCP-11104/b3f7de0ccd6fbc8c"
                            }
                        ]
                    }
                }
            ]
        }
    ]
}
{
    "Listeners": [
        {
            "ListenerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:listener/net/nlb-172-31-255-108/c013af8e1ea63c44/626b0a83f4ba62dd",
            "LoadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:loadbalancer/net/nlb-172-31-255-108/c013af8e1ea63c44",
            "Port": 11105,
            "Protocol": "TCP",
            "DefaultActions": [
                {
                    "Type": "forward",
                    "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:targetgroup/172-31-255-108-TCP-11105/a75a9c8c59f1cc33",
                    "ForwardConfig": {
                        "TargetGroups": [
                            {
                                "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:targetgroup/172-31-255-108-TCP-11105/a75a9c8c59f1cc33"
                            }
                        ]
                    }
                }
            ]
        }
    ]
}
{
    "Listeners": [
        {
            "ListenerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:listener/net/nlb-172-31-255-108/c013af8e1ea63c44/0080fc477ddc749a",
            "LoadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:loadbalancer/net/nlb-172-31-255-108/c013af8e1ea63c44",
            "Port": 22,
            "Protocol": "TCP",
            "DefaultActions": [
                {
                    "Type": "forward",
                    "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:targetgroup/172-31-255-108-TCP-22/6dbcf4cf7a8cb3fc",
                    "ForwardConfig": {
                        "TargetGroups": [
                            {
                                "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:targetgroup/172-31-255-108-TCP-22/6dbcf4cf7a8cb3fc"
                            }
                        ]
                    }
                }
            ]
        }
    ]
}
.
.
(中略)
.
.
{
    "Listeners": [
        {
            "ListenerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:listener/net/nlb-172-31-255-131/18ca6bafadb7cca3/1427680f898f7b97",
            "LoadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:loadbalancer/net/nlb-172-31-255-131/18ca6bafadb7cca3",
            "Port": 137,
            "Protocol": "UDP",
            "DefaultActions": [
                {
                    "Type": "forward",
                    "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:targetgroup/172-31-255-131-UDP-137/49f7ca090de4590e",
                    "ForwardConfig": {
                        "TargetGroups": [
                            {
                                "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:targetgroup/172-31-255-131-UDP-137/49f7ca090de4590e"
                            }
                        ]
                    }
                }
            ]
        }
    ]
}
{
    "Listeners": [
        {
            "ListenerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:listener/net/nlb-172-31-255-131/18ca6bafadb7cca3/c1690508e9ec09d2",
            "LoadBalancerArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:loadbalancer/net/nlb-172-31-255-131/18ca6bafadb7cca3",
            "Port": 4049,
            "Protocol": "UDP",
            "DefaultActions": [
                {
                    "Type": "forward",
                    "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:targetgroup/172-31-255-131-UDP-4049/75c9783cbcb26768",
                    "ForwardConfig": {
                        "TargetGroups": [
                            {
                                "TargetGroupArn": "arn:aws:elasticloadbalancing:ap-northeast-1:<AWSアカウントID>:targetgroup/172-31-255-131-UDP-4049/75c9783cbcb26768"
                            }
                        ]
                    }
                }
            ]
        }
    ]
}

動作確認

SSH

それでは、動作確認です。

まず、SSHでFSx for ONTAPファイルシステムとSVMに接続できるか確認します。

ターゲットグループでステータスがhealthyになった後、NLBのDNS名(nlb-172-31-255-131-18ca6bafadb7cca3.elb.ap-northeast-1.amazonaws.com)にSSHします。

# FSx for ONTAPファイルシステムにSSH
$ ssh fsxadmin@nlb-172-31-255-131-a1785226825aa0ea.elb.ap-northeast-1.amazonaws.com
The authenticity of host 'nlb-172-31-255-131-a1785226825aa0ea.elb.ap-northeast-1.amazonaws.com (10.0.10.29)' can't be established.
ECDSA key fingerprint is SHA256:ADAx3P4wxoDRojBabySzk+EdVXWWxOr9Xh6qLFymBG0.
ECDSA key fingerprint is MD5:c7:0e:76:bb:cb:bd:73:95:62:e6:5f:0e:b8:15:98:48.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'nlb-172-31-255-131-a1785226825aa0ea.elb.ap-northeast-1.amazonaws.com,10.0.10.29' (ECDSA) to the list of known hosts.
Password:
This is your first recorded login.

# FSx for ONTAPファイルシステムの論理インターフェイス(LIF)を確認
::> network interface show
            Logical    Status     Network            Current       Current Is
Vserver     Interface  Admin/Oper Address/Mask       Node          Port    Home
----------- ---------- ---------- ------------------ ------------- ------- ----
FsxId038b1517ef3b4a2d1
            fsxadmin     up/up    172.31.255.131/24  FsxId038b1517ef3b4a2d1-01
                                                                   e0e     true
            inter_1      up/up    10.0.10.198/24     FsxId038b1517ef3b4a2d1-01
                                                                   e0e     true
            inter_2      up/up    10.0.11.201/24     FsxId038b1517ef3b4a2d1-02
                                                                   e0e     true
fsx-for-ontap-svm-001
            iscsi_1      up/up    10.0.10.221/24     FsxId038b1517ef3b4a2d1-01
                                                                   e0e     true
            iscsi_2      up/up    10.0.11.57/24      FsxId038b1517ef3b4a2d1-02
                                                                   e0e     true
            nfs_smb_management_1
                         up/up    172.31.255.108/24  FsxId038b1517ef3b4a2d1-01
                                                                   e0e     true
6 entries were displayed.

できらぁ!ということで無事、接続できました。

次にSVMにSSHします。NLBのDNS名(nlb-172-31-255-108-c013af8e1ea63c44.elb.ap-northeast-1.amazonaws.com)にSSHします。

# SVMにSSH
$ ssh vsadmin@nlb-172-31-255-108-c81b7fd42d220f34.elb.ap-northeast-1.amazonaws.com
The authenticity of host 'nlb-172-31-255-108-c81b7fd42d220f34.elb.ap-northeast-1.amazonaws.com (10.0.11.101)' can't be established.
ECDSA key fingerprint is SHA256:0aqinzCQShbKPZ1cEhMb9+FaW5mdCLCqIx6RGB+ylhI.
ECDSA key fingerprint is MD5:45:36:be:71:bb:c0:e5:64:9e:65:2f:dc:6e:c5:ce:f1.
Are you sure you want to continue connecting (yes/no)? yes
Warning: Permanently added 'nlb-172-31-255-108-c81b7fd42d220f34.elb.ap-northeast-1.amazonaws.com,10.0.11.101' (ECDSA) to the list of known hosts.
Password:

This is your first recorded login.

# SVMの論理インターフェイス(LIF)を確認
::> network interface show
            Logical    Status     Network            Current       Current Is
Vserver     Interface  Admin/Oper Address/Mask       Node          Port    Home
----------- ---------- ---------- ------------------ ------------- ------- ----
fsx-for-ontap-svm-001
            iscsi_1      up/up    10.0.10.221/24     FsxId038b1517ef3b4a2d1-01
                                                                   e0e     true
            iscsi_2      up/up    10.0.11.57/24      FsxId038b1517ef3b4a2d1-02
                                                                   e0e     true
            nfs_smb_management_1
                         up/up    172.31.255.108/24  FsxId038b1517ef3b4a2d1-01
                                                                   e0e     true
3 entries were displayed.

# SVMの表示
::> vserver show
                               Admin      Operational Root
Vserver     Type    Subtype    State      State       Volume     Aggregate
----------- ------- ---------- ---------- ----------- ---------- ----------
fsx-for-ontap-svm-001
            data    default    running    running     fsx_for_   aggr1
                                                      ontap_svm_
                                                      001_root

SVMもできらぁ!ということで接続できました。

NFS

続いてNFSでマウントできるか確認してみます。

# 現在のディスクサイズ一覧を表示
$ df -hT
Filesystem     Type      Size  Used Avail Use% Mounted on
devtmpfs       devtmpfs  471M     0  471M   0% /dev
tmpfs          tmpfs     479M     0  479M   0% /dev/shm
tmpfs          tmpfs     479M  400K  478M   1% /run
tmpfs          tmpfs     479M     0  479M   0% /sys/fs/cgroup
/dev/nvme0n1p1 xfs       8.0G  1.5G  6.6G  19% /
tmpfs          tmpfs      96M     0   96M   0% /run/user/0

# マウントポイントを作成
$ sudo mkdir /nfs

# マウント
$ sudo mount -t nfs nlb-172-31-255-108-c81b7fd42d220f34.elb.ap-northeast-1.amazonaws.com:/nfs /nfs

# マウントされたことを確認
$ df -hT
Filesystem                                                                Type      Size  Used Avail Use% Mounted on
devtmpfs                                                                  devtmpfs  471M     0  471M   0% /dev
tmpfs                                                                     tmpfs     479M     0  479M   0% /dev/shm
tmpfs                                                                     tmpfs     479M  404K  478M   1% /run
tmpfs                                                                     tmpfs     479M     0  479M   0% /sys/fs/cgroup
/dev/nvme0n1p1                                                            xfs       8.0G  1.5G  6.6G  19% /
tmpfs                                                                     tmpfs      96M     0   96M   0% /run/user/0
nlb-172-31-255-108-c81b7fd42d220f34.elb.ap-northeast-1.amazonaws.com:/nfs nfs4      973M  384K  973M   1% /nfs

# 任意のファイルを作成できることを確認
$ sudo mkdir /nfs/test-dir
$ sudo touch /nfs/test-dir/file
$ ls -l /nfs/test-dir
total 0
-rw-r--r-- 1 root root 0 May 31 10:21 file

NFSを使ったマウントもできますね。

SMB

# 現在のドライブ一覧を表示
> Get-PSDrive

Name           Used (GB)     Free (GB) Provider      Root                                                               CurrentLocation
----           ---------     --------- --------      ----                                                               ---------------
Alias                                  Alias
C                  13.05         16.95 FileSystem    C:\                                                               Windows\system32
Cert                                   Certificate   \
Env                                    Environment
Function                               Function
HKCU                                   Registry      HKEY_CURRENT_USER
HKLM                                   Registry      HKEY_LOCAL_MACHINE
Variable                               Variable
WSMan                                  WSMan

# ZドライブにFSx for ONTAPのボリュームを割り当て
> net use Z: \\nlb-172-31-255-108-c81b7fd42d220f34.elb.ap-northeast-1.amazonaws.com\C$\smb
\\nlb-172-31-255-108-c81b7fd42d220f34.elb.ap-northeast-1.amazonaws.com\C$\smb のパスワードが無効です。

'nlb-172-31-255-108-c81b7fd42d220f34.elb.ap-northeast-1.amazonaws.com' のユーザー名を入力してください: fsx-dev.classmethod.jp\FSxAdmin
nlb-172-31-255-108-c81b7fd42d220f34.elb.ap-northeast-1.amazonaws.com のパスワードを入力してください:
コマンドは正常に終了しました。

# Zドライブに割り当てられたことを確認
> Get-PSDrive

Name           Used (GB)     Free (GB) Provider      Root                                                               CurrentLocation
----           ---------     --------- --------      ----                                                               ---------------
Alias                                  Alias
C                  13.49         16.51 FileSystem    C:\                                                               Windows\system32
Cert                                   Certificate   \
Env                                    Environment
Function                               Function
HKCU                                   Registry      HKEY_CURRENT_USER
HKLM                                   Registry      HKEY_LOCAL_MACHINE
Variable                               Variable
WSMan                                  WSMan
Z                   0.00          0.95 FileSystem    \\nlb-172-31-255-108-c81b7fd42d2...


# Zドライブに任意のフォルダを作成できることを確認
> New-Item Z:\test-dir -type directory


    ディレクトリ: Z:\


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
d-----        2022/05/31     10:37                test-dir


> New-Item Z:\test-dir\file


    ディレクトリ: Z:\test-dir


Mode                 LastWriteTime         Length Name
----                 -------------         ------ ----
-a----        2022/05/31     10:38              0 file

SMBでもマウントできました。

本番利用する際は自己責任で

FSx for ONTAPにNLB経由でアクセスしてみました。

NLB経由でもFSx for ONTAPファイルシステムやSVMへのSSHとNFS、SMBを使ったマウントができることを確認できて大満足です。

ただし、AWS公式ではTransit Gatewayを使うことを案内しており、NLBを使うのはある種、裏技的なものです。そのため本番利用でFSx for ONTAPにNLB経由でアクセスするような構成を取る場合は、料金や性能などをよく検証をした上で自己責任でご使用ください。

また、FSx for ONTAPの使い勝手を確認してみたいという方はMulti-AZ構成ではなく、Single-AZ構成で検証してみることをオススメします。Single-AZ構成の場合はエンドポイントIPアドレスの範囲を設定する必要がないため、Transit Gatewayを使わずにVPC外のネットワークからFSx for ONTAPにアクセスできます。

この記事が誰かの助けになれば幸いです。

以上、AWS事業本部 コンサルティング部の のんピ(@non____97)でした!