LB@AWSリソース¶
はじめに¶
本サイトにつきまして、以下をご認識のほど宜しくお願いいたします。
01. LB¶
ロードバランシングしたいプロトコルに合わせて、使用するロードバランサーを選択する。
| LB名 | OSI階層モデルのレイヤー | リスナーが処理できるプロトコル | ターゲット | リクエストヘッダー (L7) |
パケットヘッダーのフィールド (L4) |
セキュリティグループ |
|---|---|---|---|---|---|---|
| ALB:Application Load Balancer | L7 (アプリケーション層) |
HTTP、HTTPS、gRPC | IPアドレス、AWS EC2インスタンス、Lambda | URL、HTTPヘッダー | ポート番号フィールド | 可 |
| NLB:Network Load Balancer | L4 (トランスポート層) |
TCP、UDP、TLS | IPアドレス、AWS EC2インスタンス、ALB | 不可 | IPアドレスフィールド、ポート番号フィールド | 不可 |
| GLB:Gateway Load Balancer | L3 (ネットワーク層) 、L4 |
IP | IPアドレス、AWS EC2インスタンス | 不可 | IPアドレスフィールド、ポート番号フィールド | 不可 |
| CLB:Classic Load Balancer | L4、L7 |
HTTP、HTTPS、TCP、SSL/TLS | なし | URL、HTTPヘッダー | IPアドレスフィールド、ポート番号フィールド | 可 |
02. ALB:Application Load Balancing¶
ALBとは¶
クラウドリバースプロキシサーバー、かつクラウドL7ロードバランサーとして働く。
AWS EC2へのリクエストをバランスよく分配することによって、サーバーへの負荷を緩和する。

