HA構成プロキシ環境を NLBを使って構築してみる
前回のブログ では プロキシサーバー シングル構成の検証環境を構築しました。
今回は 高可用性(HA)を目的としたプロキシサーバー冗長化 を検証してみます。 想定する本番環境は下記の通り。
※ そもそもプロキシサーバーを使用している理由
などは前回のブログを参照ください
目次
環境構築
検証環境は以下のとおりです。
- 2つの Availability Zone(AZ) にそれぞれサブネットを作成
- プロキシサーバーを 2サブネットに配置する Auto Scaling Group を作成
- Network Load Balancer (NLB) を使って ターゲットを分散
APPサーバーから NLB → Proxyサーバー経由で Serviceを利用できるか確かめてみます。 構築は勉強も兼ねて CloudFormation(CFn)で行います。
github に今回作成した CFnテンプレートを上げています。
- 00-network.yaml: ネットワークリソース作成用
- 01-sg.yaml: セキュリティグループ作成用
- 02-nlb.yaml: NLB 作成用
- 03-as.yaml: Auto Scaling Group 作成用
- 04-ec2-service.yaml: サービスサーバー (Linux) 作成用
- 05-ec2-app.yaml: アプリサーバー (Windows) 作成用
以降、Proxy-VPC内の システム周りを中心に説明します。
NLB
下記 3リソースを作成します。
- LoadBalancer (AWS CloudFormation ドキュメント)
- TargetGroup (AWS CloudFormation ドキュメント)
- Listener (AWS CloudFormation ドキュメント)
▼— LoadBalancer ---
Type: AWS::ElasticLoadBalancingV2::LoadBalancer Properties: Name: !Sub ${Prefix}-nlb Type: network Scheme: internal IpAddressType: ipv4 Subnets: - Fn::ImportValue: !Sub ${Prefix}-subnet2-a - Fn::ImportValue: !Sub ${Prefix}-subnet2-c
- NLBを作成するので
Type: network
とします - 内部向けを想定しているので
Scheme: internal
とします - NLBを 2サブネットに設置するための設定を
Subnets:
に記載します
▼— TargetGroup ---
Type: AWS::ElasticLoadBalancingV2::TargetGroup Properties: Name: !Sub ${Prefix}-nlb-tg TargetType: instance Protocol: TCP Port: 3128 # squid VpcId: Fn::ImportValue: !Sub ${Prefix}-vpc2
後ほどこのターゲットグループが Auto Scaling Group と関連付けられます。
NLBは ターゲットグループに対して Protocol: TCP
、 Port: 3128
(squidで使うポート番号) のリクエストを送信します。
TargetType:
は instance
もしくは ip
が選択できます。今回は instance
を選択しますが、
留意点は TargetType:
によって NLBから送られる パケットの送信元IPアドレス が変わる ことです。
インスタンス ID を使用してターゲットを指定すると、 クライアントの送信元 IP アドレス が保持 され、アプリケーションに提供されます。
ターゲットを IP アドレスで指定する場合、送信元 IP アドレスは ロードーバランサノードのプライベート IP アドレス となります。
▼— Listener ---
Type: AWS::ElasticLoadBalancingV2::Listener Properties: Port: 3128 Protocol: TCP DefaultActions: - Type: forward TargetGroupArn: !Ref NLBTargetGroup LoadBalancerArn: !Ref NLB
- クライアントからのリクエストを
Port: 3128
、Protocol: TCP
で受け付けます DefaultActions:
でアクションを設定します。 リクエストを指定したTargetGroup
へルーティング (forward
) します。
セキュリティグループ
NLB構成としたことでプロキシサーバーに設定するセキュリティグループの設定内容が少々変わってきます。
Type: AWS::EC2::SecurityGroup Properties: GroupDescription: SG for Proxy Server GroupName: !Sub ${Prefix}-proxy-sg VpcId: Fn::ImportValue: !Sub ${Prefix}-vpc2 SecurityGroupIngress: - IpProtocol: tcp FromPort: 3128 ToPort: 3128 CidrIp: 10.0.0.0/24 # from Proxy-VPC (for healthcheck) - IpProtocol: tcp FromPort: 3128 ToPort: 3128 CidrIp: 192.168.0.0/24 # from APP-VPC # - IpProtocol: tcp # FromPort: 3128 # ToPort: 3128 # SourceSecurityGroupId: !Ref AppSG
コメントアウトしている部分が前回の シングル構成時のルール です (クライアントSGからの ポート3128を許可)。
今回は NLB経由の接続ですが、 NLBは セキュリティグループを持ちません 。
また、 TargetType: instance
としているため、 NLBで送信元IPをクライアントのIPに置き換えています 。
そのため、 CIDR形式で 以下の通信を許可する必要があります。
- NLBを配置しているネットワークCIDR からの通信 (ヘルスチェックのため)
- クライアントを配置しているネットワークCIDR からの通信 (メインの通信のため)
プロキシサーバーのAMI
Auto Scaling で使用する AMIを事前に作成します。
Amazon Linux2 EC2インスタンスを起動して squid のインストール・自動起動の設定をします。
設定ファイル /etc/squid/squid.conf
の修正内容としては大きく 2つ。
acl localnet src 192.168.0.0/24 # VPC Network (Application side) acl localnet src 10.0.0.0/24 # VPC Network (Proxy side: for NLB health check) ... # disable cache acl NOCACHE src all cache deny NOCACHE
前 2行で アクセス制御の設定、後ろ2行でキャッシュの無効化を行っています ( 参考: Qiita: Squidのキャッシュ機能を無効化する )。
設定後、AMIを作成します。
Auto Scaling Group
下記 2リソースを作成します。
- Launch Configuration (AWS CloudFormation ドキュメント)
- Auto Scaling Group (AWS CloudFormation ドキュメント)
▼— Launch Configuration ---
Type: AWS::AutoScaling::LaunchConfiguration Properties: LaunchConfigurationName: !Sub ${Prefix}-launch-configuration ImageId: !Ref ProxyServerImageId InstanceType: t3.micro SecurityGroups: - Fn::ImportValue: !Sub ${Prefix}-proxy-sg BlockDeviceMappings: - DeviceName: /dev/xvda Ebs: DeleteOnTermination: True VolumeType: gp2 VolumeSize: 8 KeyName: !Ref Ec2KeyName # ... 略
ImageId:
に事前に作成したAMIの IDを入れます。
他は EC2インスタンスを作成するときと同じように設定していきます。
▼— Auto Scaling Group ---
Type: AWS::AutoScaling::AutoScalingGroup Properties: AutoScalingGroupName: !Sub ${Prefix}-as-group LaunchConfigurationName: !Ref LaunchConfiguration DesiredCapacity: 2 MaxSize: 2 MinSize: 2 VPCZoneIdentifier: - Fn::ImportValue: !Sub ${Prefix}-subnet2-a - Fn::ImportValue: !Sub ${Prefix}-subnet2-c TargetGroupARNs: - Fn::ImportValue: !Sub ${Prefix}-nlb-tg HealthCheckType: ELB # ... 略
LaunchConfigurationName:
に前述の LaunchConfigurationを指定します。- 常に 2台を維持する設定とするため、
DesiredCapacity:
、MaxSize:
、MinSize:
を2
とします。 TargetGroupARNs:
に NLBの TargetGroup を指定します
検証
接続・ステータス確認
APPサーバーにログインして、Service-VPCにある サービスを利用できるか検証します。 (Serviceの EC2インスタンスには httpd を入れておきます)
※APPサーバーのプロキシ設定は以下の通り。
APPサーバーにログインして、ServiceのローカルIPにアクセスしてみます。
Serviceの httpd ログを見てみます。APPサーバーを 2台立てて交互にアクセスしてみました。 2台のプロキシサーバーからアクセスされていることが確認できます。
ターゲットグループを見てみます。 2台ともヘルスチェックに合格しています。
Auto Scaling Group のステータスは以下の通り。
インスタンスを止めてみる
1つの プロキシサーバーを止めてみます。
止めたインスタンスが Unhealthy
となりました。
ライフサイクルが 終了中
に変わります。
新しい命が作られそうです。
無事に入れ替わりました。
Service のログにも新しくできたプロキシサーバーからのアクセスが確認できます。
(参考) 一連のアクティビティ履歴は以下の通り。
おわりに
HA構成プロキシ環境を NLBを使って構築してみました。 NLB, Auto Scaling 周りの 動作は勉強はしていたものの実際に見てはいなかったので、 確認できてよかったです。 CFnテンプレートを書く筋肉も付いてきた気がします。
今後は下記 2点あたりを考えて、まとめていけたらなと思っています。
- NLB, Auto Scaling のパラメータチューニング (今回はほとんどデフォルト)
- 運用・ログ監視周り
(追記) 通信要件によっては、そもそも ALB(IPターゲット) をリバースプロキシとして使えば実装できるみたいです。そちらの検証を今後行ってみます。