NLBとALBの直接接続する際の注意点
AWSのNLBとALBを直接接続した構成を構築する機会があった。せっかくなので検証した内容などを記録しておく。
なお、この機能の利用方法は下記ドキュメントに記載されている。
Application Load Balancers as targets
背景
最近、下記要件を満たすようにELBを構成する必要があった。
- ホストベースルーティング機能が必要
- 固定IPである必要がある
これら要件を満たすには単純にALBやNLBを1つ立てればよいとはならない。
というのも1の要件を満たすにはALB、2の要件を満たすにはNLBを利用する必要がある。
以前も同様の要件で構築したことがあるが、そのときは下記構成で構築した。
固定IP化をNLBで行い、リクエストをnginxを用いたプロキシサーバを用いてALBへパススルーすることで実現した。
しかし今回は、下記構成で構築した。
この構成は9月末に発表された機能によって実現できるようになった。以前の構成と見比べてもらえばすぐに分かるが、プロキシサーバなしでNLBとALBを直接接続している。これにより、プロキシサーバを構築する必要なく(運用対象の削減!)、NLBの機能をALBの機能をどちらも同時に利用する事が可能になった。
NLBとALB直接接続の利点
まず最初に、この機能の利点について。
NLBとALBの機能を同時に利用できるようになったこと、主にNLBの機能であった下記機能をALBで利用可能になったのがうれしいところ。
- ALBのIPの固定化が可能
- ALBをNLBを介してPrivateLinkで公開可能
今回はIPの固定化のために利用しているが、PrivateLinkをALBで利用したいときもこの構成が使える。
なお、PrivateLinkを用いてALBを別VPCに公開する方法についてはAWSのブログで紹介されているので気になる方はそちらへ。
Network Load BalancerのターゲットグループにApplication Load Balancerを設定する
HTTPS通信で利用する場合
HTTPS通信を受けたい場合は注意すべき点が1つある。
それは、TLSの終端をALBにする必要がある点。
NLBとALBを接続する機能はNLBのTLSリスナではサポートしておらず、TCPリスナを利用する必要がある。そのため、必然的にALBを側でHTTPSリスナを用意し、TLSを終端する必要がある。
ちなみに、この制約によりNLBではログが取得できない。(NLBはTLSリスナしかログを収集できない)
ヘルスチェックの注意点
NLBからALBへのリクエスト転送はNLBのターゲットグループのヘルスチェックに合格しないと開始されない。
この機能を利用する際のヘルスチェックの仕様として注意すべき点は下記。
- ヘルスチェックの多くの設定は変更不可
- 送信元IPはNLBのローカルIPとなる
- プロトコルはHTTPかHTTPSのみ利用可能
- ALB側のレスポンスコードは200~399の範囲である必要がある
ヘルスチェックの多くの設定は変更不可
ALBとターゲットとした場合、ターゲットグループのヘルスチェック設定の多くは設定変更不可。基本的にデフォルトの値で利用することになる。
変更不可な設定は下記。
- Unhealthyとみなすヘルスチェック失敗の閾値
- ヘルスチェック失敗とみなすタイムアウト時間
- ヘルスチェック間隔時間
- ヘルスチェック成功とするステータスコード
こちらはドキュメントに記載されている。
For Advanced health check settings, you cannot modify Unhealthy threshold, Timeout, Interval, and Success codes.
ちなみにCloudFormationのデフォルト設定で構築した際の設定は下記となる。
その時利用したコードは下記。
InternetNLBTargetToALB:
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
Port: 80
Protocol: TCP
Targets:
- Id: !Ref InternalALB
Port: 80
TargetType: alb
VpcId: !Ref VPC
送信元IPはNLBのローカルIP
ALBへ行われるヘルスチェックの送信元IPはNLBのローカルIPとなる。(サブネットのCidrから採番されたIP)
そのため、ALB側のSecurityGroupでNLBのローカルIPからの通信を許可しておく必要がある。
プロトコルはHTTPかHTTPSのみ利用可能
ターゲットグループのポート設定はTCPしか許可されていないため、勘違いしやすいポイント。
ヘルスチェックプロトコルはHTTPかHTTPSのみ利用可能であり、TCPなどは利用不可となっている。
For Health checks, choose HTTP or HTTPS as the Health check protocol.
なお、CloudFormationで作成した場合、NLB用のターゲットグループのヘルスチェックポートはデフォルトだとTCPになるが、ALBをターゲットにした場合のみHTTPとなるので注意が必要。
※この情報はドキュメントが追いついていないので記載されていない。
ALB側のレスポンスコードは200~399
ヘルスチェックに対するレスポンスのステータスコードは200〜399である必要がある。
ALBのリスナルールでNLBからのリクエストは上記ステータスコードでレスポンスするように設定する必要がある。
下記はCloudFormationで構築する際の例。NLBのローカルIPからのリクエストに対して200番を返す設定としている。
ListenerRuleForNLBHealthCheck:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
- Type: fixed-response
FixedResponseConfig:
StatusCode: '200'
Conditions:
- Field: source-ip
SourceIpConfig:
Values:
- !Ref NLBCidr # NLBが存在するサブネットのCidr
ListenerArn: !Ref InternalALBListener
Priority: 1
おまけ:検証に利用したCloudFormationテンプレート
最後に検証で利用したCloudFormationテンプレートを記載しておく。これをデプロイすることで、NLBとALBをHTTPで接続した環境が構築される。(VPCなどは記載されていないので、別途作成する必要があり)
AWSTemplateFormatVersion: '2010-09-09'
Description: This template is for ELB connection test.
It deploys internal Application Load Balancer and internet facing Network Load Balancer.
Parameters:
PublicSubnets:
Type: List<AWS::EC2::Subnet::Id>
PrivateSubnets:
Type: List<AWS::EC2::Subnet::Id>
VPC:
Type: AWS::EC2::VPC::Id
NLBCidr:
Type: String
Resources:
InternalALB:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Scheme: internal
SecurityGroups:
- !Ref SecurityGroupForInternalALB
Subnets: !Ref PrivateSubnets
Type: application
InternalALBListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: fixed-response
FixedResponseConfig:
StatusCode: '403'
ContentType: application/json
MessageBody: '{"message":"NG"}'
LoadBalancerArn: !Ref InternalALB
Port: 80
Protocol: HTTP
ListenerRule:
Type: AWS::ElasticLoadBalancingV2::ListenerRule
Properties:
Actions:
- Type: fixed-response
FixedResponseConfig:
StatusCode: '200'
ContentType: application/json
MessageBody: '{"message":"OK"}'
Conditions:
- Field: source-ip
SourceIpConfig:
Values:
- !Ref NLBCidr
ListenerArn: !Ref InternalALBListener
Priority: 1
SecurityGroupForInternalALB:
Type: AWS::EC2::SecurityGroup
Properties:
GroupDescription: It is for internal ALB
VpcId: !Ref VPC
SecurityGroupIngress:
- CidrIp: !Ref NLBCidr
IpProtocol: tcp
FromPort: 80
ToPort: 80
- CidrIp: 0.0.0.0/0
IpProtocol: tcp
FromPort: 80
ToPort: 80
InternetNLB:
Type: AWS::ElasticLoadBalancingV2::LoadBalancer
Properties:
Scheme: internet-facing
Subnets: !Ref PublicSubnets
Type: network
InternetNLBListener:
Type: AWS::ElasticLoadBalancingV2::Listener
Properties:
DefaultActions:
- Type: forward
TargetGroupArn: !Ref InternetNLBTargetToALB
LoadBalancerArn: !Ref InternetNLB
Port: 80
Protocol: TCP
InternetNLBTargetToALB:
DependsOn:
- InternalALBListener
Type: AWS::ElasticLoadBalancingV2::TargetGroup
Properties:
HealthCheckProtocol: HTTP # The supported value is 'HTTP' or 'HTTPS' if the target type is ALB
Port: 80
Protocol: TCP
Targets:
- Id: !Ref InternalALB
Port: 80
TargetType: alb
VpcId: !Ref VPC
Discussion