Kubernetes Networking — On a Real Cluster
Actually Dig Into Cluster DNS
한국어 원문으로 표시합니다.
이 실습은 진짜 쿠버네티스에서 돕니다
VM 안에 k3s 한 대가 실제로 떠 있습니다. CoreDNS 가 진짜로 돌고, 질의를 로그로 남기며, 파드는 실제 컨테이너입니다. 그래서 "이름을 하나 찾는 데 질의가 몇 번 나가는가" 같은 것을 세어 볼 수 있습니다.
처음 뜨는 데 2분쯤 걸립니다. VM 이 부팅하고 k3s 를 설치하기 때문입니다.
목표
파드가 이름을 찾는 경로를 처음부터 끝까지 따라가고, ndots:5 가 만드는
숨은 비용을 직접 세어 확인한 뒤 dnsConfig 로 고칩니다.
왜 중요한가
클러스터에서 "느리다" 는 신고의 상당수가 DNS 입니다. 그런데 애플리케이션 지표에는 잘 잡히지 않습니다. 요청 하나가 이름 하나를 찾는 데 질의를 다섯 번 날리고 그중 넷이 NXDOMAIN 이어도, 애플리케이션 입장에서는 그냥 "조금 느린 요청" 입니다. CoreDNS 의 부하는 조용히 올라가고, 어느 날 파드 수가 늘면 그때 터집니다.
원인은 resolv.conf 한 줄입니다. ndots:5 는 점이 5개 미만인 이름은
먼저 검색 도메인을 붙여 시도하라는 뜻입니다. example.com 은 점이 하나라
example.com.default.svc.cluster.local 부터 물어보게 됩니다. 클러스터 안
이름을 짧게 쓰라고 있는 편의가, 밖으로 나가는 이름에는 그대로 비용이 됩니다.
단계
- CoreDNS 가 어디에 있고 무엇을 하는지 확인해
/root/k8sdns/coredns.txt에 저장하세요.kube-dns서비스의 ClusterIP 와 Corefile 전문이 들어가야 합니다. - 파드 안의
/etc/resolv.conf를 그대로/root/k8sdns/resolv.txt에 저장하세요.nameserver·search·options세 줄이 모두 있어야 합니다. web이라는 Deployment(레플리카 2,nginx:1.27-alpine, 포트 이름http)와 같은 이름의 Service 를 만들고, 긴 이름과 짧은 이름 둘 다 조회해/root/k8sdns/svc-a.txt에 저장하세요. 같은 ClusterIP 가 나와야 합니다.- CoreDNS 의 Corefile 에
log플러그인을 켜고,example.com을 두 가지 도구로 각각 조회해 CoreDNS 로그의 질의 수를 세어/root/k8sdns/ndots.txt에 저장하세요.queries_nslookup=과queries_getaddrinfo=두 줄로 시작하고 그 아래에 로그를 붙입니다.- busybox 의
nslookup한 번 curl한 번 (curlimages/curl:8.10.1) 두 숫자가 크게 다릅니다. 왜 다른지가 이 단계의 핵심입니다.
- busybox 의
web-h라는 헤드리스 Service(clusterIP: None)를 만들고 조회 결과를/root/k8sdns/headless.txt에 저장하세요. 파드 IP 들이 그대로 나와야 합니다.web의 SRV 레코드를 조회해/root/k8sdns/srv.txt에 저장하세요.lowdots라는 파드를dnsConfig로ndots: 1을 주어 띄우고, 4번의curl과 같은 도구로 질의 수를 다시 세어/root/k8sdns/fixed.txt에 저장하세요(queries=줄 포함). 3회 이하여야 합니다. 도구를 바꾸면 비교가 성립하지 않습니다./root/k8sdns/report.md에dns_ip=,queries_before=,queries_after=세 줄과 함께ndots가 왜 문제였는지, 그리고nslookup으로 재면 왜 문제가 보이지 않는지를 적으세요.
참고
- 조회 도구는 파드 안에서 씁니다.
kubectl run q --rm -it --image=busybox:1.36 --restart=Never -- nslookup <이름>이 가장 간단합니다. - Corefile 은
kubectl -n kube-system get cm coredns -o yaml로 봅니다. 고칠 때는kubectl -n kube-system edit cm coredns뒤에kubectl -n kube-system rollout restart deploy coredns를 하세요. - 로그는
kubectl -n kube-system logs deploy/coredns로 봅니다. 세기 전에 로그를 한 번 비우고 싶으면 CoreDNS 를 재시작하면 됩니다. - SRV 이름은
_<포트이름>._<프로토콜>.<서비스>.<네임스페이스>.svc.cluster.local입니다. 포트에 이름이 없으면 SRV 가 만들어지지 않습니다. - 4번의 두 숫자가 다른 이유: busybox 의
nslookup은 DNS 프로토콜을 직접 말하므로search와ndots를 읽지 않습니다. 평범한 애플리케이션은getaddrinfo를 부르고, 그쪽은 resolv.conf 를 그대로 따르며 A 와 AAAA 를 각각 묻습니다. - 로그를 셀 때는 세기 직전에 CoreDNS 를 재시작하세요. 재시작이 곧 로그를 비우는 방법이고, 그래야 앞 단계의 질의가 섞이지 않습니다.
- 흔한 실수 1: 이름 끝에 점을 붙이는 것(
example.com.). 절대 이름이라 검색 도메인을 건너뛰어 배우려던 것이 사라집니다. - 흔한 실수 2: 5번에서
clusterIP: None을 빼는 것. 그러면 평범한 서비스라 ClusterIP 하나만 돌아옵니다.
CoreDNS 는 어디에 있는가
CoreDNS 가 어디에 있고 무엇을 하는지 확인해 /root/k8sdns/coredns.txt 에 저장하세요. kube-dns 서비스의 ClusterIP 와 Corefile 전문이 들어가야 합니다.
kube-dns 라는 이름의 서비스를 kube-system 에서 찾고, coredns ConfigMap 의 Corefile 을 함께 담습니다. 이름이 CoreDNS 인데 서비스 이름이 kube-dns 인 것은 예전 구현의 이름을 그대로 물려받았기 때문입니다.
파드는 무엇을 보고 이름을 찾는가
파드 안의 /etc/resolv.conf 를 그대로 /root/k8sdns/resolv.txt 에 저장하세요. nameserver·search·options 세 줄이 모두 있어야 합니다.
파드 하나를 띄워 그 안의 /etc/resolv.conf 를 그대로 읽습니다. VM 자신의 resolv.conf 가 아니라 파드 안의 것이어야 합니다 — 둘은 완전히 다릅니다.
서비스 이름이 주소가 되는 순간
web 이라는 Deployment(레플리카 2, nginx:1.27-alpine, 포트 이름 http)와 같은 이름의 Service 를 만들고, 긴 이름과 짧은 이름 둘 다 조회해 /root/k8sdns/svc-a.txt 에 저장하세요. 같은 ClusterIP 가 나와야 합니다.
Deployment 와 Service 를 만든 뒤, 같은 네임스페이스의 파드에서 web 과 web.default.svc.cluster.local 을 각각 조회합니다. 짧은 이름이 되는 이유는 search 도메인 덕분입니다.
이름 하나에 질의 몇 번인가
CoreDNS 의 Corefile 에 log 플러그인을 켜고, example.com 을 두 가지 도구로 각각 조회해 CoreDNS 로그의 질의 수를 세어 /root/k8sdns/ndots.txt 에 저장하세요. queries_nslookup= 과 queries_getaddrinfo= 두 줄로 시작하고 그 아래에 로그를 붙입니다.
- busybox 의
nslookup한 번 curl한 번 (curlimages/curl:8.10.1) 두 숫자가 크게 다릅니다. 왜 다른지가 이 단계의 핵심입니다.
Corefile 에 log 를 한 줄 넣고 CoreDNS 를 재시작한 뒤, 파드에서 example.com 을 한 번만 조회하고 로그를 셉니다. 끝에 점을 붙이면(example.com.) 검색 도메인을 건너뛰므로 붙이지 마세요.
헤드리스는 무엇을 돌려주는가
web-h 라는 헤드리스 Service(clusterIP: None)를 만들고 조회 결과를 /root/k8sdns/headless.txt 에 저장하세요. 파드 IP 들이 그대로 나와야 합니다.
clusterIP: None 인 서비스를 만들고 조회합니다. 평범한 서비스와 달리 주소가 여러 개 나옵니다.
포트 번호를 이름으로 찾는다
web 의 SRV 레코드를 조회해 /root/k8sdns/srv.txt 에 저장하세요.
SRV 이름은 _<포트이름>._tcp.<서비스>.<네임스페이스>.svc.cluster.local 입니다. 3단계에서 포트에 http 라는 이름을 붙여 두었습니다.
ndots 를 낮춰 고친다
lowdots 라는 파드를 dnsConfig 로 ndots: 1 을 주어 띄우고, 4번의 curl 과 같은 도구로 질의 수를 다시 세어 /root/k8sdns/fixed.txt 에 저장하세요(queries= 줄 포함). 3회 이하여야 합니다. 도구를 바꾸면 비교가 성립하지 않습니다.
파드 스펙의 dnsConfig.options 에 {name: ndots, value: "1"} 을 넣습니다. 그러면 점이 하나만 있어도 검색 도메인을 거치지 않습니다.
무엇을 배웠나
/root/k8sdns/report.md 에 dns_ip=, queries_before=, queries_after= 세 줄과 함께 ndots 가 왜 문제였는지, 그리고 nslookup 으로 재면 왜 문제가 보이지 않는지를 적으세요.
dns_ip=, queries_before=, queries_after= 세 줄과 함께, ndots 가 왜 문제였는지를 본문에 적습니다.