AWS中級 #6 ALB / NLB と ACM (HTTPS)
#5 Route 53 のドメインが指す場 — そこにはほぼ常に ロードバランサー があります。AWS のマネージドロードバランサーをまとめて ELB (Elastic Load Balancing) と呼び、その中に ALB / NLB / GWLB の 3 種類があります。
この記事では 3 つの LB の違い → ALB の Listener / Target Group / Health Check の流れ → ACM で証明書を取得して HTTPS を貼る場を 1 本の線で通していきます。
ロードバランサーが解く問題 #
EC2 1 台の後ろにドメインを直接刺すと次が崩れます。
| 問題 | LB が解く場 |
|---|---|
| EC2 が死ぬとサイトがダウン | Health check で死んだインスタンスを外し、生きているインスタンスへ |
| トラフィック増で 1 台では足りない | 複数インスタンスへ負荷分散 |
| AZ 障害で全面ダウン | Multi-AZ 分散 |
| HTTPS 証明書をインスタンスごとに管理 | LB で一度終端 (TLS termination) |
| カナリア / Blue-Green デプロイ | Listener Rule で比率分散 |
運用ではほぼ常に Internet → ALB / NLB → EC2 / ECS / Lambda パターン。
ALB / NLB / GWLB — 3 つの場の比較 #
| ALB (Application LB) | NLB (Network LB) | GWLB (Gateway LB) | |
|---|---|---|---|
| OSI レイヤー | L7 (HTTP / HTTPS) | L4 (TCP / UDP / TLS) | L3/L4 (IP) |
| ルーティング | path / host / header / メソッド | port のみ | パケットそのまま |
| スループット | 良 | 非常に高速 (数百万 RPS) | 適合場で高速 |
| WebSocket | ✅ | ✅ | - |
| HTTP/2 | ✅ | ✅ (TLS) | - |
| 固定 IP | ❌ (DNS) | ✅ (AZ ごとに EIP) | - |
| WAF 連動 | ✅ | ❌ | - |
| Cognito 認証 | ✅ | ❌ | - |
| Lambda target | ✅ | ❌ | - |
| 用途 | web / API | ゲーム / IoT / TCP / gRPC | セキュリティアプライアンス (Firewall) |
決定ガイド #
HTTP(S) ?
├── YES → ALB
│ └── 非常に高い RPS (数十万+) ? → ALB → 限界なら NLB
└── NO →
TCP/UDP ?
├── YES → NLB
└── 外部セキュリティアプライアンス通過 → GWLB99% の一般的な web 用途は ALB です。NLB はゲーム / IoT / 非常に高い処理量 / 固定 IP が必要な場合に使います。
ALB の形 #
Route 53
│
▼
┌────────┐
│ ALB │
│ │
└─┬──┬───┘
│ │
Listener (port 443)
│ │
▼ ▼
Listener Rules
(path / host)
│
├── /api/* ────▶ Target Group A (api EC2 群)
├── /admin/* ────▶ Target Group B (admin)
└── default / ────▶ Target Group C (web)
│
├── EC2 #1 (AZ a)
├── EC2 #2 (AZ b)
└── EC2 #3 (AZ a)中心となる 3 つの要素:
1) Listener — 受けるポート #
ALB がどのポートでトラフィックを受けるか。通常は 80 (HTTP)、443 (HTTPS)。
aws elbv2 create-load-balancer \
--name my-alb \
--subnets subnet-pubA subnet-pubB \
--security-groups sg-alb \
--scheme internet-facing \
--type application
aws elbv2 create-listener \
--load-balancer-arn <alb-arn> \
--protocol HTTPS \
--port 443 \
--certificates CertificateArn=<acm-arn> \
--default-actions Type=forward,TargetGroupArn=<tg-arn>2) Target Group — 送る先 #
Listener がトラフィックを送るインスタンス / IP / Lambda の集まり。ポートとプロトコルを持つグループ。
aws elbv2 create-target-group \
--name my-app-tg \
--protocol HTTP \
--port 8080 \
--vpc-id vpc-... \
--target-type instance \
--health-check-protocol HTTP \
--health-check-path /health \
--health-check-interval-seconds 30 \
--healthy-threshold-count 2 \
--unhealthy-threshold-count 3target-type の場:
| タイプ | 用途 |
|---|---|
instance | EC2 インスタンス ID。SG の場がなめらか |
ip | 任意 IP (VPC 内)。ECS / Fargate の自動登録 |
lambda | Lambda 関数。ALB → Lambda パターン |
3) Listener Rule — ルーティング規則 #
同じ Listener 内で path / host / header によって別の Target Group へ送る。
Priority Condition Action
10 host = api.example.com forward → tg-api
20 path = /admin/* forward → tg-admin
30 path = /static/* redirect → cloudfront.example.com
default * forward → tg-webルールは priority 順 (小さい方が先)。マッチしたら停止。
Listener Rule のアクション #
- forward — Target Group へ (重みで複数も)
- redirect — 別 URL へ (HTTP → HTTPS の永久リダイレクトの定石)
- fixed-response — 固定応答 (メンテナンスページ)
- authenticate-cognito / -oidc — ユーザー認証後に通過
Listener (port 80)
default action: redirect → HTTPS://#{host}#{path}#{query} (301)
Listener (port 443)
default action: forward → tg-webこれが運用の標準パターン。すべての 80 トラフィックを 443 に永久転送。
Health Check — 生きた場のみ #
Target Group の Health Check が 死んだインスタンスを自動で外し、復活したら戻します。
ALB ─ HTTP GET /health ──▶ EC2:8080
│
応答 200 ──▶ healthy (3 回連続)
応答 5xx ──▶ unhealthy (3 回連続) → ルーティングから除外よく使うオプション:
| オプション | 内容 |
|---|---|
HealthCheckPath | /health、/healthz のような軽い場 |
HealthCheckProtocol | HTTP / HTTPS |
HealthCheckIntervalSeconds | 30 (通常) |
HealthyThresholdCount | 2~3 回連続 200 → healthy |
UnhealthyThresholdCount | 2~3 回連続失敗 → unhealthy |
Matcher.HttpCode | 200 または 200-299 |
Health Check パスの設計 #
良い /health 応答:
@app.get("/health")
def health():
return {"status": "ok"}DB チェックまでする deep health は 別パス に:
@app.get("/health/deep")
def deep_health(db: Session = Depends(get_db)):
db.execute("SELECT 1")
return {"status": "ok", "db": "ok"}/health は常に軽く、/health/deep はモニタリング / デバッグの場で。ALB が deep health をポーリングすると DB に負荷がかかります。
Sticky Session — 同じ場へ #
特定ユーザーのリクエストを 常に同じインスタンスへ 送るオプション。
aws elbv2 modify-target-group-attributes \
--target-group-arn <tg-arn> \
--attributes \
Key=stickiness.enabled,Value=true \
Key=stickiness.type,Value=lb_cookie \
Key=stickiness.lb_cookie.duration_seconds,Value=86400用途:
- セッションをメモリに置く旧アプリ — ほぼ作るべきでないが移行のための一時用途
- WebSocket のような長寿命接続 — 自動 stickiness
運用では セッションを外部 (Redis / DB) に出して stateless が定石。Stickiness は最終手段。
NLB の場 #
ALB が解けない場合に NLB を使います。
NLB の強み #
- 固定 IP (AZ ごとに EIP) — ファイアウォールのホワイトリスト登録が必要な場合に最適
- 数百万 RPS 処理
- TLS termination も可能 (NLB が TLS を解いて平文で backend)
- PrivateLink の場 (サービスを別 VPC へ公開)
NLB の弱み #
- L4 のみ — path / host / header ルーティング不可
- WAF 連動が直接できない
- 単一 Listener が単一 Target Group
aws elbv2 create-load-balancer \
--name my-nlb --type network \
--subnets subnet-pubA subnet-pubB
aws elbv2 create-listener \
--load-balancer-arn <nlb-arn> \
--protocol TLS --port 443 \
--certificates CertificateArn=<acm-arn> \
--default-actions Type=forward,TargetGroupArn=<tg-arn>ACM — 証明書発行の場 #
ACM (AWS Certificate Manager) は AWS 内の ALB / NLB / CloudFront / API Gateway で使う 公開 SSL 証明書を無料 で発行 / 自動更新します。
証明書リクエスト #
aws acm request-certificate \
--domain-name example.com \
--subject-alternative-names "*.example.com" "api.example.com" \
--validation-method DNS \
--region ap-northeast-2検証方式:
- DNS 検証 (推奨) — Route 53 の CNAME で自動検証、自動更新
- Email 検証 (旧式) — admin@example.com 等にメール送信、毎年手動
ほぼ常に DNS 検証。Route 53 と一緒に使えばコンソールが「Create record in Route 53」ボタンで自動。
証明書の場 — リージョン一致ルール #
ACM 証明書はリージョン単位。ALB がソウルなら証明書もソウルで発行。ただし CloudFront は常に us-east-1 (#7)。
ALB (ソウル) → ACM 証明書 (ap-northeast-2)
NLB (東京) → ACM 証明書 (ap-northeast-1)
CloudFront → ACM 証明書 (us-east-1) ← 常に
API Gateway (REST) → ACM 証明書 (該当リージョン)
API Gateway (Edge) → ACM 証明書 (us-east-1)自動更新 #
ACM 証明書は 既定 13 か月有効、満了 60 日前から自動更新:
- DNS 検証で作った証明書: 完全自動
- Email 検証: 手動 (だから DNS 推奨)
自動更新が失敗する場合:
- DNS 検証 CNAME が消える → ドメイン解決失敗
- ALB が証明書を使用中だがドメインが別所に移った → 検証失敗
ACM コンソールで 満了通知 が自動、CloudWatch アラームも可能。
HTTPS を貼る一行手順 #
ドメインがあって ALB があると仮定。
1. ACM で証明書をリクエスト (DNS 検証)
2. Route 53 に検証 CNAME 追加 (コンソール 1 クリック)
3. 証明書 ISSUED を待つ (数分)
4. ALB Listener 443 に証明書 attach
5. Listener 80 → HTTPS リダイレクト
6. Route 53 のドメイン → ALB Aliasこの 6 ステップが運用の標準パターン。証明書を毎年更新する手間もなし。
Security Policy — TLS バージョン #
Listener の Security Policy が許可する TLS バージョン / 暗号セットを定義。
ELBSecurityPolicy-TLS13-1-2-2021-06 ← 推奨 (TLS 1.3、1.2)
ELBSecurityPolicy-TLS-1-2-2017-01 ← 互換性高い
ELBSecurityPolicy-FS-2018-06 ← Forward Secrecy 強制旧クライアント (TLS 1.0、1.1) を切りたいなら TLS13-1-2-2021-06。毎年新しいポリシーが出るので定期点検。
Connection Draining — 優雅な終了 #
インスタンスを 手動で外す、または ASG が縮小するとき 進行中のリクエストが切れないよう待機する場。
ALB ─ 新規リクエストは送らない ─▶ EC2 (deregistration_delay = 300s)
↑
進行中のリクエストは最後まで処理既定 300 秒。通常は 30~60 秒で十分。短すぎると進行中リクエスト切断、長すぎるとデプロイが遅い。
LB の SG と EC2 の SG #
#2 で見た SG パターン:
ALB SG (sg-alb)
Inbound: 443 ← 0.0.0.0/0
Outbound: all
EC2 SG (sg-app)
Inbound: 8080 ← sg-alb ← ALB SG そのもの
Outbound: allNLB は異なります — NLB 自身は SG を持たない (旧 NLB) または 1 つだけ (新オプション)。なので EC2 SG は NLB の IP ではなく クライアント IP をそのまま見ます。運用では NLB クライアント IP を絞るために NACL や VPC レベルの場を追加することも。
よくハマる罠 #
1) ACM 証明書が ISSUED にならない #
原因はほぼ 99%:
- 検証 CNAME が Route 53 に入っていない
- CNAME が誤った zone に入っている (
example.comではなくapi.example.comの zone) - TTL が長すぎて伝搬しない → 5 分ほど待つ
2) CloudFront 証明書をソウルで発行 #
CloudFront は us-east-1 のみ。コンソールで取得時、右上を N. Virginia に。
3) HTTP 80 Listener を作らず HTTPS のみ #
ユーザーが http://example.com で来ると timeout。80 Listener の redirect to HTTPS が標準。
4) Health check path が / #
/ が重い場 (DB 呼び出し等) なら ALB health check が DB を 30 秒ごとに爆撃。/health のような軽いパス を別途用意。
5) Target Group のポート vs Listener のポート #
ALB Listener は 443 だが Target Group の EC2 は 8080 ということがあります。両者は別物。Target Group のポートは EC2 が listen 中の場。
6) 502 Bad Gateway #
ALB → EC2 応答が崩れるとき。よくある原因:
- EC2 の keep-alive timeout < ALB idle timeout (60s 既定)
- EC2 が応答する前に切れる
- EC2 SG が ALB SG を inbound で受けていない
- EC2 が 8080 で listen していない
7) Sticky session で負荷偏り #
特定インスタンスにだけリクエストが溜まり、1 台だけ CPU 100% — Stickiness をオフして stateless に。
8) Cross-Zone オフ #
旧 ALB の cross-zone オプションがオフだと AZ 単位均等分配 — ある AZ のインスタンスは少ないのにトラフィックは同量 → 負荷偏り。Cross-zone load balancing を有効化 (ALB は既定オン、NLB は費用ゆえ既定オフ)。
9) Idle timeout の罠 #
ALB の idle timeout (既定 60s) がバックエンド / クライアントの keep-alive より短いと 502。通常はバックエンド keep-alive > ALB idle。
まとめ #
今回押さえたこと:
- ELB = ALB / NLB / GWLB。99% の一般的 web は ALB
- ALB: L7、path / host / header ルーティング、WAF 連動、Lambda target、Cognito 認証
- NLB: L4、固定 IP、数百万 RPS、PrivateLink
- ALB の場 = Listener (受けるポート) → Listener Rule (path/host) → Target Group (送る場) → Health Check
- Target Group の target-type = instance / ip / lambda
- Listener Rule の action = forward / redirect / fixed-response / authenticate
- HTTP → HTTPS redirect が運用標準 (80 Listener の default action)
- Health check は軽い
/health、deep は別途/health/deep - ACM = 無料 SSL 証明書 + 自動更新。DNS 検証 推奨
- リージョンマッピング — ALB は同リージョン、CloudFront は常に
us-east-1 - HTTPS を貼る 6 ステップ — 証明書リクエスト → CNAME 検証 → ISSUED → Listener attach → 80 redirect → Route 53 Alias
- Security Policy で許可 TLS バージョンを制限
- 罠 — 証明書検証失敗、CloudFront リージョン、80 抜け、health check 重い、ポート混乱、502、sticky 偏り、cross-zone、idle timeout
次回 — CloudFront #
ALB までの場は片付きました。最後に、ユーザーに近くキャッシュ を置く場 — CloudFront です。
#7 CloudFront で静的サイトを配信 では、Origin / Behavior / Cache Policy の流れ、S3 + CloudFront 静的ホスティングパターン、OAC で S3 を安全に隠す方法、そして無効化 (invalidation) まで整理します。