02-02. セットアップ¶
コンソール画面の場合¶
▼ 設定項目と説明¶
| 設定項目 | 説明 | 補足 |
|---|---|---|
| リスナー | ALBに割り振るポート番号と受信するプロトコルを設定する。リバースプロキシサーバーかつロードバランサ-として、これらの通信をターゲットグループにルーティングする。 | |
| スキーム | パブリックネットワークからのリクエストを待ち受けるか、あるいはプライベートネットワークからのリクエストを待ち受けるかを設定する。 | |
| セキュリティポリシー | リクエストの送信者が使用するSSL/TLSプロトコルや暗号化方式のバージョンに合わせて、ALBが受信できるこれらのバージョンを設定する。 | ・リクエストの送信者には、ブラウザ、APIにリクエストを送信する外部サービス、フォワーディング元のAWSリソース (例:CloudFrontなど) などを含む。 ・- https://docs.aws.amazon.com/elasticloadbalancing/latest/application/create-https-listener.html#describe-ssl-policies |
| ルール | リクエストのルーティングのロジックを設定する。 | |
| ターゲットグループ | ルーティング時に使用するプロトコルと、宛先とするポート番号を設定する。 | ターゲットグループ内のターゲットのうち、トラフィックはヘルスチェックがOKになっているターゲットにルーティングされる。 |
| ヘルスチェック | ターゲットグループに所属するプロトコルとアプリケーションのポート番号を指定して、定期的にリクエストを送信する。 |
▼ ターゲットグループ¶
| ターゲットの指定方法 | 補足 |
|---|---|
| AWS EC2インスタンス | ターゲットはAWS EC2である必要がある。 |
| IPアドレス | ターゲットのパブリックIPアドレスは静的である必要がある。 |
| Lambda | ターゲットはLambdaである必要がある。 |
ルールの設定例¶
| ユースケース | ポート | IF | THEN |
|---|---|---|---|
リクエストが80番ポートを指定した時に、443番ポートにリダイレクトしたい。 |
80 |
それ以外の場合はルーティングされないリクエスト | ルーティング先:https://#{host}:443/#{path}?#{query}ステータスコード: HTTP_301 |
リクエストが443番ポートを指定した時に、ターゲットグループにフォワーディングしたい。 |
443 |
それ以外の場合はルーティングされないリクエスト | 特定のターゲットグループ |
Terraformの場合¶
▼ EKSに紐づけるALB¶
module "alb_eks" {
source = "terraform-aws-modules/alb/aws"
version = "= 9.13.0"
name = "foo-alb-eks"
enable_cross_zone_load_balancing = true
vpc_id = "*****"
subnets = ["*****", "*****"]
associate_web_acl = true
web_acl_arn = "*****"
access_logs = {
bucket = "*****"
prefix = "foo-alb-eks"
}
security_group_egress_rules = {
all = {
from_port = 0
to_port = 65535
protocol = "-1"
cidr_ipv4 = "0.0.0.0/0"
}
}
security_group_ingress_rules = {
https = {
from_port = 443
to_port = 443
protocol = "-1"
cidr_ipv4 = "0.0.0.0/0"
}
}
listeners = {
https = {
port = 443
protocol = "HTTPS"
certificate_arn = "*****"
forward = {
# ターゲットグループのキー名を指定する
target_group_key = "eks"
}
}
http = {
port = 80
protocol = "HTTP"
action_type = "redirect"
redirect = {
port = 443
protocol = "HTTPS"
status_code = "HTTP_301"
}
}
}
# ターゲットグループを定義
# aws_lb_target_groupを使用しても良い
target_groups = {
# 自由にキー名を設定する
eks = {
port = 30180
protocol = "HTTP"
# Nodeにルーティングするためにinstanceとする
target_type = "instance"
# ターゲットグループへのEC2の登録はEKSマネージドNodeグループに委譲する
create_attachment = false
health_check = {
enabled = true
path = "/healthz/ready"
port = 30000
protocol = "HTTP"
matcher = "200"
}
}
}
}
# ターゲットグループとマネージドNodeグループを紐づける
resource "aws_autoscaling_attachment" "alb_eks" {
autoscaling_group_name = aws_eks_node_group.foo.resources[0].autoscaling_groups[0].name
lb_target_group_arn = module.alb_eks.target_group_arns["eks"]
}
▼ メンテナンス用ALB¶
module "alb_eks_maintenance" {
source = "terraform-aws-modules/alb/aws"
version = "= 9.13.0"
name = "foo-alb-maintenance"
enable_cross_zone_load_balancing = true
vpc_id = "*****"
subnets = ["*****", "*****"]
associate_web_acl = true
web_acl_arn = "*****"
access_logs = {
bucket = "*****"
prefix = "foo-alb-maintenance"
}
security_group_egress_rules = {
all = {
from_port = 0
to_port = 65535
protocol = "-1"
cidr_ipv4 = "0.0.0.0/0"
}
}
security_group_ingress_rules = {
https = {
from_port = 443
to_port = 443
protocol = "-1"
cidr_ipv4 = "0.0.0.0/0"
}
}
listeners = {
https = {
port = 443
protocol = "HTTPS"
certificate_arn = "*****"
# JSONデータを含む固定レスポンス
action_type = "fixed-response"
fixed_response = {
content_type = "application/json"
message_body = jsonencode({
code = "9999"
# メンテナンスモード時の業務コード
reason = "MAINTENANCE"
})
status_code = "503"
}
# XMLデータを含む固定レスポンスの場合
# fixed_response = {
# content_type = "text/xml;charset=UTF-8"
# message_body = <<-XML
# <?xml version="1.0" encoding="UTF-8"?>
# <error>
# <code>9999</status>
# <reason>MAINTENANCE</statusReason>
# </error>
# XML
# status_code = "503"
# }
}
http = {
port = 80
protocol = "HTTP"
action_type = "redirect"
redirect = {
port = 443
protocol = "HTTPS"
status_code = "HTTP_301"
}
}
}
}
AWS Load Balancer Controllerの場合¶
設計パターン¶
▼ 同じドメインを設け、パスで複数のBFFに振り分ける場合¶
flowchart LR
user[クライアント]
r53[Route53<br/>example.com]
alb[ALB<br/>HTTPS :443]
subgraph EKS[EKS Cluster]
svcA[Service A<br/>Port 3000]
svcB[Service B<br/>Port 4000]
end
user --> r53
r53 --> alb
alb -- "/app1/*" --> svcA
alb -- "/app2/*" --> svcB
▼ 異なるドメインを設け、通信経路を分ける場合¶
flowchart LR
user[クライアント]
r53A[Route53<br/>app1.example.com]
r53B[Route53<br/>app2.example.com]
albA[app1 ALB<br/>HTTPS :443]
albB[app2 ALB<br/>HTTPS :443]
subgraph EKS[EKS Cluster]
svcA[Service A<br/>Port 3000]
svcB[Service B<br/>Port 4000]
end
user --> r53A
user --> r53B
r53A --> albA
r53B --> albB
albA -- "Host: app1.example.com" --> svcA
albB -- "Host: app2.example.com" --> svcB
ALBインスタンス¶
▼ ALBインスタンスとは¶
ALBの実体で、各ALBインスタンスが異なるグローバルIPアドレスを持つ。
複数のAZにルーティングするようにALBを設定した場合、各AZにALBインスタンスが1つずつ配置される。

▼ 割り当てられるIPアドレス¶
ALBに割り当てられるIPアドレスには、AWS VPCのものが適用される。
そのため、AWS EC2のセキュリティグループでは、AWS VPCのCIDRブロックを許可するように設定する必要がある。
▼ オートスケーリング¶
単一障害点にならないように、負荷が高まるとALBインスタンスが増えるように自動スケールアウトする仕組みを持つ。
▼ 500系ステータスの原因¶
▼ ALBのセキュリティグループ¶
AWS Route53からルーティングされるパブリックIPアドレスを受信できるようにしておく必要がある。
パブリックネットワークに公開するサイトであれば、IPアドレスは全ての範囲 (0.0.0.0/0と::/0) にする。
社内向けのサイトであれば、社内のプライベートIPアドレスのみ (*.*.*.*/32) を許可する。
常時SSLのアプリケーションへのルーティング¶
▼ 問題¶
アプリケーションが常時SSLになっているアプリケーション (例:WordPress) の場合、ALBからアプリケーションにHTTPプロトコルでルーティングすると、HTTPSプロトコルへのリダイレクトループが発生してしまう。
常時SSLがデフォルトになっていないアプリケーションであれば、これは起こらない。
▼ Webサーバーにおける対処方法¶
ALBを経由したリクエストには、リクエストヘッダーにX-Forwarded-Protoヘッダーが付与される。
これには、ALBに対するリクエストのプロトコルの種類が文字列で代入されている。
これが『HTTPS』だった場合、Webサーバーに対するリクエストをHTTPSプロトコルであるとみなすように対処する。
これにより、アプリケーションに対するリクエストのプロトコルがHTTPSプロトコルとなる (こちらを行った場合は、アプリケーション側の対応不要) 。
*実装例*
SetEnvIf X-Forwarded-Proto https HTTPS=on
▼ アプリケーションにおける対処方法¶

