ALB / NLB와 ACM (HTTPS)
AWS의 매니지드 로드 밸런서 ALB / NLB / GWLB의 역할 차이, Listener / Target Group / Health Check의 흐름, 그리고 ACM으로 인증서를 발급받아 HTTPS를 한 번에 다는 운영 흐름까지 정리합니다.
12장 Route 53의 도메인이 가리키는 곳에는 거의 항상 로드 밸런서가 있습니다. AWS의 매니지드 로드 밸런서를 통틀어 **ELB (Elastic Load Balancing)**라고 부르고, 그 안에 ALB / NLB / GWLB 세 가지 종류가 있습니다.
본 챕터에서는 세 LB의 차이에서 시작해 ALB의 Listener / Target Group / Health Check 흐름, 그리고 ACM으로 인증서를 받아 HTTPS를 다는 과정까지 한 줄로 정리합니다. 여기서 다루는 SG 패턴은 9장 EC2 운영의 연장이고, ALB를 Origin으로 두는 패턴과 ACM의 리전 규칙은 14장 CloudFront로 이어지며, Target Group의 ip 타입은 15장 ECS와 Fargate에서 자동 등록으로 다시 나타납니다.
로드 밸런서가 푸는 문제 #
EC2 한 대 뒤에 도메인을 직접 꽂으면 다음이 깨집니다.
| 문제 | LB가 푸는 기능 |
|---|---|
| EC2가 죽으면 사이트가 다운 | Health check로 죽은 인스턴스를 빼고 살아 있는 쪽으로 |
| 트래픽 많아져 한 대로 부족 | 여러 인스턴스에 부하 분산 |
| AZ 장애 시 전면 다운 | Multi-AZ 분산 |
| HTTPS 인증서를 인스턴스마다 관리 | LB에서 한 번 끊어 줌 (TLS termination) |
| 카나리 / Blue-Green 배포 | Listener Rule로 비율 분산 |
운영에서는 거의 항상 Internet → ALB / NLB → EC2 / ECS / Lambda 패턴입니다.
ALB / NLB / GWLB — 세 가지 비교 #
| 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 | 지원 | 안 됨 | - |
| 용도 | 웹 / API | 게임 / IoT / TCP / gRPC | 보안 어플라이언스 (Firewall) |
결정 가이드 #
HTTP(S) ?
├── YES → ALB
│ └── 매우 높은 RPS (수십만+)? → ALB → 한계 시 NLB
└── NO →
TCP/UDP ?
├── YES → NLB
└── 외부 보안 어플라이언스 통과 → GWLB일반 웹 워크로드는 거의 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)
└── 기본 / ────▶ Target Group C (web)
│
├── EC2 #1 (AZ a)
├── EC2 #2 (AZ b)
└── EC2 #3 (AZ a)핵심 구성 요소는 다음과 같습니다.
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>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 패턴 |
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 같은 장수명 연결입니다.
운영에서는 세션을 외부(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 입니다(14장).
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 추가 (콘솔 한 번 클릭)
3. 인증서 ISSUED 대기 (수 분)
4. ALB Listener 443 에 인증서 attach
5. Listener 80 → HTTPS redirect
6. Route 53 의 도메인 → ALB Alias이 여섯 단계가 운영의 표준 패턴입니다. 인증서를 매년 갱신할 일도 없습니다.
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 #
9장 EC2 운영에서 본 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) 한 SG만 가집니다(새 옵션). 그래서 EC2 SG가 NLB의 IP가 아닌 클라이언트 IP를 그대로 보게 됩니다. 운영에서는 NLB 클라이언트 IP를 좁히기 위해 NACL이나 VPC 단 제어를 추가하기도 합니다.
자주 만나는 함정 #
- ACM 인증서가 ISSUED 안 됨 — 거의 99%가 검증 CNAME이 Route 53에 안 들어갔거나, 잘못된 zone에 들어갔거나(
example.com이 아니라api.example.com의 zone), TTL이 너무 길어 전파가 안 된 경우입니다. 5분 정도 기다려 봅니다. - CloudFront 인증서를 서울에서 발급 — CloudFront는
us-east-1만 씁니다. 콘솔에서 받을 때 우측 상단을 N. Virginia로 바꿉니다. - HTTP 80 Listener 안 만들고 HTTPS 만 — 사용자가
http://example.com으로 들어오면 timeout이 납니다. 80 Listener의 redirect to HTTPS가 표준입니다. - Health check path가
/—/가 무거운 작업(DB 호출 등)이면 ALB health check가 DB를 30초마다 폭격합니다./health같은 가벼운 경로를 별도로 둡니다. - Target Group의 포트 vs Listener 포트 혼동 — ALB Listener는 443 인데 Target Group의 EC2는 8080일 수 있습니다. 두 포트는 별개입니다. Target Group 포트가 EC2가 listen 중인 포트입니다.
- 502 Bad Gateway — ALB → EC2 응답이 깨질 때입니다. 흔한 원인은 EC2의 keep-alive timeout이 ALB idle timeout(60s 기본)보다 짧거나, EC2가 응답하기 전에 끊기거나, EC2 SG가 ALB SG를 inbound에 안 받거나, EC2가 8080에서 listen 하지 않는 것입니다.
- Sticky session으로 부하 쏠림 — 특정 인스턴스에만 요청이 쌓여 한 대만 CPU 100%가 됩니다. Stickiness를 끄고 stateless로 둡니다.
- Cross-Zone 끔 — 옛 ALB의 cross-zone 옵션이 꺼져 있으면 AZ 단위 균등 분배가 되어, 한 AZ의 인스턴스가 적은데 트래픽은 같은 양이라 부하가 쏠립니다. Cross-zone load balancing을 켭니다(ALB는 기본 켜짐, NLB는 비용 때문에 기본 꺼짐).
연습문제 #
- §“HTTPS 다는 한 줄 절차"의 여섯 단계를 보지 않고 적어 보세요. 그중 12장 Route 53의 작업(검증 CNAME 추가, 도메인 Alias)은 어느 단계인지 표시하고, ACM 작업과 ALB 작업을 구분해 보세요.
- ALB와 NLB의 비교표를 보고, 다음 세 워크로드에 각각 무엇을 골라야 하는지 §“결정 가이드"를 근거로 답하세요. (a) 일반 REST API, (b) 방화벽 화이트리스트를 위해 고정 IP가 필요한 TCP 게임 서버, (c) WAF를 붙여야 하는 웹 사이트.
- CloudFront 용 인증서를 서울에서 발급해 ISSUED가 안 되는 상황을 가정하고, §“인증서의 리전 일치 규칙"을 근거로 원인과 해결을 적어 보세요. 이 규칙은 14장 CloudFront에서 다시 확인하게 됩니다.
한 줄 요약: ELB는 ALB / NLB / GWLB로 나뉘고 일반 웹은 거의 ALB 다. ALB 흐름은 Listener(받는 포트) → Listener Rule(path/host) → Target Group(보낼 대상) → Health Check이며, HTTP 80의 default action을 HTTPS redirect로 두는 것이 표준이다. ACM은 무료 SSL 인증서를 DNS 검증으로 자동 갱신하며, ALB는 같은 리전이지만 CloudFront는 항상 us-east-1이다.
다음 챕터 #
ALB 까지의 역할은 잡았습니다. 다음 14장 CloudFront에서는 마지막으로 사용자에 가까이 캐시를 두는 CloudFront로 이어집니다. Origin / Behavior / Cache Policy의 흐름, S3 + CloudFront 정적 호스팅 패턴, OAC로 S3를 안전하게 가리는 방법, 그리고 무효화(invalidation)까지 정리합니다.