Kubernetes Service 통신 완벽 가이드 + Tailscale DNS 문제 해결
목차
- 문제 상황 분석
- Kubernetes Service 통신 흐름
- CoreDNS 동작 원리
- Tailscale이 DNS에 미치는 영향
- 완전한 패킷 흐름 분석
- 문제 해결 방법
- 트러블슈팅 가이드
- 모니터링 및 디버깅
문제 상황 분석
실제 발생한 문제
요청:
Pod → frigate.video-management-system.svc.cluster.local
CoreDNS가 받은 쿼리:
frigate.video-management-system.svc.cluster.local.tailb45a71.ts.net
^^^^^^^^^^^^^^^^
Tailscale 도메인 추가됨!
결과:
[ERROR] Failed to resolve (Caused by NameResolutionError)로그 분석
CoreDNS 에러:
[ERROR] plugin/errors: 2 frigate.video-management-system.svc.cluster.local.tailb45a71.ts.net. A: read udp 10.42.0.162:51979->8.8.8.8:53: i/o timeout
분석:
1. 원래 도메인: frigate.video-management-system.svc.cluster.local
2. 실제 쿼리: frigate.video-management-system.svc.cluster.local.tailb45a71.ts.net
3. CoreDNS가 8.8.8.8 (외부 DNS)에 쿼리 → 실패
4. 클러스터 내부 도메인인데 외부로 쿼리를 보냄 (잘못됨!)Kubernetes Service 통신 흐름
Pod to Service 통신 전체 그림
┌─────────────────────────────────────────────────────────────────┐
│ Kubernetes Cluster │
│ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Pod A (Airflow Worker) │ │
│ │ IP: 10.42.0.100 │ │
│ │ Namespace: workflow-engine │ │
│ │ │ │
│ │ Application Code: │ │
│ │ requests.get('http://frigate.video-management-system │ │
│ │ .svc.cluster.local:5000/api/...') │ │
│ └────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ │ 1. DNS Query │
│ │ "frigate.video-management-system │
│ │ .svc.cluster.local" │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ /etc/resolv.conf (Pod 내부) │ │
│ ├──────────────────────────────────────────────────────────┤ │
│ │ nameserver 10.43.0.10 ← CoreDNS Service IP │ │
│ │ search workflow-engine.svc.cluster.local │ │
│ │ svc.cluster.local │ │
│ │ cluster.local │ │
│ │ options ndots:5 │ │
│ └────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ │ 2. DNS Query 전송 │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ CoreDNS Pod (kube-system namespace) │ │
│ │ IP: 10.42.1.5 │ │
│ │ │ │
│ │ Corefile: │ │
│ │ cluster.local { │ │
│ │ kubernetes cluster.local in-addr.arpa ip6.arpa { │ │
│ │ pods insecure │ │
│ │ fallthrough in-addr.arpa ip6.arpa │ │
│ │ } │ │
│ │ } │ │
│ └────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ │ 3. Kubernetes API 조회 │
│ │ "frigate" Service 정보 요청 │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Kubernetes API Server │ │
│ │ │ │
│ │ Services: │ │
│ │ - frigate.video-management-system │ │
│ │ ClusterIP: 10.43.123.45 │ │
│ │ Port: 5000 │ │
│ │ Selector: app=frigate │ │
│ └────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ │ 4. DNS Response │
│ │ A record: 10.43.123.45 │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Pod A │ │
│ │ DNS Response 수신: 10.43.123.45 │ │
│ └────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ │ 5. HTTP Request │
│ │ Dst: 10.43.123.45:5000 │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ kube-proxy (iptables or IPVS) │ │
│ │ │ │
│ │ iptables rules: │ │
│ │ -A KUBE-SERVICES -d 10.43.123.45/32 -p tcp │ │
│ │ --dport 5000 -j KUBE-SVC-XXX │ │
│ │ │ │
│ │ -A KUBE-SVC-XXX -j KUBE-SEP-AAA (50% probability) │ │
│ │ -A KUBE-SVC-XXX -j KUBE-SEP-BBB (50% probability) │ │
│ │ │ │
│ │ -A KUBE-SEP-AAA -p tcp -j DNAT │ │
│ │ --to-destination 10.42.2.10:5000 ← Frigate Pod 1 │ │
│ │ -A KUBE-SEP-BBB -p tcp -j DNAT │ │
│ │ --to-destination 10.42.2.11:5000 ← Frigate Pod 2 │ │
│ └────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ │ 6. DNAT 적용 │
│ │ 10.43.123.45:5000 │
│ │ → 10.42.2.10:5000 (실제 Pod) │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Frigate Pod │ │
│ │ IP: 10.42.2.10 │ │
│ │ Port: 5000 │ │
│ │ │ │
│ │ Application 처리 │ │
│ └────────────────────────┬─────────────────────────────────┘ │
│ │ │
│ │ 7. HTTP Response │
│ ▼ │
│ ┌──────────────────────────────────────────────────────────┐ │
│ │ Pod A │ │
│ │ Response 수신 │ │
│ └──────────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────────┘CoreDNS 동작 원리
CoreDNS 설정 파일 (Corefile)
yaml
# kubectl -n kube-system get cm coredns -o yaml
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
# Kubernetes plugin: 클러스터 내부 DNS
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
# Prometheus metrics
prometheus :9153
# Forward plugin: 외부 DNS
forward . /etc/resolv.conf {
max_concurrent 1000
}
# Cache
cache 30
# Loop detection
loop
# Reload
reload
# Load balance
loadbalance
}DNS 쿼리 처리 과정
┌────────────────────────────────────────────────────────────┐
│ CoreDNS Query Processing │
└────────────────────────────────────────────────────────────┘
쿼리: frigate.video-management-system.svc.cluster.local
┌─────────────────────────────────────────────────────────────┐
│ Step 1: Query 수신 │
├─────────────────────────────────────────────────────────────┤
│ - Client: 10.42.0.100 (Pod A) │
│ - Query: frigate.video-management-system.svc.cluster.local │
│ - Type: A (IPv4 주소 조회) │
└──────────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Step 2: Plugin Chain 시작 │
├─────────────────────────────────────────────────────────────┤
│ 1. errors plugin │
│ → 에러 로깅 준비 │
│ │
│ 2. health plugin │
│ → 헬스체크 (pass) │
│ │
│ 3. ready plugin │
│ → Readiness check (pass) │
└──────────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Step 3: kubernetes plugin │
├─────────────────────────────────────────────────────────────┤
│ Zone 확인: cluster.local? │
│ YES → Kubernetes API 조회 │
│ │
│ Query Kubernetes API: │
│ GET /api/v1/namespaces/video-management-system/ │
│ services/frigate │
│ │
│ Response: │
│ { │
│ "metadata": { │
│ "name": "frigate", │
│ "namespace": "video-management-system" │
│ }, │
│ "spec": { │
│ "clusterIP": "10.43.123.45", │
│ "ports": [{ │
│ "port": 5000, │
│ "targetPort": 5000 │
│ }] │
│ } │
│ } │
└──────────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Step 4: DNS Response 생성 │
├─────────────────────────────────────────────────────────────┤
│ Answer: │
│ frigate.video-management-system.svc.cluster.local. │
│ 30 IN A 10.43.123.45 │
│ │
│ Authority: (none) │
│ Additional: (none) │
└──────────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Step 5: cache plugin │
├─────────────────────────────────────────────────────────────┤
│ Cache에 저장 (TTL: 30초) │
│ Key: frigate.video-management-system.svc.cluster.local │
│ Value: 10.43.123.45 │
└──────────────────────┬──────────────────────────────────────┘
│
▼
┌─────────────────────────────────────────────────────────────┐
│ Step 6: Response 전송 │
├─────────────────────────────────────────────────────────────┤
│ UDP Packet: │
│ Src: 10.43.0.10:53 (CoreDNS) │
│ Dst: 10.42.0.100:random (Pod A) │
│ Answer: 10.43.123.45 │
└─────────────────────────────────────────────────────────────┘Search Domain과 ndots
bash
# Pod 내부 /etc/resolv.conf
nameserver 10.43.0.10
search workflow-engine.svc.cluster.local svc.cluster.local cluster.local
options ndots:5ndots:5의 의미:
- 도메인에 점(.)이 5개 미만이면 search domain을 붙여서 시도
frigate.video-management-system.svc.cluster.local- 점이 4개 → search domain 시도!
실제 DNS 쿼리 순서:
Original query: frigate.video-management-system.svc.cluster.local
ndots=5 → 점이 4개 → Search domain 적용!
1st try: frigate.video-management-system.svc.cluster.local.workflow-engine.svc.cluster.local
→ NXDOMAIN (없음)
2nd try: frigate.video-management-system.svc.cluster.local.svc.cluster.local
→ NXDOMAIN (없음)
3rd try: frigate.video-management-system.svc.cluster.local.cluster.local
→ NXDOMAIN (없음)
4th try: frigate.video-management-system.svc.cluster.local (원본 그대로)
→ SUCCESS! 10.43.123.45성능 문제: 불필요한 DNS 쿼리 3번 발생!
해결 방법:
python
# 방법 1: FQDN 사용 (마지막에 점 추가)
url = "http://frigate.video-management-system.svc.cluster.local.:5000"
# ↑
# 점 추가!
# 방법 2: ndots 조정 (Pod spec)
dnsConfig:
options:
- name: ndots
value: "1"Tailscale이 DNS에 미치는 영향
Tailscale 기본 동작
┌─────────────────────────────────────────────────────────────┐
│ Tailscale Network │
├─────────────────────────────────────────────────────────────┤
│ │
│ Node A (Kubernetes Node) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ tailscaled │ │
│ │ Tailscale IP: 100.64.1.10 │ │
│ │ Hostname: k8s-node-1.tailb45a71.ts.net │ │
│ │ │ │
│ │ /etc/resolv.conf (Host): │ │
│ │ nameserver 100.100.100.100 ← Tailscale DNS │ │
│ │ search tailb45a71.ts.net │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
│ Pod (inside Node A) │
│ ┌──────────────────────────────────────────────────────┐ │
│ │ /etc/resolv.conf: │ │
│ │ nameserver 10.43.0.10 ← CoreDNS │ │
│ │ search namespace.svc.cluster.local │ │
│ │ svc.cluster.local │ │
│ │ cluster.local │ │
│ │ tailb45a71.ts.net ← Tailscale domain 추가! │ │
│ │ options ndots:5 │ │
│ └──────────────────────────────────────────────────────┘ │
│ │
└─────────────────────────────────────────────────────────────┘문제 발생 메커니즘
┌────────────────────────────────────────────────────────────┐
│ Problem: Tailscale Search Domain 간섭 │
└────────────────────────────────────────────────────────────┘
Query: frigate.video-management-system.svc.cluster.local
Pod의 /etc/resolv.conf:
nameserver 10.43.0.10
search workflow-engine.svc.cluster.local
svc.cluster.local
cluster.local
tailb45a71.ts.net ← 문제!
options ndots:5
ndots=5 → 점이 4개 → Search domain 시도!
1st: frigate.video-management-system.svc.cluster.local
.workflow-engine.svc.cluster.local
→ CoreDNS → NXDOMAIN
2nd: frigate.video-management-system.svc.cluster.local
.svc.cluster.local
→ CoreDNS → NXDOMAIN
3rd: frigate.video-management-system.svc.cluster.local
.cluster.local
→ CoreDNS → NXDOMAIN
4th: frigate.video-management-system.svc.cluster.local
.tailb45a71.ts.net ← 여기서 문제!
→ CoreDNS → kubernetes plugin (cluster.local이 아님)
→ forward plugin (외부 DNS로 전달)
→ 8.8.8.8 or 172.27.150.2 (upstream DNS)
→ Timeout! (존재하지 않는 도메인)
5th: frigate.video-management-system.svc.cluster.local
(원본 그대로)
→ CoreDNS → kubernetes plugin → SUCCESS!CoreDNS 로그에서 확인
[ERROR] plugin/errors: 2 frigate.video-management-system.svc.cluster.local.tailb45a71.ts.net. A: read udp 10.42.0.162:51979->8.8.8.8:53: i/o timeout
분석:
- 쿼리: frigate.video-management-system.svc.cluster.local.tailb45a71.ts.net
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
Kubernetes 도메인 Tailscale 도메인
- CoreDNS가 이 쿼리를 받음
- kubernetes plugin: "cluster.local"이 아니므로 pass
- forward plugin: 외부 DNS(8.8.8.8)로 전달
- 8.8.8.8: 이런 도메인 없음 → Timeout완전한 패킷 흐름 분석
정상 케이스 (Tailscale 없음)
┌─────────────────────────────────────────────────────────────┐
│ Step 1: Application → DNS Query │
└─────────────────────────────────────────────────────────────┘
Application (Python):
requests.get('http://frigate.video-management-system.svc.cluster.local:5000')
↓ getaddrinfo() system call
glibc resolver:
/etc/resolv.conf 읽기
nameserver 10.43.0.10
search workflow-engine.svc.cluster.local svc.cluster.local cluster.local
options ndots:5
ndots 체크:
"frigate.video-management-system.svc.cluster.local" → 점 4개
→ Search domain 시도!
DNS Query 1:
frigate.video-management-system.svc.cluster.local.workflow-engine.svc.cluster.local
┌─────────────────────────────────────────────────────────────┐
│ Step 2: DNS Query → CoreDNS │
└─────────────────────────────────────────────────────────────┘
UDP Packet:
Src: 10.42.0.100:random
Dst: 10.43.0.10:53 (CoreDNS Service IP)
L2: Ethernet
Src MAC: Pod A veth MAC
Dst MAC: cni0 bridge MAC
L3: IP
Src IP: 10.42.0.100
Dst IP: 10.43.0.10
L4: UDP
Src Port: 54321 (random)
Dst Port: 53
L7: DNS Query
Transaction ID: 0x1234
Flags: Standard query
Questions: 1
Name: frigate.video-management-system.svc.cluster.local.workflow-engine.svc.cluster.local
Type: A
Class: IN
┌─────────────────────────────────────────────────────────────┐
│ Step 3: CoreDNS Processing │
└─────────────────────────────────────────────────────────────┘
CoreDNS receives query
kubernetes plugin:
Zone match? "cluster.local"
frigate.video-management-system.svc.cluster.local.workflow-engine.svc.cluster.local
→ 끝이 "cluster.local"? YES!
Parse query:
Service: frigate
Namespace: video-management-system
But... ".workflow-engine.svc.cluster.local"이 추가로 붙음
→ Kubernetes API 조회 실패 → NXDOMAIN
DNS Response:
RCODE: NXDOMAIN (No such domain)
┌─────────────────────────────────────────────────────────────┐
│ Step 4: Retry (Search domain 계속) │
└─────────────────────────────────────────────────────────────┘
DNS Query 2:
frigate.video-management-system.svc.cluster.local.svc.cluster.local
→ NXDOMAIN
DNS Query 3:
frigate.video-management-system.svc.cluster.local.cluster.local
→ NXDOMAIN
DNS Query 4:
frigate.video-management-system.svc.cluster.local (원본)
→ SUCCESS! A 10.43.123.45
┌─────────────────────────────────────────────────────────────┐
│ Step 5: HTTP Request → Service │
└─────────────────────────────────────────────────────────────┘
TCP Handshake:
SYN: 10.42.0.100:54322 → 10.43.123.45:5000
iptables DNAT (kube-proxy):
-A KUBE-SERVICES -d 10.43.123.45/32 -p tcp --dport 5000
-j KUBE-SVC-FRIGATE
-A KUBE-SVC-FRIGATE -m statistic --mode random --probability 0.5
-j KUBE-SEP-FRIGATE-POD1
-A KUBE-SEP-FRIGATE-POD1 -p tcp
-j DNAT --to-destination 10.42.2.10:5000
Packet 변환:
Before DNAT: 10.42.0.100 → 10.43.123.45:5000
After DNAT: 10.42.0.100 → 10.42.2.10:5000
┌─────────────────────────────────────────────────────────────┐
│ Step 6: Packet Routing to Pod │
└─────────────────────────────────────────────────────────────┘
Routing decision:
Dst: 10.42.2.10
Route table: 10.42.2.0/24 via flannel.1 (VXLAN)
VXLAN Encapsulation:
Outer IP: Node A IP → Node B IP
Outer UDP: Port 4789
VXLAN: VNI 1
Inner IP: 10.42.0.100 → 10.42.2.10
Inner TCP: 54322 → 5000
┌─────────────────────────────────────────────────────────────┐
│ Step 7: Frigate Pod Receives Request │
└─────────────────────────────────────────────────────────────┘
VXLAN Decapsulation at Node B
TCP Connection:
10.42.0.100:54322 ←→ 10.42.2.10:5000
HTTP Request:
GET /api/115/recordings?after=... HTTP/1.1
Host: frigate.video-management-system.svc.cluster.local:5000
Frigate Application processes request
HTTP Response:
HTTP/1.1 200 OK
Content-Type: application/json
...문제 케이스 (Tailscale 있음)
┌─────────────────────────────────────────────────────────────┐
│ Step 1-3: 동일 (Search domain 시도) │
└─────────────────────────────────────────────────────────────┘
Query 1-3: NXDOMAIN (동일)
┌─────────────────────────────────────────────────────────────┐
│ Step 4: Tailscale Search Domain 시도 (문제!) │
└─────────────────────────────────────────────────────────────┘
DNS Query 4:
frigate.video-management-system.svc.cluster.local.tailb45a71.ts.net
^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^^ ^^^^^^^^^^^^^^^^^^
Kubernetes 도메인 Tailscale 도메인
CoreDNS receives query:
kubernetes plugin:
Zone match? "cluster.local"
frigate...cluster.local.tailb45a71.ts.net
→ 끝이 "cluster.local"? NO! (끝이 "ts.net")
→ Pass (처리 안 함)
forward plugin:
외부 DNS로 전달
forward . /etc/resolv.conf
/etc/resolv.conf (CoreDNS Pod):
nameserver 8.8.8.8
nameserver 172.27.150.2
UDP Query:
Src: CoreDNS Pod (10.42.0.162)
Dst: 8.8.8.8:53
Question:
frigate.video-management-system.svc.cluster.local.tailb45a71.ts.net
8.8.8.8 (Google DNS):
"그런 도메인 모름"
→ No response (timeout)
CoreDNS:
[ERROR] plugin/errors: 2 frigate.video-management-system.svc.cluster.local.tailb45a71.ts.net. A: read udp 10.42.0.162:51979->8.8.8.8:53: i/o timeout
Retry with 172.27.150.2:
→ Timeout again
┌─────────────────────────────────────────────────────────────┐
│ Step 5: 최종적으로 원본 도메인 시도 │
└─────────────────────────────────────────────────────────────┘
DNS Query 5:
frigate.video-management-system.svc.cluster.local (원본)
CoreDNS kubernetes plugin:
→ SUCCESS! 10.43.123.45
BUT: 이미 많은 시간 소비 (5초 timeout × 여러 번)
→ Application timeout 발생 가능!문제 해결 방법
방법 1: CoreDNS Rewrite Plugin (권장)
Tailscale search domain을 무시하도록 설정:
yaml
# ConfigMap 수정
kubectl -n kube-system edit cm coredns
apiVersion: v1
kind: ConfigMap
metadata:
name: coredns
namespace: kube-system
data:
Corefile: |
.:53 {
errors
health {
lameduck 5s
}
ready
# ========================================
# Tailscale search domain 제거 (추가!)
# ========================================
rewrite stop {
name regex (.*)\.tailb45a71\.ts\.net\.cluster\.local {1}.cluster.local
answer name (.*)\.cluster\.local {1}.tailb45a71.ts.net.cluster.local
}
rewrite stop {
name regex (.*)\.tailb45a71\.ts\.net {1}
answer auto
}
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
prometheus :9153
forward . /etc/resolv.conf {
max_concurrent 1000
}
cache 30
loop
reload
loadbalance
}동작 원리:
Query: frigate.video-management-system.svc.cluster.local.tailb45a71.ts.net
rewrite plugin:
Pattern match: (.*)\.tailb45a71\.ts\.net
Capture: frigate.video-management-system.svc.cluster.local
Rewrite to: frigate.video-management-system.svc.cluster.local
kubernetes plugin:
Query: frigate.video-management-system.svc.cluster.local
→ SUCCESS!방법 2: Tailscale DNS 설정 수정
Tailscale이 Kubernetes에 search domain을 주입하지 않도록:
bash
# Tailscale 설정 확인
tailscale status
tailscale netcheck
# Node에서 Tailscale 설정 수정
# /etc/systemd/system/tailscaled.service.d/override.conf
[Service]
Environment="TS_ACCEPT_DNS=false"
# 재시작
sudo systemctl daemon-reload
sudo systemctl restart tailscaled또는 Tailscale Admin Console에서:
DNS → Global nameservers → Override local DNS
→ Disable "Add search domains to local DNS"방법 3: Pod DNS Policy 설정
특정 Pod가 Tailscale DNS를 우회하도록:
yaml
apiVersion: v1
kind: Pod
metadata:
name: airflow-worker
spec:
dnsPolicy: "None" # 기본 DNS 설정 무시
dnsConfig:
nameservers:
- 10.43.0.10 # CoreDNS 직접 지정
searches:
- workflow-engine.svc.cluster.local
- svc.cluster.local
- cluster.local
# tailb45a71.ts.net 제외!
options:
- name: ndots
value: "2" # 성능 최적화
- name: timeout
value: "2"
- name: attempts
value: "2"방법 4: FQDN 사용 (임시 해결)
애플리케이션 코드 수정:
python
# Before (문제)
url = "http://frigate.video-management-system.svc.cluster.local:5000"
# After (해결)
url = "http://frigate.video-management-system.svc.cluster.local.:5000"
# ↑
# 점 추가!왜 동작하는가?:
- 마지막 점(.) = FQDN (Fully Qualified Domain Name)
- ndots 체크 무시 → search domain 시도 안 함
- 바로 원본 도메인으로 쿼리
방법 5: NodeLocal DNSCache 사용
DNS 성능 최적화 + Tailscale 문제 우회:
bash
# NodeLocal DNSCache 설치
kubectl apply -f https://k8s.io/examples/admin/dns/nodelocaldns.yaml동작:
Pod → 169.254.20.10 (Node-local DNS cache)
→ Cache hit? Return
→ Cache miss? CoreDNS (10.43.0.10)장점:
- DNS 쿼리 속도 향상
- CoreDNS 부하 감소
- Tailscale search domain 영향 최소화
트러블슈팅 가이드
증상 1: DNS 해석 실패
bash
# Pod 내부에서
kubectl exec -it <pod> -- nslookup frigate.video-management-system.svc.cluster.local
# 실패 시 출력:
Server: 10.43.0.10
Address: 10.43.0.10#53
** server can't find frigate.video-management-system.svc.cluster.local: NXDOMAIN진단 단계:
bash
# 1. Pod DNS 설정 확인
kubectl exec -it <pod> -- cat /etc/resolv.conf
출력:
nameserver 10.43.0.10
search namespace.svc.cluster.local svc.cluster.local cluster.local tailb45a71.ts.net
options ndots:5
문제: tailb45a71.ts.net이 포함됨!
# 2. CoreDNS 로그 확인
kubectl -n kube-system logs -l k8s-app=kube-dns --tail=100
문제 로그:
[ERROR] plugin/errors: 2 frigate...cluster.local.tailb45a71.ts.net. A: read udp ... i/o timeout
# 3. CoreDNS ConfigMap 확인
kubectl -n kube-system get cm coredns -o yaml
확인 사항:
- rewrite plugin 설정 여부
- kubernetes plugin zone 설정
# 4. Service 존재 확인
kubectl -n video-management-system get svc frigate
출력:
NAME TYPE CLUSTER-IP EXTERNAL-IP PORT(S) AGE
frigate ClusterIP 10.43.123.45 <none> 5000/TCP 30d
# 5. CoreDNS에서 직접 쿼리
kubectl run -it --rm debug --image=busybox --restart=Never -- \
nslookup frigate.video-management-system.svc.cluster.local 10.43.0.10
성공하면: CoreDNS는 정상, Pod DNS 설정 문제
실패하면: CoreDNS 설정 문제증상 2: DNS 응답 느림
bash
# DNS 쿼리 시간 측정
kubectl exec -it <pod> -- time nslookup frigate.video-management-system.svc.cluster.local
출력:
real 0m 5.023s ← 너무 느림!
user 0m 0.001s
sys 0m 0.002s원인 분석:
bash
# tcpdump로 DNS 쿼리 캡처
kubectl exec -it <pod> -- tcpdump -i any -nn port 53
출력 분석:
10:30:01.000 A? frigate...workflow-engine.svc.cluster.local
10:30:01.100 NXDOMAIN
10:30:01.200 A? frigate...svc.cluster.local
10:30:01.300 NXDOMAIN
10:30:01.400 A? frigate...cluster.local
10:30:01.500 NXDOMAIN
10:30:01.600 A? frigate...tailb45a71.ts.net ← 여기서 timeout!
10:30:06.600 Timeout
10:30:06.700 A? frigate...cluster.local (원본)
10:30:06.800 A 10.43.123.45 ← 성공
총 5초 이상 소요!해결:
bash
# 방법 1: ndots 조정
kubectl edit deployment <deployment>
spec:
template:
spec:
dnsConfig:
options:
- name: ndots
value: "2" # 5 → 2로 변경
# 방법 2: FQDN 사용 (코드 수정)
# 방법 3: CoreDNS rewrite plugin 추가증상 3: 특정 도메인만 실패
bash
# 증상
kubectl exec -it <pod> -- curl http://frigate.video-management-system.svc.cluster.local:5000
# → 실패
kubectl exec -it <pod> -- curl http://google.com
# → 성공진단:
bash
# CoreDNS forward 설정 확인
kubectl -n kube-system get cm coredns -o yaml | grep -A 5 forward
출력:
forward . /etc/resolv.conf {
max_concurrent 1000
}
# CoreDNS Pod의 /etc/resolv.conf 확인
kubectl -n kube-system exec -it <coredns-pod> -- cat /etc/resolv.conf
출력:
nameserver 8.8.8.8
nameserver 172.27.150.2
search tailb45a71.ts.net ← 문제!
# 외부 도메인은 성공 (8.8.8.8이 응답)
# 클러스터 도메인 + Tailscale suffix는 실패모니터링 및 디버깅
CoreDNS 메트릭 확인
bash
# Prometheus metrics
kubectl -n kube-system port-forward svc/kube-dns 9153:9153
# 메트릭 확인
curl http://localhost:9153/metrics
주요 메트릭:
# coredns_dns_request_duration_seconds: DNS 쿼리 시간
# coredns_dns_requests_total: 총 DNS 요청 수
# coredns_dns_responses_total: DNS 응답 (NOERROR, NXDOMAIN 등)
# coredns_forward_requests_total: Forward된 쿼리 수Grafana Dashboard:
yaml
# Prometheus Query 예시
# 실패한 DNS 쿼리 비율
sum(rate(coredns_dns_responses_total{rcode="NXDOMAIN"}[5m]))
/
sum(rate(coredns_dns_responses_total[5m])) * 100
# Tailscale 도메인 쿼리 수
sum(rate(coredns_forward_requests_total{to=~".*tailb45a71.ts.net.*"}[5m]))
# DNS 쿼리 지연 시간 (p99)
histogram_quantile(0.99,
sum(rate(coredns_dns_request_duration_seconds_bucket[5m])) by (le)
)패킷 캡처로 분석
bash
# CoreDNS Pod에서 패킷 캡처
kubectl -n kube-system exec -it <coredns-pod> -- \
tcpdump -i any -nn -s 0 -w /tmp/coredns.pcap port 53
# 파일 다운로드
kubectl -n kube-system cp <coredns-pod>:/tmp/coredns.pcap ./coredns.pcap
# Wireshark로 분석
wireshark coredns.pcap분석 포인트:
Filter: dns
정상 쿼리:
Query: frigate.video-management-system.svc.cluster.local
Response time: 0.001s
Answer: 10.43.123.45
문제 쿼리:
Query: frigate.video-management-system.svc.cluster.local.tailb45a71.ts.net
Response time: 5.000s (timeout)
Answer: (none)DNS 쿼리 추적 (dig)
bash
# Pod 내부에서
kubectl exec -it <pod> -- sh
# dig 설치 (Alpine 기준)
apk add bind-tools
# DNS 쿼리 추적
dig +trace frigate.video-management-system.svc.cluster.local @10.43.0.10
출력:
; <<>> DiG 9.16.1 <<>> +trace frigate...
;; global options: +cmd
. 518400 IN NS a.root-servers.net.
...
; 최종 응답
frigate.video-management-system.svc.cluster.local. 30 IN A 10.43.123.45
;; Query time: 1 msec
;; SERVER: 10.43.0.10#53(10.43.0.10)로그 기반 모니터링
bash
# CoreDNS 에러 로그 실시간 모니터링
kubectl -n kube-system logs -f -l k8s-app=kube-dns | grep ERROR
# Tailscale 관련 에러만
kubectl -n kube-system logs -f -l k8s-app=kube-dns | grep tailb45a71
# 특정 도메인 쿼리만
kubectl -n kube-system logs -f -l k8s-app=kube-dns | grep frigate정리
문제 원인 요약
1. Tailscale이 Node에 설치됨
└→ /etc/resolv.conf에 search domain 추가
search tailb45a71.ts.net
2. Kubernetes가 Pod 생성 시 resolv.conf 상속
└→ Pod의 /etc/resolv.conf에도 tailb45a71.ts.net 추가
3. Pod에서 Service 호출
└→ frigate.video-management-system.svc.cluster.local
4. glibc resolver의 ndots=5 체크
└→ 점이 4개 → Search domain 시도!
5. 4번째 시도에서 Tailscale domain 추가
└→ frigate...cluster.local.tailb45a71.ts.net
6. CoreDNS가 이 쿼리를 받음
└→ kubernetes plugin: "cluster.local"로 끝나지 않음 → Pass
└→ forward plugin: 외부 DNS(8.8.8.8)로 전달
7. 외부 DNS가 응답 못함 (존재하지 않는 도메인)
└→ Timeout (5초)
8. 최종적으로 원본 도메인으로 재시도
└→ 성공하지만 이미 많은 시간 소비최적 해결 방법
┌─────────────────────────────────────────────────────────────┐
│ 권장 해결 방법 우선순위 │
├─────────────────────────────────────────────────────────────┤
│ │
│ 1순위: CoreDNS rewrite plugin (클러스터 레벨) │
│ - 모든 Pod에 적용 │
│ - 애플리케이션 코드 수정 불필요 │
│ - 성능 영향 최소 │
│ │
│ 2순위: Pod dnsPolicy/dnsConfig (Pod 레벨) │
│ - 특정 워크로드만 조정 │
│ - ndots 최적화 가능 │
│ - 세밀한 제어 가능 │
│ │
│ 3순위: Tailscale DNS 설정 변경 (Node 레벨) │
│ - Tailscale 전체에 영향 │
│ - 다른 Tailscale 기능 영향 가능 │
│ │
│ 4순위: FQDN 사용 (코드 레벨) │
│ - 임시 해결책 │
│ - 모든 도메인에 점(.) 추가 필요 │
│ │
└─────────────────────────────────────────────────────────────┘성능 최적화
yaml
# 최적화된 DNS 설정
apiVersion: v1
kind: Pod
metadata:
name: optimized-pod
spec:
dnsPolicy: "None"
dnsConfig:
nameservers:
- 10.43.0.10
searches:
- video-management-system.svc.cluster.local # 자주 쓰는 namespace
- svc.cluster.local
- cluster.local
options:
- name: ndots
value: "2" # 성능 향상 (5 → 2)
- name: timeout
value: "2" # 빠른 실패
- name: attempts
value: "2" # 재시도 횟수
- name: single-request-reopen # A와 AAAA 쿼리 병렬화
- name: use-vc # TCP 사용 (대용량 응답)성능 개선 효과:
Before (ndots=5, Tailscale domain 포함):
- DNS 쿼리 시간: 5초+
- 불필요한 쿼리: 4번
After (ndots=2, Tailscale domain 제거):
- DNS 쿼리 시간: 0.001초
- 불필요한 쿼리: 0번
→ 5000배 성능 향상!이제 Kubernetes Service DNS 통신과 Tailscale DNS 간섭 문제를 완벽히 이해하고 해결할 수 있습니다!