ALBを経由したリクエストには、リクエストヘッダーにHTTP_X_FORWARDED_PROTOヘッダーが付与される。
これには、ALBに対するリクエストのプロトコルの種類が文字列で代入されている。
そのため、もしALBに対するリクエストがHTTPSプロトコルだった場合は、ALBからアプリケーションに対するリクエストもHTTPSプロトコルであるとみなすように、index.phpに追加実装を実行する (こちらを行った場合は、Webサーバー側の対応不要) 。
*実装例*
<?php
// index.php
if (isset($_SERVER["HTTP_X_FORWARDED_PROTO"])
&& $_SERVER["HTTP_X_FORWARDED_PROTO"] == "https") {
$_SERVER["HTTPS"] = "on";
}
負荷分散方式¶
▼ 負荷分散方式とは¶
ターゲットに対するリクエストフォワーディング時の負荷分散方式を設定する。
▼ ラウンドロビン方式¶
受信したリクエストを、ターゲットに均等にルーティングする。
▼ 最小未処理リクエスト方式 (ファステスト)¶
受信したリクエストを、未処理のリクエスト数が最も少ないターゲットにルーティングする。
▼ スロースタート方式¶
受信したリクエストをルーティングする時に、スロースタート方式 (通過させるリクエストの数を少しずつ増加させる) で負荷分散を実施する。
リクエスト数の非常に多い高トラフィックなシステムで、起動直後のパフォーマンスが悪いアプリケーション (例:キャッシュに依存、接続プールの作成が必要、ウォームアップが必要なJVM言語製アプリケーション) にいきなり高負荷をかけないようにできる。
アクセスログ¶
▼ HTTPSリクエストの場合¶
HTTPSリクエストのアクセスログのフォーマットは以下の通りである。
https 2018-07-02T22:23:00.186641Z app/my-loadbalancer/50dc6c495c0c9188 192.168.131.39:2817 10.0.0.1:80 0.086 0.048 0.037 200 200 0 57 "GET https://www.example.com:443/ HTTP/1.1" "curl/7.46.0" ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2 arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067 "Root=1-58337281-1d84f3d73c47ec4e58577259" "www.example.com" "arn:aws:acm:us-east-2:123456789012:certificate/12345678-1234-1234-1234-123456789012" 1 2018-07-02T22:22:48.364000Z "authenticate,forward" "-" "-" "10.0.0.1:80" "200" "-" "-" TID_123456
https # リクエストタイプ
2018-07-02T22:23:00.186641Z
app/my-loadbalancer/50dc6c495c0c9188 # ロードバランサー名
192.168.131.39:2817 # クライアント側の情報
10.0.0.1:80 # ターゲット側の情報 (AWS EC2、AWS ECS、AWS EC2 NodeのIPアドレスとポート番号)
0.086
0.048
0.037
200 # ロードバランサーのレスポンスのステータスコード
200
0
57
"GET https://www.example.com:443/ HTTP/1.1"
"curl/7.46.0" # ユーザーエージェント
ECDHE-RSA-AES128-GCM-SHA256 TLSv1.2
arn:aws:elasticloadbalancing:us-east-2:123456789012:targetgroup/my-targets/73e2d6bc24d8a067
"Root=1-58337281-1d84f3d73c47ec4e58577259"
"www.example.com"
"arn:aws:acm:us-east-2:123456789012:certificate/12345678-1234-1234-1234-123456789012"
1
2018-07-02T22:22:48.364000Z
"waf,authenticate,forward" # AWS WAFを通過している場合はここに記録される
"-"
"-"
"10.0.0.1:80"
"200" # サーバー側のレスポンスのステータスコード
"-"
"-"
TID_123456
03. CLB: Classic Load Balancer¶
キューを持ち、クラウドL4/L7ロードバランサーとして働く。
ALB、NLB、では元々実装されていたキューを廃止した経緯がある。
04. NLB:Network Load Balancer¶
クラウドL4ロードバランサーとして働く。
固定IPアドレスを設定できる。
そのため、ドメインを指定できず、IPアドレスを指定しないといけないHTTPリクエストを送信できないような通信元にも対応している。
この場合、NLBで受信したHTTPリクエストをALB(internalタイプ)に送信するようにするとよい。
flowchart LR
Route53
NLB
ALB[internal ALB]
EKS
Route53 --> NLB --> ALB --> EKS