DNS basics
분류: Layer 2 - 인프라 기초 | 작성일: 2026-04-01
1. 한 줄 정의
섹션 제목: “1. 한 줄 정의”DNS(Domain Name System)는 사람이 읽을 수 있는 도메인 이름(api.example.com)을 컴퓨터가 이해하는 IP 주소(52.94.1.2)로 변환하는 인터넷의 전화번호부다.
2. 왜 중요한가
섹션 제목: “2. 왜 중요한가”- 서버 IP가 바뀌어도 도메인은 고정: AWS EC2를 재배포하거나 ALB를 교체하면 IP가 달라진다. DNS가 없다면 클라이언트 코드를 전부 수정해야 한다.
- 트래픽 제어의 시작점: 로드 밸런싱, 장애 조치(Failover), A/B 테스트 모두 DNS 레이어에서 시작된다.
- 배포 없이 라우팅 변경: DNS TTL 조정만으로 트래픽을 새 서버로 전환할 수 있다.
- BackOps 관점: Nest.js API 서버를 ALB 뒤에 두거나 CloudFront로 캐싱할 때, Route 53 설정이 잘못되면 서비스 자체가 불통이 된다.
3. 핵심 개념
섹션 제목: “3. 핵심 개념”3-1. DNS 계층 구조 — 비유로 이해하기
섹션 제목: “3-1. DNS 계층 구조 — 비유로 이해하기”비유: 도서관 사서 시스템
- 당신(클라이언트): “api.example.com의 주소를 알고 싶어요”
- 안내 데스크(Recursive Resolver): “제가 대신 알아봐 드릴게요”
- 관장실(Root Nameserver): “.com 담당은 저쪽 서가입니다”
- .com 서가(TLD Nameserver): “example.com 담당은 4층입니다”
- 4층 담당자(Authoritative Nameserver): “api.example.com → 52.94.1.2 입니다”
클라이언트 │ ▼Recursive Resolver (ISP 또는 8.8.8.8) │ ├──▶ Root Nameserver (.) │ └── ".com? TLD 서버는 192.5.6.30이야" │ ├──▶ TLD Nameserver (.com) │ └── "example.com? Authoritative는 205.251.196.1이야" │ └──▶ Authoritative Nameserver (example.com) └── "api.example.com → 52.94.1.2"```text
**Root Nameserver**: 전 세계에 13개 클러스터(a.root-servers.net ~ m.root-servers.net)가 있으며, Anycast로 수백 개의 물리 서버가 운영됨.
**TLD Nameserver**: `.com`, `.net`, `.io`, `.kr` 등 최상위 도메인별로 존재. Verisign이 `.com`을 운영.
**Authoritative Nameserver**: 실제 도메인의 DNS 레코드를 보유. AWS Route 53이 여기에 해당.
**왜 계층 구조인가 — 설계 원리 심화**
DNS가 단일 서버가 아닌 계층 구조인 이유는 **확장성(Scalability)** 과 **장애 격리(Fault Isolation)** 때문이다.
- **단일 서버였다면**: 인터넷에 존재하는 수억 개의 도메인을 한 서버가 관리해야 하고, 그 서버 장애 시 전 세계 인터넷이 불통된다.- **계층 구조이므로**: Root는 TLD만, TLD는 Second-Level 도메인만 알면 된다. Route 53(Authoritative)이 다운되어도 전 세계 다른 도메인에는 영향 없다. 각 계층이 독립적으로 장애를 격리한다.
**캐싱이 성능을 보장하는 원리**
계층 구조의 또 다른 핵심은 각 단계 응답을 TTL 동안 캐시한다는 점이다. Root Nameserver와 TLD Nameserver는 거의 변하지 않으므로 TTL이 하루~이틀이다. 실제로 브라우저에서 두 번째로 `api.example.com`에 접속할 때는 OS 캐시에서 즉시 IP를 찾아서 DNS 질의 전체 과정이 생략된다.
```bash# 실제 DNS 질의 시간 측정 (캐시 여부 확인)time dig api.example.com
# 첫 번째 요청 (캐시 없음) 예상 출력:# ;; Query time: 52 msec# ;; SERVER: 10.0.0.2#53
# 같은 명령 즉시 재실행 (캐시 있음) 예상 출력:# ;; Query time: 1 msec ← 캐시 히트! Root→TLD→Auth 과정 건너뜀```
> 📖 더 보기: [What is recursive DNS? — Cloudflare](https://www.cloudflare.com/learning/dns/what-is-recursive-dns/) — Recursive Resolver의 캐싱 동작과 성능 향상 원리를 시각적으로 설명 (입문)
**프론트엔드 → 플랫폼 브릿지: Next.js API Route vs CDN DNS 라우팅**
프론트엔드에서 Next.js API Route(`/api/products`)를 호출할 때와 CDN 경유 API(`api.example.com/products`)를 호출할 때 DNS 동작이 어떻게 다른지 이해하는 것이 플랫폼 엔지니어의 핵심 역량이다.
```[Next.js API Route — 동일 도메인 내부 요청]브라우저 → fetch('/api/products') → 현재 페이지 도메인과 동일 (www.example.com) → DNS 조회 불필요 (이미 IP 알고 있음) → 기존 TCP 연결 재사용 → Vercel/EC2 서버의 Next.js가 직접 처리
[CDN + DNS 라우팅 — 별도 도메인 API]브라우저 → fetch('https://api.example.com/products') → 새로운 도메인 → DNS 조회 필요 → Route 53: Latency 라우팅 → 가장 가까운 리전 ALB IP 반환 → CloudFront: 엣지 캐시 확인 → 히트 시 Origin(NestJS) 요청 안 함 → 새 TCP + TLS 연결 수립 (or HTTP Keep-Alive로 재사용)```
**실무 판단 포인트**: API를 동일 도메인 서브패스(`/api/*`)로 제공하면 DNS 오버헤드가 없지만 CDN 캐시를 분리 적용하기 어렵다. 별도 서브도메인(`api.example.com`)으로 분리하면 DNS TTL·라우팅 정책을 독립적으로 제어할 수 있다.
---
### 3-2. Recursive vs Iterative 질의
#### Recursive 질의 (재귀 질의)
클라이언트가 Recursive Resolver에게 "최종 답만 줘"라고 요청. Resolver가 모든 중간 질의를 대신 수행.
```text클라이언트 ──[recursive 질의]──▶ Recursive Resolver │ (내부적으로 반복 질의)클라이언트 ◀──[최종 IP 응답]──── Recursive Resolver```text
- **주로 사용되는 구간**: 클라이언트 ↔ Recursive Resolver- **특징**: 클라이언트는 기다리기만 하면 됨
#### Iterative 질의 (반복 질의)
Resolver가 각 단계 서버에 "모르면 다음 서버 주소라도 알려줘"라고 물어보고, 직접 다음 서버를 찾아가는 방식.
```textRecursive Resolver ──[iterative]──▶ Root NS: "TLD 서버는 X야"Recursive Resolver ──[iterative]──▶ TLD NS: "Authoritative는 Y야"Recursive Resolver ──[iterative]──▶ Authoritative NS: "IP는 Z야"```text
- **주로 사용되는 구간**: Recursive Resolver ↔ Root/TLD/Authoritative- **특징**: Resolver가 직접 발로 뛰며 정보 수집
#### 실제 동작 (혼합 방식)
```text클라이언트 ──[Recursive]──▶ Resolver ──[Iterative]──▶ Root → TLD → Auth```text
실무에서 대부분의 DNS 해석은 이 혼합 방식으로 동작한다.
---
### 3-2-1. Private Hosted Zone — VPC 내부 DNS
**Private Hosted Zone**은 VPC 안에서만 해석되는 내부 전용 DNS 영역이다. 같은 이름(`db.internal`)을 외부에서 조회하면 NXDOMAIN이 나오고, VPC 안에서는 내부 IP가 반환된다.
```text[외부]dig db.internal → NXDOMAIN (응답 없음)
[VPC 내부 ECS Task]dig db.internal → 10.0.21.5 (RDS Private IP)```text
**실무 활용**: 마이크로서비스 간 통신에 Private Hosted Zone을 사용하면, 서비스 IP가 바뀌어도 도메인을 고정할 수 있다. ECS Service Discovery와 함께 쓰면 `service-a.internal` → ECS Task로 자동 라우팅된다.
```hcl# Private Hosted Zone 생성 (Terraform)resource "aws_route53_zone" "private" { name = "internal.example.com"
vpc { vpc_id = aws_vpc.main.id } # private = true 는 vpc 블록이 있으면 자동 설정됨}
resource "aws_route53_record" "rds" { zone_id = aws_route53_zone.private.zone_id name = "db.internal.example.com" type = "CNAME" ttl = 300 records = [aws_db_instance.main.address]}```text
**주의사항**: Private Hosted Zone은 반드시 VPC와 연결해야 한다. 연결된 VPC 안에서만 해석된다. 여러 VPC에서 같은 Zone에 접근하려면 각 VPC를 모두 연결해야 한다.
---
### 3-3. TTL (Time To Live)
DNS 응답에 포함된 캐시 유효 시간(초 단위).
```textapi.example.com. 300 IN A 52.94.1.2 ↑ TTL = 300초 (5분)```text
| TTL 값 | 특징 | 사용 사례 || -------------- | -------------------------- | ----------------------- || 60초 이하 | 변경 빠름, DNS 쿼리 많아짐 | 장애 조치, 배포 전환 || 300초 (5분) | 균형 | 일반적인 API 서버 || 3600초 (1시간) | 안정적, 변경 느림 | 변경이 드문 정적 리소스 || 86400초 (1일) | 최대 캐싱 | 거의 변하지 않는 도메인 |
**실무 팁**: 서버 마이그레이션 계획 시 최소 TTL의 2배 전에 TTL을 낮춰두어야 한다. TTL이 1시간이면 변경 1시간 전에 TTL을 60초로 줄여야 전환이 빠르다.
---
### 3-3-1. DNS 원리의 전이 가능성 — 캐싱과 위임 트리가 어디서 다시 나타나는가
DNS에서 배운 두 가지 핵심 패턴(TTL 기반 캐싱, 계층적 위임 트리)은 다른 시스템에서 동일한 형태로 반복된다. 이 패턴을 인식하면 CDN, HTTP 캐시, Redis, 서비스 디스커버리를 처음 보는 기술이 아니라 **이미 알고 있는 패턴의 변형**으로 이해할 수 있다.
#### TTL 캐싱 원리의 전이
DNS TTL의 핵심은 "원본에 묻지 않고 유효 시간 동안 로컬에서 응답하고, 만료되면 원본에 재확인한다"는 것이다. 이 원리는 아래 시스템에서 동일하게 작동한다.
| 시스템 | TTL 역할 | 만료 동작 || --- | --- | --- || **DNS Resolver 캐시** | 레코드 TTL (RFC 1035 §3.2.1) | TTL 0이 되면 Authoritative NS에 재질의 || **CDN Edge Cache** | Cache-Control: `s-maxage` / CDN-Cache-Control | Edge에서 stale 상태가 되면 Origin으로 재검증(If-None-Match) || **HTTP Cache-Control** | `max-age=300` | 브라우저가 만료 후 조건부 GET 재요청 || **Redis EXPIRE** | `EXPIRE key 300` (초 단위) | TTL 0이 되면 키 자동 삭제, 다음 요청 시 DB에서 재적재 |
공통 trade-off: TTL을 길게 잡으면 원본 부하가 줄고 응답이 빠르지만, 변경 전파가 느리다. TTL을 짧게 잡으면 최신성이 올라가지만 원본 요청이 증가한다. DNS 마이그레이션 전 TTL을 낮추는 절차가 CDN Purge나 Redis `DEL`을 선제적으로 실행하는 절차와 동일한 이유다.
#### 위임 트리 구조의 전이
DNS 위임 트리(Root → TLD → Authoritative)는 "상위 계층이 하위 계층의 주소만 알고, 실제 데이터는 리프 노드가 보유한다"는 설계다. 마이크로서비스 서비스 디스커버리도 같은 구조로 동작한다.
| DNS 계층 | 마이크로서비스 대응 || --- | --- || Root Nameserver | Consul Agent / K8s API Server (전체 레지스트리 게이트웨이) || TLD Nameserver (`.svc.cluster.local`) | K8s CoreDNS zone (`cluster.local` 위임 존) || Authoritative NS (서비스 레코드) | CoreDNS가 Service → ClusterIP를 A 레코드로 반환 || NS 위임 레코드 | Consul DNS 포워딩 (`consul.` 도메인 → Consul Agent) |
K8s에서 `curl http://payment-svc.payments.svc.cluster.local`을 호출하면, Pod의 `/etc/resolv.conf`가 CoreDNS로 질의를 보내고, CoreDNS가 `payments` 네임스페이스의 `payment-svc` Service ClusterIP를 반환한다. DNS 위임처럼 CoreDNS가 `cluster.local` zone을 위임받아 관리하는 구조다. Consul을 함께 쓸 때는 CoreDNS가 `*.consul` 도메인을 Consul Agent(port 8600)로 포워딩한다 — TLD 위임과 동일한 패턴이다.
> 📖 참고: [CoreDNS: DNS and Service Discovery](https://coredns.io/) | [Kubernetes DNS 커스터마이징](https://kubernetes.io/docs/tasks/administer-cluster/dns-custom-nameservers/) | [Cloudflare CDN-Cache-Control](https://developers.cloudflare.com/cache/concepts/cdn-cache-control/)
---
### 3-4. DNS 레코드 타입
| 레코드 | 용도 | 예시 || --------- | ----------------------------------------- | ----------------------------------- || **A** | 도메인 → IPv4 | `api.example.com → 52.94.1.2` || **AAAA** | 도메인 → IPv6 | `api.example.com → 2001:db8::1` || **CNAME** | 도메인 → 다른 도메인 | `www.example.com → example.com` || **MX** | 메일 서버 지정 (우선순위 포함) | `10 mail.example.com` || **TXT** | 텍스트 정보 (SPF, DKIM, 도메인 소유 확인) | `v=spf1 include:amazonses.com ~all` || **NS** | 도메인의 Authoritative Nameserver | `ns-123.awsdns-45.com` || **SOA** | 도메인 권한 정보 (시리얼, 갱신 주기) | 자동 생성됨 |
**실무 예시 — TXT 레코드 활용**:
```bash# AWS SES 도메인 검증_amazonses.example.com TXT "pmBGN/7MjnfhTKUZ06Enqq1PeGUaOkw8lGl..."
# Google Workspace 도메인 소유 확인example.com TXT "google-site-verification=abc123..."```text
---
### 3-5. AWS Alias Record vs CNAME — Zone Apex 문제
#### Zone Apex(존 정점)란?
도메인의 루트 자체. `example.com` (www 없는 버전)이 Zone Apex다.
**DNS 표준 제약**: Zone Apex에는 CNAME을 설정할 수 없다.
```text# 이것은 DNS 표준 위반 (불가능)example.com CNAME alb-1234.ap-northeast-2.elb.amazonaws.com```text
왜냐하면 Zone Apex에는 NS, SOA 레코드가 반드시 존재해야 하는데, CNAME은 다른 레코드와 공존할 수 없기 때문이다.
#### AWS Alias Record로 해결
Route 53의 Alias Record는 AWS가 만든 독자적 확장 기능이다.
```text# Alias Record: Zone Apex에서 ALB 연결 가능example.com A ALIAS alb-1234.ap-northeast-2.elb.amazonaws.com```text
| 비교 항목 | CNAME | Alias Record || -------------- | ----------- | ------------------------ || Zone Apex 사용 | 불가 | 가능 || 대상 | 모든 도메인 | AWS 리소스 전용 || 비용 | 쿼리당 과금 | 무료 || IP 자동 추적 | 불가 | ALB IP 변경 시 자동 추적 || TTL 설정 | 직접 설정 | Route 53이 자동 관리 || DNS 표준 | O | X (AWS 전용) |
**Alias 지원 대상**:
- CloudFront 배포- ALB / NLB / CLB- S3 정적 웹사이트 엔드포인트- API Gateway- 같은 Hosted Zone 내의 다른 Route 53 레코드
---
### 3-6. DNS 캐싱 계층
```text브라우저 캐시 │ (miss) ▼OS DNS 캐시 (nscd / systemd-resolved) │ (miss) ▼ISP / 기업 Recursive Resolver │ (miss) ▼Root → TLD → Authoritative Nameserver```text
**각 계층 확인 방법**:
```bash# macOS: OS DNS 캐시 비우기sudo dscacheutil -flushcache; sudo killall -HUP mDNSResponder
# Linux: systemd-resolved 캐시 확인resolvectl statistics
# 브라우저: Chrome은 chrome://net-internals/#dns 에서 캐시 확인/삭제```text
---
## 4. 실무에서 어떻게 쓰이나
### 4-1. `api.example.com` → ALB 연결
**구성**: Route 53 → Alias → ALB → ECS/EC2 Nest.js API
```textRoute 53 Hosted Zone: example.com└── api.example.com └── A Alias → alb-api-1234.ap-northeast-2.elb.amazonaws.com```text
**Terraform 예시**:
```hclresource "aws_route53_record" "api" { zone_id = aws_route53_zone.main.zone_id name = "api.example.com" type = "A"
alias { name = aws_lb.api.dns_name zone_id = aws_lb.api.zone_id evaluate_target_health = true }}```text
### 4-2. CloudFront 배포에 커스텀 도메인 연결
```textwww.example.com (Alias) → xxxx.cloudfront.net```text
Route 53에서 CloudFront 배포에 Alias Record를 생성하면, CloudFront가 자동으로 HTTPS 인증서(ACM)와 엮어서 동작한다.
```hclresource "aws_route53_record" "www" { zone_id = aws_route53_zone.main.zone_id name = "www.example.com" type = "A"
alias { name = aws_cloudfront_distribution.main.domain_name zone_id = aws_cloudfront_distribution.main.hosted_zone_id evaluate_target_health = false }}```text
### 4-3. Route 53 라우팅 정책 실무 선택 가이드
| 상황 | 정책 | 이유 || ------------------------------------- | ----------- | ---------------------------- || 단순 연결 (ALB 1개) | Simple | 가장 기본 || 카나리 배포 (신버전 10% 트래픽) | Weighted | 비율 제어 || 멀티 리전 (ap-northeast-2, us-east-1) | Latency | 응답 지연 최소화 || Active-Passive 고가용성 | Failover | 메인 장애 시 스탠바이로 전환 || 국가별 다른 콘텐츠 | Geolocation | 규정/언어 대응 |
### 4-4. Active-Active vs Active-Passive Failover — 선택 기준
**Active-Passive**: Primary 리소스가 정상일 때만 서빙. 장애 시 Secondary(대기 서버)로 전환. DR 비용이 적지만 Failover 시 60~120초 전환 지연이 있다.
```text[정상 시] → Route 53은 Primary만 응답[Primary 장애 시] → Route 53이 Health Check 실패 감지 → Secondary를 반환
설정법:Primary 레코드: Failover = PRIMARY, Health Check 연결Secondary 레코드: Failover = SECONDARY (Health Check 없어도 됨)```text
**Active-Active**: 여러 리소스가 동시에 트래픽을 처리. 하나가 장애 나도 나머지가 계속 서빙. Weighted 또는 Latency 라우팅으로 구현한다.
```text[정상 시] → 여러 리전/서버가 동시에 트래픽 처리[서울 장애 시] → Health Check 실패 → Route 53이 서울 응답 제외 → 도쿄/버지니아만 응답 (서비스 무중단)```text
**AWS 공식 권고 (2024)**: 가능하면 Active-Active를 사용하라. DNS 레코드를 업데이트하는 것보다 **데이터 플레인(Health Check)**을 활용한 자동 전환이 더 빠르고 안정적이다. 재해 복구가 필요한 경우 **Application Recovery Controller(ARC)**와 Route 53을 연동하면 수동 개입 없이 리전 간 자동 Failover가 가능하다.
```bash# Geolocation 정책 사용 시 반드시 Default 레코드 설정 필요# Default 없으면 커버되지 않는 지역 클라이언트는 NXDOMAIN 응답 받음aws route53 change-resource-record-sets \ --hosted-zone-id Z1234567890 \ --change-batch '{ "Changes": [{ "Action": "CREATE", "ResourceRecordSet": { "Name": "api.example.com", "Type": "A", "GeoLocation": { "CountryCode": "*" }, "TTL": 300, "ResourceRecords": [{"Value": "52.94.1.2"}] } }] }'# → CountryCode: "*" 가 Default 레코드 역할```text
---
## 5. 내 업무와 어떻게 연결되나
BackOps / Nest.js + AWS 스택 기준:
- **API 서버 배포**: ECS에 Nest.js 배포 시 `api.example.com → ALB Alias` 설정이 필수. Zone Apex를 피하려면 `api.` 서브도메인을 쓰는 것이 일반적.- **스테이징 환경 분리**: `api-staging.example.com`을 별도 ALB에 연결해 프로덕션과 격리.- **헬스 체크 + Failover**: Route 53 Health Check가 ALB를 감시하다가 장애 감지 시 DR 리전으로 자동 전환. `evaluate_target_health = true`가 핵심.- **SES 이메일 설정**: 이메일 발송 서비스 연동 시 MX, TXT (SPF/DKIM) 레코드를 Route 53에 추가해야 함.- **TXT 레코드 디버깅**: GitHub Actions에서 OIDC 설정이나 외부 서비스 도메인 인증 실패 시 TXT 레코드를 가장 먼저 확인.
---
## 6. 비교 / 대안
### Route 53 vs Cloudflare DNS
| 항목 | Route 53 | Cloudflare DNS || ------------- | ----------------------------- | ------------------------------ || DNS 응답 속도 | 평균 ~20ms | 평균 ~11ms (세계 1위) || AWS 통합 | 완벽 (Alias, Health Check) | 제한적 || 라우팅 정책 | 8가지 (지리, 지연, 가중치 등) | 기본만 제공 || DDoS 방어 | 기본 제공 | 더 강력한 엣지 보호 || WAF 통합 | AWS WAF 별도 | 무료 플랜에도 기본 포함 || 가격 | Hosted Zone당 $0.50/월 + 쿼리 | 무료 플랜 있음 || 글로벌 PoP | 약 100개 | 310개+ || 적합한 상황 | AWS 올인원 스택 | 멀티클라우드, 글로벌 성능 우선 |
### Route 53 vs Azure DNS / Google Cloud DNS
| 항목 | Route 53 | Azure DNS | Google Cloud DNS || ---------------- | --------------------- | ------------------------ | ---------------- || 각 클라우드 통합 | AWS 완벽 | Azure 완벽 | GCP 완벽 || 가격 (Zone) | $0.50/월 | $0.50/월 | $0.20/월 || 라우팅 정책 | 풍부함 | 기본 | 기본 || 결론 | AWS 스택이면 Route 53 | Azure 스택이면 Azure DNS | GCP면 Google |
---
## 6.5. 트러블슈팅
### 케이스 1: DNS 전파 지연 (Propagation Delay)
**증상**: 레코드를 변경했는데 일부 지역/네트워크에서는 이전 IP로 응답함.
**원인**: 기존 TTL 동안 각 Resolver가 캐시를 유지.
**해결**:
```bash# 여러 DNS 서버에서 직접 쿼리해서 전파 상태 확인dig @8.8.8.8 api.example.com # Google DNSdig @1.1.1.1 api.example.com # Cloudflare DNSdig @205.251.196.1 api.example.com # Route 53 Authoritative 직접
# 전파 확인 사이트: https://dnschecker.org```text
**예방**: 변경 전 최소 TTL × 2 시간 전에 TTL을 낮춰둔다 (예: 3600 → 60).
---
### 케이스 2: NXDOMAIN 오류
**증상**: `dig api.example.com` 결과에 `NXDOMAIN` 표시. 서비스 전체 불통.
**원인 체크리스트**:
1. Hosted Zone이 올바른 도메인으로 생성되었는가?2. 도메인 등록사(가비아, Route 53 Registrar)의 NS 레코드가 Route 53 Hosted Zone NS와 일치하는가?3. 레코드 이름에 오타가 없는가? (`api.example.com.` 마지막 점 주의)
```bash# NS 레코드 확인 (도메인 등록사 NS와 비교)dig NS example.com
# Route 53 Hosted Zone NS 확인 (콘솔 또는 CLI)aws route53 list-resource-record-sets \ --hosted-zone-id Z1234567890 \ --query "ResourceRecordSets[?Type=='NS']"```text
---
### 케이스 3: ALB DNS 연결 실패 (Health Check 미통과)
**증상**: Route 53 Failover 설정 후 트래픽이 항상 Secondary로만 감.
**원인**: Health Check가 Primary ALB를 unhealthy로 판정.
**확인 방법**:
```bash# Health Check 상태 확인aws route53 get-health-check-status \ --health-check-id abc12345-1234-1234-1234-123456789012
# ALB 타겟 그룹 헬스 직접 확인aws elbv2 describe-target-health \ --target-group-arn arn:aws:elasticloadbalancing:...```text
**해결**:
- Security Group이 Route 53 Health Check IP 범위를 허용하는지 확인- Health Check 경로(`/health`)가 200을 반환하는지 확인- `evaluate_target_health = true`로 ALB 자체 헬스와 연동
---
### 케이스 4: CNAME Loop / CNAME Flattening 오류
**증상**: `CNAME to CNAME` 체인이 너무 길거나 순환 참조 발생.
**원인**: `a.example.com → b.example.com → a.example.com` 형태의 순환 CNAME.
**해결**: `dig +trace api.example.com`으로 CNAME 체인 추적 후 순환 여부 확인.
---
### 케이스 5: TTL이 너무 길어 긴급 전환 불가
**증상**: 장애 발생 후 IP를 바꿨는데 TTL 1시간 동안 트래픽이 구 서버로 계속 들어옴.
**해결**: 즉시 TTL을 60초로 낮추고, 현재 TTL 만료 후부터 효과 발생 대기.
**예방**: 프로덕션 레코드 TTL은 평상시 300초, 마이그레이션 전날 60초로 낮추는 것이 표준 절차.
---
### 케이스 6: Geolocation 라우팅에서 특정 국가 클라이언트가 NXDOMAIN 응답
**증상**: 특정 국가(예: 동남아시아) 사용자들만 `NXDOMAIN` 또는 서비스 불통. 한국·미국 사용자는 정상.
**원인**: Geolocation 라우팅 설정 시 Default 레코드가 없어서, 커버되지 않는 지역 클라이언트에게 Route 53이 응답을 반환하지 않음.
**해결**:
```bash# Default 레코드 추가 (CountryCode "*")# → 어떤 국가 코드도 매칭되지 않으면 이 레코드로 응답aws route53 change-resource-record-sets \ --hosted-zone-id Z1234567890 \ --change-batch '{ "Changes": [{ "Action": "CREATE", "ResourceRecordSet": { "Name": "api.example.com", "Type": "A", "GeoLocation": {"CountryCode": "*"}, "TTL": 300, "ResourceRecords": [{"Value": "52.94.1.2"}] } }] }'
# 확인: 특정 지역에서 응답 시뮬레이션aws route53 test-dns-answer \ --hosted-zone-id Z1234567890 \ --record-name api.example.com \ --record-type A \ --edns0-client-subnet-ip 203.0.113.0 # 태국 IP 예시# → 응답이 와야 정상```text
**AWS 공식 권고**: Geolocation, Geoproximity, Latency 라우팅 정책을 사용할 때는 **반드시 Default 레코드**를 함께 설정하라. 설정하지 않으면 매핑되지 않는 지역 사용자는 응답을 받지 못한다.
---
### 케이스 7: DNSSEC 검증 실패 → SERVFAIL
**증상**: 특정 도메인에서 `SERVFAIL` 응답. `dig api.example.com`은 결과가 없는데 `dig @8.8.8.8 api.example.com +cd`는 정상 응답함.
**원인**: DNSSEC 서명 만료 또는 DS-DNSKEY 체인 불일치. DNSSEC을 활성화한 도메인에서 서명(RRSIG)이 만료되거나, 상위 존의 DS 레코드와 하위 존의 DNSKEY가 불일치하면, 검증 리졸버가 응답을 버리고 `SERVFAIL`을 반환한다 (RFC 4035 §5.3).
```bash# 1단계: DNSSEC이 원인인지 확인# +cd (Checking Disabled) 를 붙이면 검증 건너뜀dig api.example.com # SERVFAIL ← 검증 실패 시dig api.example.com +cd # 정상 응답 ← 검증만 꺼도 됨 → DNSSEC이 원인
# 2단계: RRSIG(서명) 만료 여부 확인dig api.example.com +dnssec# ANSWER SECTION에 RRSIG 레코드의 "Signature Expiration" 날짜 확인# 예: api.example.com. 300 IN RRSIG A ... 20260101000000 20251202000000 ...# ↑ 만료일 ↑ 서명일
# 3단계: 체인 전체 검증 (delv — DNSSEC 전용 dig)delv api.example.com A# "fully validated"이면 정상# "BOGUS" 또는 "no valid RRSIG"이면 서명 문제 특정 가능
# 4단계: DS 레코드와 DNSKEY 불일치 확인dig example.com DS # 상위 존(.com)의 DS 레코드dig example.com DNSKEY # 자기 존의 DNSKEY# KeyTag가 일치해야 함 — 불일치면 zone 재서명 필요```
**해결**:- AWS Route 53 DNSSEC 사용 시: `aws route53 get-dnssec --hosted-zone-id Z...`로 KSK 상태 확인 → `ACTION_NEEDED`이면 키 갱신 필요.- 서명 만료: Authoritative 서버에서 zone을 재서명하거나, Route 53이 관리하는 경우 KSK를 교체한다.- DS 불일치: 도메인 등록사에서 DS 레코드를 최신 DNSKEY 값으로 업데이트한다.
**예방**: RRSIG 만료 30일 전 알림을 설정한다. Route 53 DNSSEC은 CloudWatch 메트릭 `DNSSECKeySigningKeysNeedingAction`으로 모니터링 가능.
> 📖 참고: [RFC 4035 §5.3 — Authenticating DNS Responses](https://datatracker.ietf.org/doc/html/rfc4035#section-5.3) | [SERVFAIL after enabling DNSSEC — CaptainDNS](https://www.captaindns.com/en/blog/servfail-after-enabling-dnssec) | [Cloudflare DNSSEC Troubleshooting](https://developers.cloudflare.com/dns/dnssec/troubleshooting/)
---
### 케이스 8: Health Check가 HTTPS 서비스를 unhealthy로 판정
**증상**: Route 53 Health Check가 ALB를 계속 unhealthy로 표시. ALB 자체는 정상 응답 중.
**원인 1**: Health Check가 HTTP(80)로 설정되어 있는데 ALB가 HTTPS(443)만 허용.
**원인 2**: Health Check 요청이 SNI(Server Name Indication) 헤더 없이 들어와서 SSL 핸드셰이크 실패.
**원인 3**: Security Group에서 Route 53 Health Checker IP 범위(`15.177.0.0/18` 등)를 차단.
**해결**:
```bash# Route 53 Health Checker IP 범위 확인aws route53 get-checker-ip-ranges
# 예상 출력 일부:# {# "CheckerIpRanges": [# "15.177.0.0/18",# "54.183.255.128/26",# "54.228.16.0/26",# ...# ]# }
# Security Group에 위 IP 범위를 HTTP/HTTPS 포트로 허용# 또는 Health Check 설정에서 "Enable SNI" 활성화```text
Health Check 설정 확인:
```textRoute 53 → Health checks → <Health check> → Edit- Protocol: HTTPS (HTTP가 아님)- Port: 443- Enable SNI: Yes (HTTPS 사용 시 필수)- String matching: /health 경로가 200 OK 반환하는지 확인```text
---
## 7. 체크리스트
DNS 설정 완료 기준:
- [ ] Route 53 Hosted Zone 생성 후 NS 레코드를 도메인 등록사에 등록했는가?- [ ] Zone Apex(`example.com`)에 CNAME 대신 Alias Record를 사용했는가?- [ ] ALB 연결 시 `evaluate_target_health = true`로 설정했는가?- [ ] TTL 값을 환경(prod/staging)에 맞게 설정했는가?- [ ] `dig` 또는 `nslookup`으로 레코드 응답을 직접 확인했는가?- [ ] Health Check 대상 경로(`/health`)가 정상 응답을 반환하는가?- [ ] Failover 구성 시 Primary/Secondary 타입을 올바르게 지정했는가?- [ ] SES 사용 시 MX, TXT(SPF/DKIM) 레코드를 추가했는가?- [ ] 마이그레이션 전 TTL을 낮추는 절차를 계획에 포함했는가?- [ ] Private Hosted Zone이 올바른 VPC에 연결되어 있는가?
---
## 8. 추가 학습 키워드
Route 53 Health Check, Private Hosted Zone, DNSSEC, GeoDNS, DNS over HTTPS(DoH), DNS over TLS(DoT), Anycast DNS, DNS Firewall, Split-horizon DNS, EDNS(Extension Mechanisms for DNS)
### 📚 추천 리소스
- 📖 [AWS Route 53 공식 문서 — 라우팅 정책](https://docs.aws.amazon.com/Route53/latest/DeveloperGuide/routing-policy.html) — Simple·Weighted·Latency·Failover 8가지 라우팅 정책 공식 설명 및 예시 (입문)- 📖 [Cloudflare — What is DNS?](https://www.cloudflare.com/learning/dns/what-is-dns/) — DNS 동작 원리를 시각적으로 설명, 계층 구조와 캐싱 흐름이 직관적 (입문)- 📖 [Amazon Route 53 Basics — StormIT](https://www.stormit.cloud/blog/amazon-route-53/) — Alias vs CNAME, Hosted Zone, Health Check 개념을 한눈에 정리한 요약 가이드 (입문)- 📖 [Mastering AWS Route 53 — DEV Community](https://dev.to/mechcloud_academy/mastering-aws-route-53-a-practical-guide-to-traffic-routing-50b) — 카나리 배포, 멀티 리전, Failover 등 실제 트래픽 라우팅 시나리오 중심 실습 가이드 (중급)- 📖 [Cloudflare DNS vs AWS Route 53 비교](https://dev.to/mechcloud_academy/cloudflare-dns-vs-aws-route-53-comprehensive-comparative-report-13mk) — 2025년 기준 응답 속도·라우팅 기능·가격 항목별 비교 (중급)
---
## 9. 직접 확인해보기
### dig 명령어 실습
```bash# 기본 A 레코드 조회dig api.example.com
# 특정 DNS 서버에서 조회 (Google Public DNS)dig @8.8.8.8 api.example.com
# 모든 레코드 타입 조회dig api.example.com ANY
# TTL 포함 상세 조회dig api.example.com +ttlid
# 계층 추적 (Root → TLD → Authoritative 전 과정)dig +trace api.example.com
# 예상 출력:# ; <<>> DiG 9.10.6 <<>> api.example.com# ;; ANSWER SECTION:# api.example.com. 300 IN A 52.94.1.2# ↑TTL ↑class ↑type ↑IP```text
### 실제 AWS 서비스 dig 조회 예시
```bash# ALB 도메인 조회 (여러 IP 반환됨 — ALB는 멀티 AZ이므로 보통 2~3개)$ dig alb-api-1234.ap-northeast-2.elb.amazonaws.com
; <<>> DiG 9.10.6 <<>> alb-api-1234.ap-northeast-2.elb.amazonaws.com;; QUESTION SECTION:;alb-api-1234.ap-northeast-2.elb.amazonaws.com. IN A
;; ANSWER SECTION:alb-api-1234.ap-northeast-2.elb.amazonaws.com. 60 IN A 3.38.120.11alb-api-1234.ap-northeast-2.elb.amazonaws.com. 60 IN A 13.124.45.89
;; Query time: 8 msec;; SERVER: 10.0.0.2#53(10.0.0.2) ← VPC DNS Resolver (VPC CIDR + 2)
# Alias Record 조회 (api.example.com → ALB)$ dig @8.8.8.8 api.example.com
;; ANSWER SECTION:api.example.com. 60 IN A 3.38.120.11api.example.com. 60 IN A 13.124.45.89# → Alias이므로 ALB의 IP가 직접 반환됨 (CNAME 체인 없음)# → TTL 60초는 ALB의 TTL을 Route 53이 자동으로 따름
# CloudFront 도메인 조회 (Anycast: 요청 위치에 따라 다른 IP)$ dig xxxx.cloudfront.net
;; ANSWER SECTION:xxxx.cloudfront.net. 60 IN A 13.226.18.102# → 같은 도메인이어도 미국에서 조회하면 다른 IP가 반환됨 (엣지 로케이션)```text
### dig +trace 전체 해석 예시
```bash$ dig +trace api.example.com
# 1단계: Root Nameserver 목록 조회. 518400 IN NS a.root-servers.net.. 518400 IN NS m.root-servers.net.# → Root NS 13개 중 하나를 선택해서 다음 질의
# 2단계: Root NS에게 .com TLD NS 질의com. 172800 IN NS a.gtld-servers.net.com. 172800 IN NS b.gtld-servers.net.# → .com TLD NS 목록 반환
# 3단계: TLD NS에게 example.com Authoritative NS 질의example.com. 172800 IN NS ns-123.awsdns-45.com.example.com. 172800 IN NS ns-456.awsdns-78.net.# → Route 53 Authoritative NS 반환
# 4단계: Route 53에게 api.example.com 질의api.example.com. 300 IN A 52.94.1.2# → 최종 IP 응답
;; Received 45 bytes from 205.251.196.1#53(ns-123.awsdns-45.com) in 12 ms# ↑ Route 53 Authoritative NS에서 12ms 만에 응답```text
### nslookup으로 조회
```bash# 기본 조회nslookup api.example.com
# 특정 서버 지정nslookup api.example.com 8.8.8.8
# 예상 출력:# Server: 8.8.8.8# Address: 8.8.8.8#53## Non-authoritative answer:# Name: api.example.com# Address: 52.94.1.2```text
### Route 53 Hosted Zone 레코드 CLI 조회
```bash# Hosted Zone ID 확인aws route53 list-hosted-zones --query "HostedZones[*].[Name,Id]" --output table
# 특정 Zone의 레코드 목록aws route53 list-resource-record-sets \ --hosted-zone-id /hostedzone/Z1234567890 \ --output table
# A 레코드만 필터링aws route53 list-resource-record-sets \ --hosted-zone-id /hostedzone/Z1234567890 \ --query "ResourceRecordSets[?Type=='A']"```text
### Health Check 상태 모니터링
```bash# Health Check 목록aws route53 list-health-checks --output table
# 특정 Health Check 상태 (healthy / unhealthy)aws route53 get-health-check-status \ --health-check-id YOUR_HEALTH_CHECK_ID \ --query "HealthCheckObservations[*].[Region,StatusReport.Status]" \ --output table```text
---
## 10. 요약
DNS는 도메인을 IP로 바꾸는 인터넷 전화번호부다. 질의 과정은 **클라이언트 → Recursive Resolver → Root → TLD → Authoritative** 계층으로 진행되며, 클라이언트는 Recursive 방식으로 요청하고 Resolver 내부는 Iterative 방식으로 동작한다.
AWS에서는 **Route 53**이 Authoritative Nameserver 역할을 한다. 핵심 포인트:
1. **Alias Record**: Zone Apex(`example.com`)에 ALB/CloudFront를 연결할 때 CNAME 대신 사용. 무료이고 IP 자동 추적.2. **TTL**: 변경 전 낮추는 것이 안전. 긴급 전환 시 TTL 값만큼 기다려야 한다.3. **라우팅 정책**: Simple(기본) → Weighted(카나리) → Latency(멀티리전) → Failover(HA) 순으로 복잡도 증가.4. **Health Check**: Failover 라우팅의 핵심. Security Group에서 Route 53 프로브 IP를 허용해야 동작.5. **dig 명령어**: 설정 후 반드시 `dig @8.8.8.8 도메인`으로 실제 응답 검증.
BackOps 실무에서 DNS 설정은 보통 "한 번 하고 잊는" 작업이지만, 잘못 설정하면 전체 서비스 장애로 이어진다. TTL과 NS 레코드 동기화를 항상 먼저 확인하라.