내부망에 쓸 수 있는 DNS 서버가 하나도 없는 상태에서 쿠버네티스를 설치하면, 파드 안에서 nslookup kubernetes.default.svc.cluster.local 이 timeout 으로 실패한다. 클러스터 내부 이름 해석까지 막히므로 서비스 디스커버리가 통째로 동작하지 않는다.
원인은 CoreDNS 가 노드의 /etc/resolv.conf 를 상위 리졸버로 삼는다는 데 있다. 그 파일에 외부 DNS(8.8.8.8 등)가 적혀 있으면 폐쇄망에서는 응답이 오지 않고, 비어 있거나 자기 자신을 가리키면 다른 방식으로 깨진다.
# 파드에서 클러스터 이름
kubectl run dnstest --rm -it --image=busybox:1.36 --restart=Never -- \
nslookup kubernetes.default.svc.cluster.local
# 파드의 resolv.conf
kubectl run dnstest --rm -it --image=busybox:1.36 --restart=Never -- \
cat /etc/resolv.conf
# CoreDNS 가 실제로 응답하는지 (서비스 IP 로 직접)
kubectl run dnstest --rm -it --image=busybox:1.36 --restart=Never -- \
nslookup kubernetes.default.svc.cluster.local 10.96.0.10
# CoreDNS 로그
kubectl -n kube-system logs -l k8s-app=kube-dns --tail=100
파드의 resolv.conf 에 CoreDNS 서비스 IP 가 정상적으로 들어 있는데 응답이 없으면, 문제는 CoreDNS 자체이거나 CNI 를 통한 파드 → 서비스 IP 경로다. 서비스 IP 로 직접 물었을 때도 안 되면 CoreDNS 파드까지 패킷이 못 가고 있다는 뜻이므로 CNI 를 먼저 본다.
외부로 나갈 곳이 없다면 forward 로 내보내지 말고 클러스터 이름만 해석하게 둔다.
.:53 {
errors
health {
lameduck 5s
}
ready
kubernetes cluster.local in-addr.arpa ip6.arpa {
pods insecure
fallthrough in-addr.arpa ip6.arpa
ttl 30
}
hosts {
10.10.10.11 registry.example.local
10.10.10.12 nfs.example.local
fallthrough
}
cache 30
loop
reload
loadbalance
}
hosts 플러그인은 내부 DNS 서버 없이 몇 개의 고정 이름을 해석해 줄 때 쓴다. 노드마다 /etc/hosts 를 복사해 두는 것보다 관리가 쉽고, ConfigMap 만 고치면 전체에 반영된다.
kubectl -n kube-system edit configmap coredns
kubectl -n kube-system rollout restart deployment coredns
plugin/loop: no next plugin found 로 CoreDNS 가 기동에 실패하는 경우가 있다. CoreDNS 의 플러그인 체인은 순서가 고정돼 있고 loop 는 forward 보다 앞에 온다. forward 를 지우면서 loop 뒤에 질의를 실제로 처리할 플러그인이 하나도 남지 않으면 이 오류가 난다.
해결은 둘 중 하나다.
loop 를 빼거나forward 를 유지하되 실제로 응답하는 주소를 준다. 없으면 hosts · file 같은 종단 플러그인을 체인 뒤에 둔다.loop 플러그인은 자기 자신으로 질의가 되돌아오는 구성을 기동 시점에 잡아내는 안전장치다. 노드의 /etc/resolv.conf 가 127.0.0.53(systemd-resolved 스텁)을 가리키는데 CoreDNS 가 그 파일을 상위로 삼으면 무한 루프가 되며, 이때 나오는 메시지는 Loop (127.0.0.1:... -> :53) detected for zone "." 이다. 증상이 이쪽이면 노드의 resolv.conf 를 실제 리졸버 주소가 담긴 파일로 바꾸거나, kubelet 의 --resolv-conf 를 /run/systemd/resolve/resolv.conf 로 지정한다.
확인 필요 — no next plugin found 의 정확한 발생 조건은 CoreDNS 버전에 따라 메시지가 달라질 수 있다. 기동 실패 시에는 kubectl -n kube-system logs 의 첫 몇 줄을 그대로 근거로 삼는다.
kubeadm init 단계에서 /etc/resolv.conf 에 닿지 않는 외부 DNS 만 적혀 있으면, 설치 자체는 되지만 이후 CoreDNS 가 그 주소를 상위로 물려받아 위 증상이 그대로 재현된다. 폐쇄망이라면 설치 전에 정리해 둔다.
# 외부 DNS 항목 제거, 내부 리졸버가 있으면 그것만 남긴다
cat /etc/resolv.conf
# NetworkManager 가 덮어쓰는 환경이면 고정
nmcli connection modify ${CONN} ipv4.ignore-auto-dns yes
nmcli connection modify ${CONN} ipv4.dns ""
내부 DNS 를 나중에 세우게 된다면 그때 Corefile 의 forward . <내부DNS> 를 추가하면 된다.
DNS 로 보이지만 실제로는 파드 네트워크가 끊긴 경우가 많다. Calico 를 VXLAN 모드로 쓰다가 IPIP 로 바꾸는 등 캡슐화 모드를 변경했다면 IP 풀 설정과 데몬셋 환경 변수가 함께 맞아야 한다.
kubectl -n kube-system logs -l k8s-app=calico-node --tail=50
kubectl get ippool -o yaml | grep -E 'vxlanMode|ipipMode|cidr'
link not found 처럼 인터페이스를 못 찾는 오류가 보이면 노드의 인터페이스 이름과 자동 감지 설정을 확인한다. 이쪽은 별도 문서에 정리돼 있다.